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