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