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