1 /*---------------------------------------------------------------------------*
2 Project: Horizon
3 File: os_Mutex.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 /*! @file
17 @brief Mutex に関する API の宣言
18
19 :include nn/os.h
20 */
21
22 #ifndef NN_OS_OS_MUTEX_H_
23 #define NN_OS_OS_MUTEX_H_
24
25 #include <nn/types.h>
26 #include <nn/Handle.h>
27 #include <nn/Result.h>
28 #include <nn/WithInitialize.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::Mutex ではなく、@ref nn::os::CriticalSection を使用すべきです。
43 スレッド間でロックが衝突しない場合のパフォーマンスでは
44 @ref nn::os::CriticalSection の方が @ref nn::os::Mutex より
45 圧倒的に高速です。
46
47 プログラムの特定の箇所について複数のスレッドからの同時実行を抑制し、
48 データやレジスタなどのリソースが複数のスレッドから同時にアクセスされることを防ぎます。
49
50 ミューテックスは @ref Lock によってロックすることができます。
51 あるスレッドがロックしているミューテックスを、他のスレッドがロックすることはできず、
52 他のスレッドがロックしようとした場合は、ミューテックスがアンロックされるまでブロックします。
53
54 アンロックは @ref Unlock によって行いますが、
55 ミューテックスのロックはスレッドに紐付けられているため、ロックしているスレッドからしか呼ぶことはできません。
56
57 Mutex は再帰ロックミューテックスであり、ロックしているスレッドがさらに @ref Lock を呼ぶことができます。
58 このとき、@ref Lock を読んだ回数と同じ回数だけ @ref Unlock が呼ばれるまで、ミューテックスがアンロックされません。
59
60 Mutex は優先度継承を実装しています。
61 低い優先度を持つスレッド L がロックしているミューテックスのロックを、
62 高い優先度を持つスレッド H が取得しようとしたとき、
63 スレッド L の優先度は一時的にスレッド H と同じ値まで引き上げられます。
64
65 Mutex オブジェクトの Wait 動作は、ロックの取得です。
66 ロックが取得できると、Wait 動作は解放されます。
67
68 @ref nn::os::Mutex::ScopedLock を使うとオブジェクトの生成からスコープの有効範囲の終わりまでの間でMutexによるロックをかけることができます。
69
70 Mutex オブジェクトは 32個まで作成することが出来ます。
71 また、API によってはこの制限にカウントされるリソースを消費する場合がありますので、ご注意ください。
72 */
73
74 class Mutex : public WaitObject
75 {
76 public:
77
78 /*!
79 @brief ミューテックスを構築し、初期化します。
80
81 @param[in] initialLocked true を指定した場合、初期化と同時にロック状態にします。所有者は作成したスレッドになります。
82 */
83 explicit Mutex(bool initialLocked);
84
85 /*!
86 @brief ミューテックスオブジェクトを構築します。
87
88 ミューテックスオブジェクトを構築しますが、初期化はしません。
89 別途、@ref Initialize を呼ぶ必要があります。
90 */
Mutex()91 Mutex() {}
92
93 /*!
94 @brief オブジェクトを構築し、初期化を行います。
95 */
96 Mutex(const nn::WithInitialize&);
97
98 /*!
99 @brief ミューテックスを初期化します。
100
101 @param[in] initialLocked true を指定した場合、初期化と同時にロック状態にします。所有者は作成したスレッドになります。
102 */
103 void Initialize(bool initialLocked = false);
104
105 /*!
106 @brief ミューテックスの初期化を試みます。
107
108 @param[in] initialLocked true を指定した場合、初期化と同時にロック状態にします。所有者は作成したスレッドになります。
109
110 @return 関数の実行結果を返します。
111 */
112 nn::Result TryInitialize(bool initialLocked = false);
113
114 /*!
115 @brief ミューテックスを破棄します。
116
117 デストラクタからも自動で呼ばれます。
118 @return 無し。
119 */
Finalize()120 void Finalize() { WaitObject::Finalize(); }
121
122 /*!
123 @brief デストラクタです。
124 */
~Mutex()125 ~Mutex() {}
126
127 /*!
128 @brief ミューテックスをロックします。
129
130 他スレッドでロックされている場合はブロックします。
131 自スレッドで既にロックされている場合は、ネスト回数が増加します。
132
133 @return 無し。
134 */
Lock()135 void Lock() { this->WaitOne(); }
136
137 /*!
138 @brief ミューテックスのロックを試みます。
139
140 ミューテックスのロックを試み、成功すれば true が返ります。
141 ロックできなかった場合、最大で timeout で指定した時間だけ待ち、
142 その間にロックを取得できれば true を返します。
143 timeout で指定した時間だけ待ってもロックを取得できなかった場合は、false を返します。
144
145 @param[in] timeout タイムアウト時間を指定します。0 を指定すると即座に処理を返します。
146
147 @return ロックに成功したかを返します。
148 */
149 bool TryLock(nn::fnd::TimeSpan timeout = 0) { return this->WaitOne(timeout); }
150
151 /*!
152 @brief ミューテックスをアンロックします。
153
154 自スレッドでロックされているミューテックスのネスト回数を 1 減らします。
155 ミューテックスをロックしていないスレッドでこの関数を呼ぶことはできません。
156
157 @return 無し。
158 */
159 void Unlock();
160
161 /*!
162 @class nn::os::Mutex::ScopedLock
163 @brief オブジェクトの生成時からオブジェクトの存在するスコープを抜けるまで間、Mutexをロックします。
164 */
165 class ScopedLock;
166
167 private:
168
169 Result TryInitializeImpl(bool initialLocked);
170
171 };
172
173 // インライン実装
174
TryInitializeImpl(bool initialLocked)175 inline Result Mutex::TryInitializeImpl(bool initialLocked)
176 {
177 Handle handle;
178 NN_UTIL_RETURN_IF_FAILED(nn::svc::CreateMutex(&handle, initialLocked));
179 this->SetHandle(handle);
180 return ResultSuccess();
181 }
182
Initialize(bool initialLocked)183 inline void Mutex::Initialize(bool initialLocked)
184 {
185 NN_ERR_THROW_FATAL(TryInitializeImpl(initialLocked));
186 }
187
TryInitialize(bool initialLocked)188 inline nn::Result Mutex::TryInitialize(bool initialLocked)
189 {
190 Result result = TryInitializeImpl(initialLocked);
191 if (result.GetSummary() == Result::SUMMARY_OUT_OF_RESOURCE)
192 {
193 return result;
194 }
195 NN_ERR_THROW_FATAL(result);
196 return result;
197 }
198
Mutex(bool initialLocked)199 inline Mutex::Mutex(bool initialLocked)
200 {
201 Initialize(initialLocked);
202 }
203
Mutex(const nn::WithInitialize &)204 inline Mutex::Mutex(const nn::WithInitialize&)
205 {
206 Initialize(false);
207 }
208
Unlock()209 inline void Mutex::Unlock()
210 {
211 NN_ERR_THROW_FATAL(nn::svc::ReleaseMutex(GetHandle()));
212 }
213
214 NN_UTIL_DETAIL_DEFINE_SCOPED_LOCK(Mutex, Lock(), Unlock());
215
216 }} // namespace nn::os
217
218 #endif // __cplusplus
219
220 // 以下、C 用宣言
221
222 #include <nn/util/detail/util_CLibImpl.h>
223
224 /*!
225 @addtogroup nn_os
226 @{
227
228 @defgroup nn_os_Mutex_c Mutex (C)
229
230 @brief @ref nn::os::Mutex の C インタフェースモジュールです。
231
232 @{
233 */
234
235 /*!
236 @struct nnosMutex
237 @brief ミューテックスを表す C の構造体です。
238 @brief 対応するクラス @ref nn::os::Mutex を参照してください。
239 */
240 NN_UTIL_DETAIL_CLIBIMPL_DEFINE_BUFFER_CLASS(nnosMutex, nn::os::Mutex, 4, u32);
241 NN_UTIL_DETAIL_CLIBIMPL_DECLARE_CONVERSION(nnosMutexToWaitObject, nnosMutex, nnosWaitObject);
242 NN_UTIL_DETAIL_CLIBIMPL_DECLARE_CONVERSION(nnosWaitObjectToMutex, nnosWaitObject, nnosMutex);
243
244 /*!
245 @brief 対応する C++ 関数 @ref nn::os::Mutex::Initialize を参照してください。
246 */
247 NN_EXTERN_C void nnosMutexInitialize(nnosMutex* this_, bool initialLocked);
248
249 /*!
250 @brief 対応する C++ 関数 @ref nn::os::Mutex::TryInitialize を参照してください。
251 */
252 NN_EXTERN_C bool nnosMutexTryInitialize(nnosMutex* this_, bool initialLocked);
253
254 /*!
255 @brief 対応する C++ 関数 @ref nn::os::Mutex::Lock を参照してください。
256 */
257 NN_EXTERN_C void nnosMutexLock(nnosMutex* this_);
258
259 /*!
260 @brief 対応する C++ 関数 @ref nn::os::Mutex::TryLock を参照してください。
261 */
262 NN_EXTERN_C bool nnosMutexTryLock(nnosMutex* this_, s64 timeout);
263
264 /*!
265 @brief 対応する C++ 関数 @ref nn::os::Mutex::Unlock を参照してください。
266 */
267 NN_EXTERN_C void nnosMutexUnlock(nnosMutex* this_);
268
269 /*!
270 @brief 対応する C++ 関数 @ref nn::os::Mutex::Finalize を参照してください。
271 */
272 NN_EXTERN_C void nnosMutexFinalize(nnosMutex* this_);
273
274 /*!
275 @}
276
277 @}
278 */
279
280 #endif /* NN_OS_IPC_OS_MUTEX_H_ */
281