1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     os_Semaphore.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: 33844 $
14  *---------------------------------------------------------------------------*/
15 
16 /*!
17     @file
18     @brief    Semaphore に関するAPI の宣言
19 
20     :include nn/os.h
21 */
22 
23 #ifndef NN_OS_OS_SEMAPHORE_H_
24 #define NN_OS_OS_SEMAPHORE_H_
25 
26 #include <nn/types.h>
27 #include <nn/Handle.h>
28 #include <nn/Result.h>
29 #include <nn/os/os_Synchronization.h>
30 
31 #include <nn/util/util_Result.h>
32 #include <nn/util/detail/util_ScopedLockImpl.h>
33 #include <nn/err.h>
34 
35 #ifdef __cplusplus
36 
37 namespace nn { namespace os {
38 
39 /*!
40     @brief セマフォを扱う為のクラスです。セマフォはカウンタを持つ同期オブジェクトです。
41 
42            通常は @ref nn::os::Semaphore ではなく、@ref nn::os::LightSemaphore を使用すべきです。
43            複数の同期オブジェクトを待つことができない点を除いて
44            @ref nn::os::Semaphore よりも @ref nn::os::LightSemaphore の方が優れています。
45 
46            セマフォの Wait 動作では、セマフォカウンタが 0 より大きくなることを待った後、セマフォカウンタを 1 増やします。
47            セマフォカウンタが 0 のときは、Wait 動作は解放されません。
48 
49            セマフォのカウンタを増やすには @ref Release を呼び出します。
50 
51            同期オブジェクトについては、@ref nn::os::Event を参照してください。
52 
53            Semaphore オブジェクトは 8個まで作成することが出来ます。
54            また、API によってはこの制限にカウントされるリソースを消費する場合がありますので、ご注意ください。
55 */
56 
57 class Semaphore : public InterruptEvent
58 {
59 public:
60 
61     /*!
62       @brief        セマフォを構築し、初期化します。
63 
64                     初期化しないコンストラクタと、初期化するコンストラクタが用意されています。
65                     初期化しないコンストラクタを使用した場合は、別途 @ref Initialize の呼び出しが必要です。
66 
67       @param[in]    initialCount    作成直後のセマフォのカウント値。
68       @param[in]    maxCount        このセマフォが取りうる最大カウント値。
69     */
70     Semaphore(s32 initialCount, s32 maxCount);
71 
72     /*!
73       @brief        セマフォを構築します。初期化はしません。使用する為には @ref Initialize の呼び出しが必要です。
74 
75     */
Semaphore()76     Semaphore() {}
77 
78     /*!
79       @brief        構築済みのセマフォを初期化します。
80 
81       @param[in]    initialCount    作成直後のセマフォのカウント値。
82       @param[in]    maxCount        このセマフォが取りうる最大カウント値。
83 
84       @return       無し。
85     */
86     void Initialize(s32 initialCount, s32 maxCount);
87 
88     /*!
89       @brief        構築済みのセマフォの初期化を試みます。
90 
91       @param[in]    initialCount    作成直後のセマフォのカウント値。
92       @param[in]    maxCount        このセマフォが取りうる最大カウント値。
93 
94       @return       成功するとtrue、失敗するとfalseを返します。
95     */
96     nn::Result TryInitialize(s32 initialCount, s32 maxCount);
97 
98     /*!
99       @brief        セマフォを破棄します。
100 
101                     デストラクタからも自動で呼ばれます。
102 
103       @return       無し。
104     */
Finalize()105     void Finalize() { InterruptEvent::Finalize(); }
106 
107     /*!
108       @brief デストラクタです。
109     */
~Semaphore()110     ~Semaphore() {}
111 
112     /*!
113       @brief        セマフォの解放(V 操作)を行い、カウンタ値を増やします。
114 
115                     セマフォ待ちでブロックされているスレッドがある場合には、最も優先順位の高いスレッドの 1 つがブロックから解除されます。
116 
117       @param[in]    releaseCount    カウント値の増分を指定します。
118 
119       @return       releaseCount を加える前のカウント値を返します。
120     */
121     s32 Release(s32 releaseCount = 1);
122 
123     /*!
124       @brief        セマフォの取得(P 操作)を行い、カウンタ値を 1 減らします。
125 
126       @return       無し。
127     */
Acquire()128     void Acquire() { this->WaitOne(); }
129 
130     /*!
131       @brief        セマフォの取得(P 操作)を試行します。
132 
133                     成功するとカウンタ値を 1 減らします。
134 
135       @param[in]    timeout     タイムアウト時間を指定します。0 を指定すると即座に処理を返します。
136 
137       @return       タイムアウト時間内に取得が成功したかを返します。
138     */
TryAcquire(nn::fnd::TimeSpan timeout)139     bool TryAcquire(nn::fnd::TimeSpan timeout) { return this->WaitOne(timeout); }
140 
141     class ScopedLock;
142 
143 private:
144 
145     Result TryInitializeImpl(s32 initialCount, s32 maxCount);
146 
147 };
148 
TryInitializeImpl(s32 initialCount,s32 maxCount)149 inline Result Semaphore::TryInitializeImpl(s32 initialCount, s32 maxCount)
150 {
151     Handle handle;
152     NN_UTIL_RETURN_IF_FAILED(nn::svc::CreateSemaphore(&handle, initialCount, maxCount));
153     this->SetHandle(handle);
154     return ResultSuccess();
155 }
156 
Initialize(s32 initialCount,s32 maxCount)157 inline void Semaphore::Initialize(s32 initialCount, s32 maxCount)
158 {
159     NN_ERR_THROW_FATAL(TryInitializeImpl(initialCount, maxCount));
160 }
161 
TryInitialize(s32 initialCount,s32 maxCount)162 inline nn::Result Semaphore::TryInitialize(s32 initialCount, s32 maxCount)
163 {
164     Result result = TryInitializeImpl(initialCount, maxCount);
165     if (result.GetSummary() == Result::SUMMARY_OUT_OF_RESOURCE)
166     {
167         return result;
168     }
169     NN_ERR_THROW_FATAL(result);
170     return result;
171 }
172 
Semaphore(s32 initialCount,s32 maxCount)173 inline Semaphore::Semaphore(s32 initialCount, s32 maxCount)
174 {
175     Initialize(initialCount, maxCount);
176 }
177 
Release(s32 releaseCount)178 inline s32 Semaphore::Release(s32 releaseCount)
179 {
180     s32 ret;
181     NN_ERR_THROW_FATAL(nn::svc::ReleaseSemaphore(&ret, GetHandle(), releaseCount));
182     return ret;
183 }
184 
185 NN_UTIL_DETAIL_DEFINE_SCOPED_LOCK(Semaphore, Acquire(), Release());
186 
187 }} // namespace nn::os
188 
189 #endif // __cplusplus
190 
191 // 以下、C 用宣言
192 
193 #include <nn/util/detail/util_CLibImpl.h>
194 
195 /*!
196   @addtogroup   nn_os
197   @{
198 
199   @defgroup     nn_os_Semaphore_c       Semaphore (C)
200 
201   @brief        @ref nn::os::Semaphore の C インタフェースモジュールです。
202 
203   @{
204 */
205 
206 /*!
207   @struct       nnosSemaphore
208   @brief        セマフォを表す C の構造体です。
209   @brief 対応するクラス @ref nn::os::Semaphore を参照してください。
210 */
211 NN_UTIL_DETAIL_CLIBIMPL_DEFINE_BUFFER_CLASS(nnosSemaphore, nn::os::Semaphore, 4, u32);
212 NN_UTIL_DETAIL_CLIBIMPL_DECLARE_CONVERSION(nnosSemaphoreToWaitObject, nnosSemaphore, nnosWaitObject);
213 NN_UTIL_DETAIL_CLIBIMPL_DECLARE_CONVERSION(nnosWaitObjectToSemaphore, nnosWaitObject, nnosSemaphore);
214 
215 /*!
216   @brief 対応する C++ 関数 @ref nn::os::Semaphore::Semaphore を参照してください。
217 */
218 NN_EXTERN_C void nnosSemaphoreInitialize(nnosSemaphore* this_, s32 initialCount, s32 maxCount);
219 
220 /*!
221   @brief 対応する C++ 関数 @ref nn::os::Semaphore::Semaphore を参照してください。
222 */
223 NN_EXTERN_C bool nnosSemaphoreTryInitialize(nnosSemaphore* this_, s32 initialCount, s32 maxCount);
224 
225 /*!
226   @brief 対応する C++ 関数 @ref nn::os::Semaphore::Release を参照してください。
227 */
228 NN_EXTERN_C s32 nnosSemaphoreRelease(nnosSemaphore* this_, s32 releaseCount);
229 
230 /*!
231   @brief 対応する C++ 関数 @ref nn::os::Semaphore::Acquire を参照してください。
232 */
233 NN_EXTERN_C void nnosSemaphoreAcquire(nnosSemaphore* this_);
234 
235 /*!
236   @brief 対応する C++ 関数 @ref nn::os::Semaphore::TryAcquire を参照してください。
237 */
238 NN_EXTERN_C bool nnosSemaphoreTryAcquire(nnosSemaphore* this_, s64 nanoSeconds);
239 
240 /*!
241   @brief 対応する C++ 関数 @ref nn::os::Semaphore::Finalize を参照してください。
242 */
243 NN_EXTERN_C void nnosSemaphoreFinalize(nnosSemaphore* this_);
244 
245 /*!
246   @}
247 
248   @}
249 */
250 
251 #endif
252