1 /*---------------------------------------------------------------------------* 2 Project: Horizon 3 File: os_LightBarrier.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: 16563 $ 14 *---------------------------------------------------------------------------*/ 15 16 #ifndef NN_OS_OS_LIGHTBARRIER_H_ 17 #define NN_OS_OS_LIGHTBARRIER_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 <cstdlib> 26 27 namespace nn { namespace os { 28 29 /*! 30 @file 31 @brief LightBarrier に関するAPI の宣言 32 33 :include nn/os.h 34 */ 35 36 /*!--------------------------------------------------------------------------* 37 @brief 複数のスレッドの到着を待つ同期機構です。 38 39 初期化時に指定された数のスレッドが到着するまで、 40 早く到着したスレッドを待機させます。 41 42 このクラスを N 個を超えるスレッドのなかから N 個の到着を 43 待つために使用することはできません。 44 45 @ref Await と初期化/終了を除くこのクラスのメンバ関数はスレッドセーフです。 46 @ref Await はコンストラクタまたは @ref Initialize メンバ関数で 47 指定する数のスレッド間でのみスレッドセーフです。 48 49 *---------------------------------------------------------------------------*/ 50 class LightBarrier 51 { 52 private: 53 struct IncrementIfLessThan_1 54 { operatorIncrementIfLessThan_155 bool operator()(s32& x) 56 { 57 if( x < -1 ) 58 { 59 ++x; 60 return true; 61 } 62 else 63 { 64 return false; 65 } 66 } 67 }; 68 69 private: 70 WaitableCounter m_CounterPlus; 71 WaitableCounter m_CounterMinus; 72 s32 m_ReleaseCountAndSign; 73 74 public: 75 //---------------------------------------- 76 //! @name 初期化/終了 77 //@{ 78 79 /*!--------------------------------------------------------------------------* 80 @brief コンストラクタです。 81 82 初期化を行わないコンストラクタです。 83 84 別途 @ref Initialize を呼び出す必要があります。 85 86 @return なし。 87 88 *---------------------------------------------------------------------------*/ LightBarrier()89 LightBarrier() {} 90 91 /*!--------------------------------------------------------------------------* 92 @brief コンストラクタです。 93 94 初期化を行うコンストラクタです。 95 96 別途 @ref Initialize を呼び出す必要はありません。 97 98 @param[in] numWait 待ち合わせるスレッドの数を指定します。 99 100 @return なし。 101 102 *---------------------------------------------------------------------------*/ LightBarrier(s32 numWait)103 LightBarrier(s32 numWait) { Initialize(numWait); } 104 105 /*!--------------------------------------------------------------------------* 106 @brief 初期化を行います。 107 108 @param[in] numWait 待ち合わせるスレッドの数を指定します。 109 110 @return なし。 111 112 *---------------------------------------------------------------------------*/ Initialize(s32 numWait)113 void Initialize(s32 numWait) 114 { 115 NN_MIN_TASSERT_( numWait, 1 ); 116 117 *m_CounterPlus = - numWait; 118 *m_CounterMinus = - numWait; 119 m_ReleaseCountAndSign = numWait; 120 } 121 122 /*!--------------------------------------------------------------------------* 123 @brief 終了処理を行います。 124 125 @return なし。 126 127 *---------------------------------------------------------------------------*/ Finalize()128 void Finalize() {} 129 130 //@} 131 132 //---------------------------------------- 133 //! @name デバッグ用情報取得 134 //@{ 135 136 /*!--------------------------------------------------------------------------* 137 @brief 待ちわせるスレッドの数を取得します。 138 139 コンストラクタまたは @ref Initialize で指定した 140 待ちわせるスレッドの数を取得します。 141 142 @return 待ち合わせるスレッドの数を返します。 143 144 *---------------------------------------------------------------------------*/ GetReleaseCount()145 s32 GetReleaseCount() const { return std::abs(m_ReleaseCountAndSign); } 146 147 /*!--------------------------------------------------------------------------* 148 @brief 待機しているスレッドの数を取得します。 149 150 既に到着して他のスレッドが到着するのを待機している 151 スレッドの数を取得します。 152 153 @return 待機しているスレッドの数を返します。 154 155 *---------------------------------------------------------------------------*/ GetNumOfWaiting()156 s32 GetNumOfWaiting() const 157 { 158 const s32 relCountAndSign = m_ReleaseCountAndSign; 159 s32 minusRemain; 160 s32 relCount; 161 162 if( relCountAndSign > 0 ) 163 { 164 minusRemain = *m_CounterPlus; 165 relCount = relCountAndSign; 166 } 167 else 168 { 169 minusRemain = *m_CounterMinus; 170 relCount = - relCountAndSign; 171 } 172 173 return (minusRemain == 0) ? 0: relCount + minusRemain; 174 } 175 176 //@} 177 178 //---------------------------------------- 179 //! @name スレッドの待ち合わせ 180 //@{ 181 182 /*!--------------------------------------------------------------------------* 183 @brief 他のスレッドの到着を待ちます。 184 185 コンストラクタまたは @ref Initialize で指定した数のスレッドが 186 Await を呼ぶまで待機します。 187 188 @return なし。 189 190 *---------------------------------------------------------------------------*/ Await()191 void Await() 192 { 193 const s32 relCountAndSign = m_ReleaseCountAndSign; 194 195 if( relCountAndSign > 0 ) 196 { 197 AwaitImpl(&m_CounterPlus, &m_CounterMinus, relCountAndSign); 198 } 199 else 200 { 201 AwaitImpl(&m_CounterMinus, &m_CounterPlus, - relCountAndSign); 202 } 203 } 204 205 //@} 206 207 private: AwaitImpl(nn::os::WaitableCounter * pCur,nn::os::WaitableCounter * pNext,s32 relCount)208 void AwaitImpl(nn::os::WaitableCounter* pCur, nn::os::WaitableCounter* pNext, s32 relCount) 209 { 210 IncrementIfLessThan_1 updater; 211 212 if( (*pCur)->AtomicUpdateConditional(updater) ) 213 { 214 pCur->WaitIfLessThan(0); 215 } 216 else 217 { 218 m_ReleaseCountAndSign = - m_ReleaseCountAndSign; 219 **pNext = - relCount; 220 **pCur = 0; 221 pCur->SignalAll(); 222 } 223 } 224 }; 225 226 227 }} // namespace nn::os 228 229 #endif // __cplusplus 230 231 // TODO: C 用 API が必要です。 232 233 #endif // ifndef NN_OS_OS_LIGHTBARRIER_H_ 234