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: 28867 $ 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 class ScopedAcquire 237 { 238 private: 239 LightSemaphore* m_Semaphore; 240 public: 241 ScopedAcquire(LightSemaphore& semaphore, bool wait = true) 242 : m_Semaphore(wait ? (semaphore.Acquire(), &semaphore) : (semaphore.TryAcquire() ? &semaphore : 0)) {} Aquired()243 bool Aquired() const { return m_Semaphore != 0; } Detach()244 void Detach() { this->m_Semaphore = 0; } ~ScopedAcquire()245 ~ScopedAcquire() { if (m_Semaphore) { m_Semaphore->Release(); } } 246 }; 247 }; 248 249 250 }} // namespace nn::os 251 252 #endif // __cplusplus 253 254 // 以下、C 用宣言 255 256 #include <nn/util/detail/util_CLibImpl.h> 257 258 /*! 259 @addtogroup nn_os 260 @{ 261 262 @defgroup nn_os_LightSemaphore_c LightSemaphore (C) 263 264 @brief @ref nn::os::LightSemaphore の C インタフェースモジュールです。 265 266 @{ 267 */ 268 269 /*! 270 @struct nnosLightSemaphore 271 @brief ライトセマフォを表す C の構造体です。 272 @brief 対応するクラス @ref nn::os::LightSemaphore を参照してください。 273 */ 274 NN_UTIL_DETAIL_CLIBIMPL_DEFINE_BUFFER_CLASS(nnosLightSemaphore, nn::os::LightSemaphore, 8, u32); 275 276 /*! 277 @brief 対応する C++ 関数 @ref nn::os::LightSemaphore::LightSemaphore を参照してください。 278 */ 279 NN_EXTERN_C void nnosLightSemaphoreInitialize(nnosLightSemaphore* this_, s32 initialCount, s32 maxCount); 280 281 /*! 282 @brief 対応する C++ 関数 @ref nn::os::LightSemaphore::GetMax を参照してください。 283 */ 284 NN_EXTERN_C s32 nnosLightSemaphoreGetMax(nnosLightSemaphore* p); 285 286 /*! 287 @brief 対応する C++ 関数 @ref nn::os::LightSemaphore::GetCount を参照してください。 288 */ 289 NN_EXTERN_C s32 nnosLightSemaphoreGetCount(nnosLightSemaphore* p); 290 291 /*! 292 @brief 対応する C++ 関数 @ref nn::os::LightSemaphore::Release を参照してください。 293 */ 294 NN_EXTERN_C s32 nnosLightSemaphoreRelease(nnosLightSemaphore* this_, s32 releaseCount); 295 296 /*! 297 @brief 対応する C++ 関数 @ref nn::os::LightSemaphore::Acquire を参照してください。 298 */ 299 NN_EXTERN_C void nnosLightSemaphoreAcquire(nnosLightSemaphore* this_); 300 301 /*! 302 @brief 対応する C++ 関数 @ref nn::os::LightSemaphore::TryAcquire を参照してください。 303 */ 304 NN_EXTERN_C bool nnosLightSemaphoreTryAcquire(nnosLightSemaphore* this_); 305 306 /*! 307 @brief 対応する C++ 関数 @ref nn::os::LightSemaphore::Finalize を参照してください。 308 */ 309 NN_EXTERN_C void nnosLightSemaphoreFinalize(nnosLightSemaphore* this_); 310 311 /*! 312 @} 313 314 @} 315 */ 316 317 #endif // ifndef NN_OS_OS_LIGHTSEMAPHORE_H_ 318