1 /*---------------------------------------------------------------------------* 2 Project: Horizon 3 File: os_LightSemaphore.h 4 5 Copyright (C)2009 Nintendo Co., Ltd. All rights reserved. 6 7 These coded instructions, statements, and computer programs contain 8 proprietary information of Nintendo of America Inc. and/or Nintendo 9 Company Ltd., and are protected by Federal copyright law. They may 10 not be disclosed to third parties or copied or duplicated in any form, 11 in whole or in part, without the prior written consent of Nintendo. 12 13 $Rev: 12446 $ 14 *---------------------------------------------------------------------------*/ 15 16 #ifndef NN_OS_OS_LIGHTSEMAPHORE_H_ 17 #define NN_OS_OS_LIGHTSEMAPHORE_H_ 18 19 #ifdef __cplusplus 20 21 #include <nn/os/os_WaitableCounter.h> 22 #include <nn/assert.h> 23 #include <nn/WithInitialize.h> 24 #include <nn/util/detail/util_ScopedLockImpl.h> 25 26 namespace nn { namespace os { 27 28 /*! 29 @file 30 @brief LightSemaphore に関するAPI の宣言 31 32 :include nn/os.h 33 */ 34 35 /*!--------------------------------------------------------------------------* 36 @brief スレッド間でリソース数の排他制御を行う同期機構です。 37 38 内部にカウンタ値を持ち、これを各スレッドで減算/加算する形で 39 リソース数を管理します。 40 カウンタ値が 0 の場合は 1 以上になるまで待つことができます。 41 42 複数の同期オブジェクトを同時に待つことができないという点を除いて 43 nn::os::LightSemaphore の方が nn::os::Semaphore より 44 優れているため、通常は nn::os::LightSemaphore を使用すべきです。 45 46 このクラスの初期化/終了以外のメンバ関数はスレッドセーフです。 47 48 *---------------------------------------------------------------------------*/ 49 class LightSemaphore 50 { 51 private: 52 struct DecrementIfPositive 53 { operatorDecrementIfPositive54 bool operator()(s32& x) 55 { 56 if( x > 0 ) 57 { 58 --x; 59 return true; 60 } 61 else 62 { 63 return false; 64 } 65 } 66 }; 67 struct LimitedAdd 68 { 69 s32 max; 70 s32 value; 71 s32 beforeUpdate; 72 operatorLimitedAdd73 bool operator()(s32& x) 74 { 75 beforeUpdate = x; 76 77 if( x > max - value ) 78 { 79 x = max; 80 } 81 else 82 { 83 x += value; 84 } 85 86 return true; 87 } 88 }; 89 90 private: 91 WaitableCounter m_Counter; 92 s32 m_Max; 93 94 public: 95 //---------------------------------------- 96 //! @name 初期化/終了 97 //@{ 98 99 /*!--------------------------------------------------------------------------* 100 @brief コンストラクタです。 101 102 初期化を行わないコンストラクタです。 103 104 別途 @ref Initialize を呼び出す必要があります。 105 106 *---------------------------------------------------------------------------*/ LightSemaphore()107 LightSemaphore() {} 108 109 /*!--------------------------------------------------------------------------* 110 @brief コンストラクタです。 111 112 初期化を行うコンストラクタです。 113 114 別途 @ref Initialize を呼び出す必要はありません。 115 116 @param[in] initialCount 初期カウンタ値を指定します。 117 @param[in] maxCount カウンタ値の最大値を指定します。 118 119 *---------------------------------------------------------------------------*/ LightSemaphore(s32 initialCount,s32 maxCount)120 LightSemaphore(s32 initialCount, s32 maxCount) { Initialize(initialCount, maxCount); } 121 122 /*!--------------------------------------------------------------------------* 123 @brief 初期化を行います。 124 125 @param[in] initialCount 初期カウンタ値を指定します。 126 @param[in] maxCount カウンタ値の最大値を指定します。 127 128 @return なし。 129 130 *---------------------------------------------------------------------------*/ Initialize(s32 initialCount,s32 maxCount)131 void Initialize(s32 initialCount, s32 maxCount) 132 { 133 NN_MIN_TASSERT_( initialCount, 0 ); 134 NN_MIN_TASSERT_( maxCount, 1 ); 135 NN_MAX_TASSERT_( initialCount, maxCount ); 136 137 *m_Counter = initialCount; 138 m_Max = maxCount; 139 } 140 141 /*!--------------------------------------------------------------------------* 142 @brief 終了処理を行います。 143 144 @return なし。 145 146 *---------------------------------------------------------------------------*/ Finalize()147 void Finalize() {} 148 149 //@} 150 151 //---------------------------------------- 152 //! @name デバッグ用情報取得 153 //@{ 154 155 /*!--------------------------------------------------------------------------* 156 @brief コンストラクタまたは @ref Initialize で指定したカウンタ値の 157 最大値を取得します。 158 159 @return 設定されているカウンタ値の最大値を返します。 160 161 *---------------------------------------------------------------------------*/ GetMax()162 s32 GetMax() const { return m_Max; } 163 164 /*!--------------------------------------------------------------------------* 165 @brief 現在のカウンタ値を取得します。 166 167 @return 現在のカウンタ値を返します。 168 169 *---------------------------------------------------------------------------*/ GetCount()170 s32 GetCount() const { return *m_Counter; } 171 172 //@} 173 174 //---------------------------------------- 175 //! @name カウンタの操作と待ち合わせ 176 //@{ 177 178 /*!--------------------------------------------------------------------------* 179 @brief カウンタ値を 1 減算します。 180 181 カウンタ値が 0 であった場合は 1 以上になるまで待ったうえで 182 減算を行います。 183 184 @return なし。 185 186 *---------------------------------------------------------------------------*/ Acquire()187 void Acquire() 188 { 189 while( ! TryAcquire() ) 190 { 191 m_Counter.WaitIfLessThan(1); 192 } 193 } 194 195 /*!--------------------------------------------------------------------------* 196 @brief カウンタ値を 1 減算しようとします。 197 198 カウンタ値が 0 であった場合は減算を行わずに返ります。 199 200 @return 減算を行ったなら true、カウンタ値が 0 であったために 201 減算を行えなかった場合は false を返します。 202 203 *---------------------------------------------------------------------------*/ TryAcquire()204 bool TryAcquire() 205 { 206 DecrementIfPositive updater; 207 return m_Counter->AtomicUpdateConditional(updater); 208 } 209 210 /*!--------------------------------------------------------------------------* 211 @brief カウンタ値に加算します。 212 213 カウンタ値が 0 であり、かついずれかのスレッドが 214 カウンタ値が 1 以上になるのを待機している場合 215 カウンタ値が加算されるとそのスレッドの待機が解除されます。 216 217 複数のスレッドが待機している場合に 2 以上の値を 218 加算すると複数のスレッドの待機が解除されます。 219 加算した値より待機しているスレッドの方が多い場合は 220 加算した値分のスレッドだけが起床し、 221 残りは待機したままです。 222 223 起床するスレッドはスレッドの優先度に応じて優先度が高い方から起床します。 224 225 @param[in] releaseCount 加算する値を指定します。 226 1 以上でなければなりません。 227 指定しなかった場合は 1 加算します。 228 229 @return 加算前のカウンタ値を返します。 230 231 *---------------------------------------------------------------------------*/ 232 s32 Release(s32 releaseCount = 1); 233 234 //@} 235 }; 236 237 238 }} // namespace nn::os 239 240 #endif // __cplusplus 241 242 // 以下、C 用宣言 243 244 #include <nn/util/detail/util_CLibImpl.h> 245 246 /*! 247 @addtogroup nn_os 248 @{ 249 250 @defgroup nn_os_LightSemaphore_c LightSemaphore (C) 251 252 @brief @ref nn::os::LightSemaphore の C インタフェースモジュールです。 253 254 @{ 255 */ 256 257 /*! 258 @struct nnosLightSemaphore 259 @brief ライトセマフォを表す C の構造体です。 260 @brief 対応するクラス @ref nn::os::LightSemaphore を参照してください。 261 */ 262 NN_UTIL_DETAIL_CLIBIMPL_DEFINE_BUFFER_CLASS(nnosLightSemaphore, nn::os::LightSemaphore, 8, u32); 263 264 /*! 265 @brief 対応する C++ 関数 @ref nn::os::LightSemaphore::LightSemaphore を参照してください。 266 */ 267 NN_EXTERN_C void nnosLightSemaphoreInitialize(nnosLightSemaphore* this_, s32 initialCount, s32 maxCount); 268 269 /*! 270 @brief 対応する C++ 関数 @ref nn::os::LightSemaphore::GetMax を参照してください。 271 */ 272 NN_EXTERN_C s32 nnosLightSemaphoreGetMax(nnosLightSemaphore* p); 273 274 /*! 275 @brief 対応する C++ 関数 @ref nn::os::LightSemaphore::GetCount を参照してください。 276 */ 277 NN_EXTERN_C s32 nnosLightSemaphoreGetCount(nnosLightSemaphore* p); 278 279 /*! 280 @brief 対応する C++ 関数 @ref nn::os::LightSemaphore::Release を参照してください。 281 */ 282 NN_EXTERN_C s32 nnosLightSemaphoreRelease(nnosLightSemaphore* this_, s32 releaseCount); 283 284 /*! 285 @brief 対応する C++ 関数 @ref nn::os::LightSemaphore::Acquire を参照してください。 286 */ 287 NN_EXTERN_C void nnosLightSemaphoreAcquire(nnosLightSemaphore* this_); 288 289 /*! 290 @brief 対応する C++ 関数 @ref nn::os::LightSemaphore::TryAcquire を参照してください。 291 */ 292 NN_EXTERN_C bool nnosLightSemaphoreTryAcquire(nnosLightSemaphore* this_); 293 294 /*! 295 @brief 対応する C++ 関数 @ref nn::os::LightSemaphore::Finalize を参照してください。 296 */ 297 NN_EXTERN_C void nnosLightSemaphoreFinalize(nnosLightSemaphore* this_); 298 299 /*! 300 @} 301 302 @} 303 */ 304 305 #endif // ifndef NN_OS_OS_LIGHTSEMAPHORE_H_ 306