/*---------------------------------------------------------------------------* Project: Horizon File: os_LightBarrier.h Copyright (C)2009 Nintendo Co., Ltd. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Rev: 16563 $ *---------------------------------------------------------------------------*/ #ifndef NN_OS_OS_LIGHTBARRIER_H_ #define NN_OS_OS_LIGHTBARRIER_H_ #ifdef __cplusplus #include #include #include #include #include namespace nn { namespace os { /*! @file @brief LightBarrier に関するAPI の宣言 :include nn/os.h */ /*!--------------------------------------------------------------------------* @brief 複数のスレッドの到着を待つ同期機構です。 初期化時に指定された数のスレッドが到着するまで、 早く到着したスレッドを待機させます。 このクラスを N 個を超えるスレッドのなかから N 個の到着を 待つために使用することはできません。 @ref Await と初期化/終了を除くこのクラスのメンバ関数はスレッドセーフです。 @ref Await はコンストラクタまたは @ref Initialize メンバ関数で 指定する数のスレッド間でのみスレッドセーフです。 *---------------------------------------------------------------------------*/ class LightBarrier { private: struct IncrementIfLessThan_1 { bool operator()(s32& x) { if( x < -1 ) { ++x; return true; } else { return false; } } }; private: WaitableCounter m_CounterPlus; WaitableCounter m_CounterMinus; s32 m_ReleaseCountAndSign; public: //---------------------------------------- //! @name 初期化/終了 //@{ /*!--------------------------------------------------------------------------* @brief コンストラクタです。 初期化を行わないコンストラクタです。 別途 @ref Initialize を呼び出す必要があります。 @return なし。 *---------------------------------------------------------------------------*/ LightBarrier() {} /*!--------------------------------------------------------------------------* @brief コンストラクタです。 初期化を行うコンストラクタです。 別途 @ref Initialize を呼び出す必要はありません。 @param[in] numWait 待ち合わせるスレッドの数を指定します。 @return なし。 *---------------------------------------------------------------------------*/ LightBarrier(s32 numWait) { Initialize(numWait); } /*!--------------------------------------------------------------------------* @brief 初期化を行います。 @param[in] numWait 待ち合わせるスレッドの数を指定します。 @return なし。 *---------------------------------------------------------------------------*/ void Initialize(s32 numWait) { NN_MIN_TASSERT_( numWait, 1 ); *m_CounterPlus = - numWait; *m_CounterMinus = - numWait; m_ReleaseCountAndSign = numWait; } /*!--------------------------------------------------------------------------* @brief 終了処理を行います。 @return なし。 *---------------------------------------------------------------------------*/ void Finalize() {} //@} //---------------------------------------- //! @name デバッグ用情報取得 //@{ /*!--------------------------------------------------------------------------* @brief 待ちわせるスレッドの数を取得します。 コンストラクタまたは @ref Initialize で指定した 待ちわせるスレッドの数を取得します。 @return 待ち合わせるスレッドの数を返します。 *---------------------------------------------------------------------------*/ s32 GetReleaseCount() const { return std::abs(m_ReleaseCountAndSign); } /*!--------------------------------------------------------------------------* @brief 待機しているスレッドの数を取得します。 既に到着して他のスレッドが到着するのを待機している スレッドの数を取得します。 @return 待機しているスレッドの数を返します。 *---------------------------------------------------------------------------*/ s32 GetNumOfWaiting() const { const s32 relCountAndSign = m_ReleaseCountAndSign; s32 minusRemain; s32 relCount; if( relCountAndSign > 0 ) { minusRemain = *m_CounterPlus; relCount = relCountAndSign; } else { minusRemain = *m_CounterMinus; relCount = - relCountAndSign; } return (minusRemain == 0) ? 0: relCount + minusRemain; } //@} //---------------------------------------- //! @name スレッドの待ち合わせ //@{ /*!--------------------------------------------------------------------------* @brief 他のスレッドの到着を待ちます。 コンストラクタまたは @ref Initialize で指定した数のスレッドが Await を呼ぶまで待機します。 @return なし。 *---------------------------------------------------------------------------*/ void Await() { const s32 relCountAndSign = m_ReleaseCountAndSign; if( relCountAndSign > 0 ) { AwaitImpl(&m_CounterPlus, &m_CounterMinus, relCountAndSign); } else { AwaitImpl(&m_CounterMinus, &m_CounterPlus, - relCountAndSign); } } //@} private: void AwaitImpl(nn::os::WaitableCounter* pCur, nn::os::WaitableCounter* pNext, s32 relCount) { IncrementIfLessThan_1 updater; if( (*pCur)->AtomicUpdateConditional(updater) ) { pCur->WaitIfLessThan(0); } else { m_ReleaseCountAndSign = - m_ReleaseCountAndSign; **pNext = - relCount; **pCur = 0; pCur->SignalAll(); } } }; }} // namespace nn::os #endif // __cplusplus // TODO: C 用 API が必要です。 #endif // ifndef NN_OS_OS_LIGHTBARRIER_H_