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: 32759 $ 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 #include <nn/config.h> 26 27 namespace nn { namespace os { 28 29 /*! 30 @file 31 @brief LightSemaphore に関するAPI の宣言 32 33 :include nn/os.h 34 */ 35 36 /*!--------------------------------------------------------------------------* 37 @brief スレッド間でリソース数の排他制御を行う同期機構です。 38 39 内部にカウンタ値を持ち、これを各スレッドで減算/加算する形で 40 リソース数を管理します。 41 カウンタ値が 0 の場合は 1 以上になるまで待つことができます。 42 43 複数の同期オブジェクトを同時に待つことができないという点を除いて 44 nn::os::LightSemaphore の方が nn::os::Semaphore より 45 優れているため、通常は nn::os::LightSemaphore を使用すべきです。 46 47 このクラスの初期化/終了以外のメンバ関数はスレッドセーフです。 48 49 *---------------------------------------------------------------------------*/ 50 class LightSemaphore 51 { 52 public: 53 static const s32 MAX_MAX_COUNT = 0x7fff; 54 55 private: 56 struct DecrementIfPositive 57 { operatorDecrementIfPositive58 bool operator()(s32& x) 59 { 60 if( x > 0 ) 61 { 62 --x; 63 return true; 64 } 65 else 66 { 67 return false; 68 } 69 } 70 }; 71 struct LimitedAdd 72 { 73 s32 max; 74 s32 value; 75 s32 beforeUpdate; 76 operatorLimitedAdd77 bool operator()(s32& x) 78 { 79 beforeUpdate = x; 80 81 if( x > max - value ) 82 { 83 x = max; 84 } 85 else 86 { 87 x += value; 88 } 89 90 return true; 91 } 92 }; 93 94 private: 95 WaitableCounter m_Counter; 96 #if NN_PLATFORM_HAS_16BIT_LL_SC 97 fnd::InterlockedVariable<s16> m_NumWaiting; 98 s16 m_Max; 99 #else 100 fnd::InterlockedVariable<s32> m_NumWaiting; 101 #endif 102 103 104 public: 105 //---------------------------------------- 106 //! @name 初期化/終了 107 //@{ 108 109 /*!--------------------------------------------------------------------------* 110 @brief コンストラクタです。 111 112 初期化を行わないコンストラクタです。 113 114 別途 @ref Initialize を呼び出す必要があります。 115 116 *---------------------------------------------------------------------------*/ LightSemaphore()117 LightSemaphore() {} 118 119 /*!--------------------------------------------------------------------------* 120 @brief コンストラクタです。 121 122 初期化を行うコンストラクタです。 123 124 別途 @ref Initialize を呼び出す必要はありません。 125 126 @param[in] initialCount 初期カウンタ値を指定します。 127 @param[in] maxCount カウンタ値の最大値を指定します。 128 指定できる最大値は 32767 です。 129 130 *---------------------------------------------------------------------------*/ LightSemaphore(s32 initialCount,s32 maxCount)131 LightSemaphore(s32 initialCount, s32 maxCount) { Initialize(initialCount, maxCount); } 132 LightSemaphore(s32 initialCount)133 LightSemaphore(s32 initialCount) { Initialize(initialCount); } 134 135 /*!--------------------------------------------------------------------------* 136 @brief 初期化を行います。 137 138 @param[in] initialCount 初期カウンタ値を指定します。 139 @param[in] maxCount カウンタ値の最大値を指定します。 140 指定できる最大値は 32767 です。 141 142 @return なし。 143 144 *---------------------------------------------------------------------------*/ Initialize(s32 initialCount,s32 maxCount)145 void Initialize(s32 initialCount, s32 maxCount) 146 { 147 NN_MIN_TASSERT_( initialCount, 0 ); 148 NN_MIN_TASSERT_( maxCount, 1 ); 149 NN_MAX_TASSERT_( initialCount, maxCount ); 150 NN_MAX_TASSERT_( maxCount, MAX_MAX_COUNT ); 151 152 *m_Counter = initialCount; 153 m_NumWaiting = 0; 154 #if NN_PLATFORM_HAS_16BIT_LL_SC 155 m_Max = maxCount; 156 #else 157 NN_UNUSED_VAR(maxCount); 158 #endif 159 } Initialize(s32 initialCount)160 void Initialize(s32 initialCount) { Initialize(initialCount, MAX_MAX_COUNT); } 161 162 /*!--------------------------------------------------------------------------* 163 @brief 終了処理を行います。 164 165 @return なし。 166 167 *---------------------------------------------------------------------------*/ Finalize()168 void Finalize() {} 169 170 //@} 171 172 //---------------------------------------- 173 //! @name デバッグ用情報取得 174 //@{ 175 176 /*!--------------------------------------------------------------------------* 177 @brief コンストラクタまたは @ref Initialize で指定したカウンタ値の 178 最大値を取得します。 179 180 @return 設定されているカウンタ値の最大値を返します。 181 182 *---------------------------------------------------------------------------*/ 183 #if NN_PLATFORM_HAS_16BIT_LL_SC GetMax()184 s32 GetMax() const { return m_Max; } 185 #endif 186 187 /*!--------------------------------------------------------------------------* 188 @brief 現在のカウンタ値を取得します。 189 190 @return 現在のカウンタ値を返します。 191 192 *---------------------------------------------------------------------------*/ GetCount()193 s32 GetCount() const { return *m_Counter; } 194 195 //@} 196 197 //---------------------------------------- 198 //! @name カウンタの操作と待ち合わせ 199 //@{ 200 201 /*!--------------------------------------------------------------------------* 202 @brief カウンタ値を 1 減算します。 203 204 カウンタ値が 0 であった場合は 1 以上になるまで待ったうえで 205 減算を行います。 206 207 @return なし。 208 209 *---------------------------------------------------------------------------*/ Acquire()210 void Acquire() 211 { 212 while( ! TryAcquire() ) 213 { 214 ++m_NumWaiting; 215 m_Counter.WaitIfLessThan(1); 216 --m_NumWaiting; 217 } 218 } 219 220 /*!--------------------------------------------------------------------------* 221 @brief カウンタ値を 1 減算しようとします。 222 223 カウンタ値が 0 であった場合は減算を行わずに返ります。 224 225 @return 減算を行ったなら true、カウンタ値が 0 であったために 226 減算を行えなかった場合は false を返します。 227 228 *---------------------------------------------------------------------------*/ TryAcquire()229 bool TryAcquire() 230 { 231 DecrementIfPositive updater; 232 return m_Counter->AtomicUpdateConditional(updater); 233 } 234 235 /*!--------------------------------------------------------------------------* 236 @brief カウンタ値に加算します。 237 238 カウンタ値が 0 であり、かついずれかのスレッドが 239 カウンタ値が 1 以上になるのを待機している場合 240 カウンタ値が加算されるとそのスレッドの待機が解除されます。 241 242 複数のスレッドが待機している場合に 2 以上の値を 243 加算すると複数のスレッドの待機が解除されます。 244 加算した値より待機しているスレッドの方が多い場合は 245 加算した値分のスレッドだけが起床し、 246 残りは待機したままです。 247 248 起床するスレッドはスレッドの優先度に応じて優先度が高い方から起床します。 249 250 @param[in] releaseCount 加算する値を指定します。 251 1 以上でなければなりません。 252 指定しなかった場合は 1 加算します。 253 254 @return 加算前のカウンタ値を返します。 255 256 *---------------------------------------------------------------------------*/ 257 s32 Release(s32 releaseCount = 1); 258 259 //@} 260 261 class ScopedAcquire 262 { 263 private: 264 LightSemaphore* m_Semaphore; 265 public: 266 ScopedAcquire(LightSemaphore& semaphore, bool wait = true) 267 : m_Semaphore(wait ? (semaphore.Acquire(), &semaphore) : (semaphore.TryAcquire() ? &semaphore : 0)) {} Aquired()268 bool Aquired() const { return m_Semaphore != 0; } Detach()269 void Detach() { this->m_Semaphore = 0; } ~ScopedAcquire()270 ~ScopedAcquire() { if (m_Semaphore) { m_Semaphore->Release(); } } 271 }; 272 }; 273 274 275 }} // namespace nn::os 276 277 #endif // __cplusplus 278 279 // 以下、C 用宣言 280 281 #include <nn/util/detail/util_CLibImpl.h> 282 283 /*! 284 @addtogroup nn_os 285 @{ 286 287 @defgroup nn_os_LightSemaphore_c LightSemaphore (C) 288 289 @brief @ref nn::os::LightSemaphore の C インタフェースモジュールです。 290 291 @{ 292 */ 293 294 /*! 295 @struct nnosLightSemaphore 296 @brief ライトセマフォを表す C の構造体です。 297 @brief 対応するクラス @ref nn::os::LightSemaphore を参照してください。 298 */ 299 NN_UTIL_DETAIL_CLIBIMPL_DEFINE_BUFFER_CLASS(nnosLightSemaphore, nn::os::LightSemaphore, 8, u32); 300 301 /*! 302 @brief 対応する C++ 関数 @ref nn::os::LightSemaphore::LightSemaphore を参照してください。 303 */ 304 NN_EXTERN_C void nnosLightSemaphoreInitialize(nnosLightSemaphore* this_, s32 initialCount, s32 maxCount); 305 306 #if NN_PLATFORM_HAS_16BIT_LL_SC 307 /*! 308 @brief 対応する C++ 関数 @ref nn::os::LightSemaphore::GetMax を参照してください。 309 */ 310 NN_EXTERN_C s32 nnosLightSemaphoreGetMax(nnosLightSemaphore* p); 311 #endif 312 313 /*! 314 @brief 対応する C++ 関数 @ref nn::os::LightSemaphore::GetCount を参照してください。 315 */ 316 NN_EXTERN_C s32 nnosLightSemaphoreGetCount(nnosLightSemaphore* p); 317 318 /*! 319 @brief 対応する C++ 関数 @ref nn::os::LightSemaphore::Release を参照してください。 320 */ 321 NN_EXTERN_C s32 nnosLightSemaphoreRelease(nnosLightSemaphore* this_, s32 releaseCount); 322 323 /*! 324 @brief 対応する C++ 関数 @ref nn::os::LightSemaphore::Acquire を参照してください。 325 */ 326 NN_EXTERN_C void nnosLightSemaphoreAcquire(nnosLightSemaphore* this_); 327 328 /*! 329 @brief 対応する C++ 関数 @ref nn::os::LightSemaphore::TryAcquire を参照してください。 330 */ 331 NN_EXTERN_C bool nnosLightSemaphoreTryAcquire(nnosLightSemaphore* this_); 332 333 /*! 334 @brief 対応する C++ 関数 @ref nn::os::LightSemaphore::Finalize を参照してください。 335 */ 336 NN_EXTERN_C void nnosLightSemaphoreFinalize(nnosLightSemaphore* this_); 337 338 /*! 339 @} 340 341 @} 342 */ 343 344 #endif // ifndef NN_OS_OS_LIGHTSEMAPHORE_H_ 345