1 /*---------------------------------------------------------------------------*
2 Project: Horizon
3 File: os_Thread.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 Thread に関する API の宣言
18
19 :include nn/os.h
20 */
21
22 #ifndef NN_OS_OS_THREAD_H_
23 #define NN_OS_OS_THREAD_H_
24
25 #include <nn/types.h>
26 #include <nn/Handle.h>
27 #include <nn/os/os_Synchronization.h>
28 #include <nn/os/os_Result.h>
29 #include <nn/os/os_Tick.h>
30 #include <nn/os/os_SpinWaitSelect.h>
31
32 #include <nn/util/util_Result.h>
33 #include <nn/util/util_TypeTraits.h>
34 #include <nn/err.h>
35
36 /*
37 @def NN_OS_CORE_NO_ALL
38 @brief 対応する C++ 関数を参照してください。@ref nn::os::CORE_NO_ALL
39 */
40 #define NN_OS_CORE_NO_ALL (-1)
41
42 /*
43 @def NN_OS_CORE_NO_USE_PROCESS_VALUE
44 @brief 対応する C++ 関数を参照してください。@ref nn::os::CORE_NO_USE_PROCESS_VALUE
45 */
46 #define NN_OS_CORE_NO_USE_PROCESS_VALUE (-2)
47
48 #define NN_OS_THREAD_PRIORITY_RANGE_SIZE 32
49
50 /*
51 @def NN_OS_LOWEST_THREAD_PRIORITY
52 @brief 対応する C++ 関数を参照してください。@ref nn::os::LOWEST_THREAD_PRIORITY
53 */
54 #define NN_OS_LOWEST_THREAD_PRIORITY (NN_OS_THREAD_PRIORITY_RANGE_SIZE - 1)
55
56 /*
57 @def NN_OS_HIGHEST_THREAD_PRIORITY
58 @brief 対応する C++ 関数を参照してください。@ref nn::os::HIGHEST_THREAD_PRIORITY
59 */
60 #define NN_OS_HIGHEST_THREAD_PRIORITY 0
61
62 /*
63 @def NN_OS_DEFAULT_THREAD_PRIORITY
64 @brief 対応する C++ 関数を参照してください。@ref nn::os::DEFAULT_THREAD_PRIORITY
65 */
66 #define NN_OS_DEFAULT_THREAD_PRIORITY 16
67
68
69
70 #ifdef __cplusplus
71
72 #include <nn/os/os_SvcTypes.autogen.h>
73
74 namespace nn{ namespace os{
75
76 namespace detail {
77 s32 ConvertSvcToLibraryPriority(s32 svc);
78 s32 ConvertLibraryToSvcPriority(s32 lib);
79 }
80
81 /*
82 @brief スレッドの最低優先度を表す定数です。31 です。
83 */
84 const s32 LOWEST_THREAD_PRIORITY = NN_OS_LOWEST_THREAD_PRIORITY;
85
86 /*
87 @brief スレッドの最高優先度を表す定数です。0 です。
88 */
89 const s32 HIGHEST_THREAD_PRIORITY = NN_OS_HIGHEST_THREAD_PRIORITY;
90
91 /*
92 @brief デフォルトのスレッド優先度を表す定数です。16 です。
93 */
94 const s32 DEFAULT_THREAD_PRIORITY = NN_OS_DEFAULT_THREAD_PRIORITY;
95
96 /*
97 @brief スレッドを実行するプロセッサ番号がどれでも良いことを表します。
98 */
99 const s32 CORE_NO_ALL = NN_OS_CORE_NO_ALL;
100
101 /*
102 @brief スレッドの実行をするプロセッサ番号を指定する際、アプリケーションで設定されているデフォルトの番号を使うことを表します。
103 */
104 const s32 CORE_NO_USE_PROCESS_VALUE = NN_OS_CORE_NO_USE_PROCESS_VALUE;
105
106 const s32 THREAD_PRIORITY_RANGE_SIZE = NN_OS_THREAD_PRIORITY_RANGE_SIZE;
107
108 /* @typedef void (*ThreadFunc)(uptr param)
109 @brief スレッドで実行する関数の型を表します。
110 */
111
112 /*!
113 @brief スレッドを表すクラスです。
114
115 Bug: 現在の実装では、優先プロセッサやアフィニティマスクの設定はできません。
116
117 スレッドには優先度があります。
118 スレッド優先度には 0~31 までの整数で指定することができ、0 が一番高い優先度を表します。
119 標準的なスレッドは @ref DEFAULT_THREAD_PRIORITY (16)を指定します。
120
121 スレッドの動作にはスタック領域が必要ですが、
122 スタック領域の管理は、自分で管理することもライブラリに任せることもできます。
123
124 自分でスタック領域を管理する場合は @ref Start 関数にスタック領域を渡し、スレッドを開始します。
125 スタック領域は uptr GetStackBottom() 関数を持つようなクラスのインスタンスを渡します。
126 @ref StackMemoryBlock や @ref StackBuffer はこの条件を満たすクラスのため、直接渡すことができます。
127 自分でスタック領域を管理する場合は、
128 スレッドが終了する前にスタック領域が無効になる(解放されるなど)ことがないように十分に注意してください。
129
130 ライブラリにスタック領域の管理を任せる場合は @ref StartUsingAutoStack 関数にスタックサイズを渡し、スレッドを開始します。
131 ライブラリが確保するスタック領域のサイズは4096byte単位です。
132
133 スレッドオブジェクトが有効になるのは Start 系関数から抜けた後です。
134 スレッドが走り出した時点ではないことに注意してください。
135 オブジェクトが有効かどうかは IsValid 関数で取得することができます。
136
137 @ref Start によって開始された Thread オブジェクトを破棄する前には、
138 必ず明示的に @ref Joinを呼ぶ必要があります。
139 @ref Detach を呼ぶことはできません。
140
141 @ref StartUsingAutoStack によって開始された Thread オブジェクトを破棄する前には、
142 必ず明示的に @ref Join か @ref Detach を呼ぶ必要があります。
143
144 Thread オブジェクトは @ref WaitObject を継承しており、Wait 動作の解放はスレッドの終了を意味します。
145 @ref Join 動作をブロック無しに行う必要がある際は、
146 先に @ref WaitOne や @ref WaitObject::WaitAny などを呼んで Wait 動作の解放を確認しておきます。
147
148 ※現在の実装では優先プロセッサやアフィニティマスクをスレッド開始時以外に指定することはできません。
149
150 スレッドには、優先プロセッサおよびアフィニティマスクを指定することができます。
151 優先プロセッサには、0 ~ (コア数-1) まで指定することができます。
152 また、@ref CORE_NO_ALL を指定すると全てのプロセッサを平等に扱うように優先プロセッサを設定し、
153 全てのプロセッサを含むアフィニティマスクを使用します。
154 @ref CORE_NO_USE_PROCESS_VALUE を指定すると、所属するアプリケーションのデフォルトの値を使用します。
155 優先プロセッサを指定すると、スレッドは指定されたプロセッサ上で優先して動作しますが、
156 必ずしも指定どおりのプロセッサ上で動作するわけではありません。
157
158 アフィニティマスクは、スレッドがどのプロセッサ上で実行されるべきかを指定するものです。
159 bit8の配列で表現し、各要素は下位1ビット目が最初のプロセッサを表します。
160 ビットを1にすることで、対象のプロセッサで走行する許可を与えます。
161 必ず、どれかのプロセッサをしてする必要があり、全てのビット0にしたマスクを指定することはできません。
162
163 スレッドの開始時には優先プロセッサを指定することができますが、
164 ここでプロセッサ番号を指定した場合、
165 スレッド開始時のアフィニティマスクはそのプロセッサ番号のみが指定されたことになります。
166 */
167
168 class Thread : public WaitObject
169 {
170 public:
171 class AutoStackManager
172 {
173 public:
174 virtual void* Construct(size_t stackSize) = 0;
175 virtual void Destruct(void* pStackBottom, bool isError) = 0;
176 };
177
178 public:
179
180 /*!
181 @brief コンストラクタです。
182
183 スレッドを開始するには、@ref Start または @ref TryStart を使います。
184 */
Thread()185 Thread() : m_CanFinalize(true) {}
186
187 /*!
188 @brief デストラクタ
189
190 スレッドオブジェクトを破棄します。
191 破棄時の注意は @ref Finalize を参照してください。
192 */
193 ~Thread();
194
195 /*!
196 @brief スレッドを初期化し実行します。
197
198 ユーザが用意したスタックを使ってスレッドを初期化し、スレッドを開始します。
199 スレッドの終了が確認されるまで、スタック領域は維持されている必要があります。
200
201 @param[in] f 実行を開始する関数へのポインタ
202 @param[in] stack スタック領域を表すオブジェクト
203 @param[in] priority スレッドの優先度
204 @param[in] coreNo スレッドの優先プロセッサ
205
206 @tparam Stack スタックを表す型
207
208 @return 無し。
209
210 :overload partialtemplate
211 */
212 template <typename Stack>
213 void Start(void (*f)(), Stack& stack, s32 priority = DEFAULT_THREAD_PRIORITY, s32 coreNo = CORE_NO_USE_PROCESS_VALUE);
214
215 /*!
216 @brief スレッドを初期化し実行します。
217
218 ユーザが用意したスタックを使ってスレッドを初期化し、スレッドを開始します。
219 スレッドの終了が確認されるまで、スタック領域は維持されている必要があります。
220
221 @param[in] f 実行を開始する関数へのポインタ
222 @param[in] param 実行を開始する関数へ渡す引数
223 @param[in] stack スタック領域を表すオブジェクト
224 @param[in] priority スレッドの優先度
225 @param[in] coreNo スレッドの優先プロセッサ
226
227 @tparam T 実行する関数の引数の型(コピーできる型である必要があります)
228 @tparam U T に変換できる型
229 @tparam Stack スタックを表す型
230
231 @return 無し。
232
233 :overload fulltemplate
234 */
235 template <typename T, typename U, typename Stack>
236 void Start(void (*f)(T), U param, Stack& stack, s32 priority = DEFAULT_THREAD_PRIORITY, s32 coreNo = CORE_NO_USE_PROCESS_VALUE);
237 template <typename T, typename Stack>
238 void Start(void (*f)(const T*), const T& param, Stack& stack, s32 priority = DEFAULT_THREAD_PRIORITY, s32 coreNo = CORE_NO_USE_PROCESS_VALUE);
239 template <typename T, typename Stack>
240 void Start(void (*f)(const T&), const T& param, Stack& stack, s32 priority = DEFAULT_THREAD_PRIORITY, s32 coreNo = CORE_NO_USE_PROCESS_VALUE);
241
242 /*!
243 @brief スレッドの初期化と実行を試みます。
244
245 スレッドを初期化し実行をしますが、
246 リソース不足などが原因で失敗した場合にエラーを返します。
247
248 @sa Start
249
250 @param[in] f 実行を開始する関数へのポインタ
251 @param[in] stack スタック領域を表すオブジェクト
252 @param[in] priority スレッドの優先度
253 @param[in] coreNo スレッドの優先プロセッサおよびアフィニティマスクの指定
254
255 @tparam Stack スタックを表す型
256
257 @return 関数の実行結果を返します。
258 */
259 template <typename Stack>
260 nn::Result TryStart(void (*f)(), Stack& stack, s32 priority = DEFAULT_THREAD_PRIORITY, s32 coreNo = CORE_NO_USE_PROCESS_VALUE);
261
262 /*!
263 @brief スレッドの初期化と実行を試みます。
264
265 スレッドを初期化し実行をしますが、
266 リソース不足などが原因で失敗した場合にエラーを返します。
267
268 @sa Start
269
270 @param[in] f 実行を開始する関数へのポインタ
271 @param[in] param 実行を開始する関数へ渡す引数
272 @param[in] stack スタック領域を表すオブジェクト
273 @param[in] priority スレッドの優先度
274 @param[in] coreNo スレッドの優先プロセッサおよびアフィニティマスクの指定
275
276 @tparam T 実行する関数の引数の型(コピーできる型である必要があります)
277 @tparam U T に変換できる型
278 @tparam Stack スタックを表す型
279
280 @return 関数の実行結果を返します。
281 */
282 template <typename T, typename U, typename Stack>
283 nn::Result TryStart(void (*f)(T), U param, Stack& stack, s32 priority = DEFAULT_THREAD_PRIORITY, s32 coreNo = CORE_NO_USE_PROCESS_VALUE);
284
285 /*!
286 @brief スレッドを初期化し実行します。
287
288 スタックは指定されたサイズ以上のサイズに自動的に確保され、
289 スレッド終了時に自動的に破棄されます。
290
291 @param[in] f 実行を開始する関数へのポインタ
292 @param[in] stackSize スタックサイズ
293 @param[in] priority スレッドの優先度
294 @param[in] coreNo スレッドの優先プロセッサおよびアフィニティマスクの指定
295
296 @return 無し。
297 */
298 void StartUsingAutoStack(void (*f)(), size_t stackSize, s32 priority = DEFAULT_THREAD_PRIORITY, s32 coreNo = CORE_NO_USE_PROCESS_VALUE);
299
300 /*!
301 @brief スレッドを初期化し実行します。
302
303 スタックは指定されたサイズ以上のサイズに自動的に確保され、
304 スレッド終了時に自動的に破棄されます。
305
306 @param[in] f 実行を開始する関数へのポインタ
307 @param[in] param 実行を開始する関数へ渡す引数
308 @param[in] stackSize スタックサイズ
309 @param[in] priority スレッドの優先度
310 @param[in] coreNo スレッドの優先プロセッサおよびアフィニティマスクの指定
311
312 @tparam T 実行する関数の引数の型(コピーできる型である必要があります)
313 @tparam U T に変換できる型
314
315 @return 無し。
316 */
317 template <typename T, typename U>
318 void StartUsingAutoStack(void (*f)(T), U param, size_t stackSize, s32 priority = DEFAULT_THREAD_PRIORITY, s32 coreNo = CORE_NO_USE_PROCESS_VALUE);
319
320 /*!
321 :overload notemplate
322
323 @brief スレッドの初期化と実行を試みます。
324
325 スレッドを初期化し実行をしますが、
326 リソース不足などが原因で失敗した場合にエラーを返します。
327
328 @sa StartUsingAutoStack
329
330 @param[in] f 実行を開始する関数へのポインタ
331 @param[in] stackSize スタックサイズ
332 @param[in] priority スレッドの優先度
333 @param[in] coreNo スレッドの優先プロセッサおよびアフィニティマスクの指定
334
335 @return 関数の実行結果を返します。
336 */
337 nn::Result TryStartUsingAutoStack(void (*f)(), size_t stackSize, s32 priority = DEFAULT_THREAD_PRIORITY, s32 coreNo = CORE_NO_USE_PROCESS_VALUE);
338
339 /*!
340 :overload template
341
342 @brief スレッドの初期化と実行を試みます。
343
344 スレッドを初期化し実行をしますが、
345 リソース不足などが原因で失敗した場合にエラーを返します。
346
347 @sa StartUsingAutoStack
348
349 @param[in] f 実行を開始する関数へのポインタ
350 @param[in] param 実行を開始する関数へ渡す引数
351 @param[in] stackSize スタックサイズ
352 @param[in] priority スレッドの優先度
353 @param[in] coreNo スレッドの優先プロセッサおよびアフィニティマスクの指定
354
355 @tparam T 実行する関数の引数の型(コピーできる型である必要があります)
356 @tparam U T に変換できる型
357
358 @return 関数の実行結果を返します。
359 */
360 template <typename T, typename U>
361 nn::Result TryStartUsingAutoStack(void (*f)(T), U param, size_t stackSize, s32 priority = DEFAULT_THREAD_PRIORITY, s32 coreNo = CORE_NO_USE_PROCESS_VALUE);
362
363 /*!
364 @brief スレッドオブジェクトを破棄します。
365
366 スレッドを破棄する前に、必ず @ref Detach か @ref Join を呼んでいる必要があります。
367 呼んでいなかった場合、PANIC します。
368
369
370 @return 無し。
371 */
372 void Finalize();
373
374 /*!
375 @brief スレッドの終了を待ちます。
376
377 この関数はスレッドの終了を無条件で待ちます。
378 タイムアウトつきで待つなど、細かい制御が必要な場合は、
379 @ref WaitObject にある関数を使ってスレッドの終了を待った後、
380 この関数を呼び出すようにしてください。
381
382 @return 無し。
383 */
384 void Join();
385
386 /*!
387 @brief スレッドのデタッチを行います。
388
389 このオブジェクトがスレッドに対して今後一切の操作を行わないことを宣言します。
390 このオブジェクトに対しては、@ref Finalize とデストラクタ以外を呼ぶことができなくなります。
391
392 @ref Start を使って開始したスレッドに対してこの関数を呼ぶことはできません。
393
394 @return 無し。
395 */
396 void Detach();
397
398 /*!
399 @brief スレッドが生きているかどうかを取得します。
400
401 @return スレッドが生きているならtrue、そうでないならfalseを返します。
402 */
IsAlive()403 bool IsAlive() const { return !const_cast<Thread*>(this)->WaitOne(0); }
404
405 /*!
406 @brief カレントスレッドを指定時間だけ休止状態にします。
407
408 @param[in] span 休止する時間
409
410 @return 無し。
411 */
412 static void Sleep(nn::fnd::TimeSpan span);
413
414 /*!
415 @brief カレントスレッドと同じ優先度のスレッドに実行機会を与えます。
416
417 スケジューラは優先度スケジューリングを行いますので
418 常に実行可能なスレッドの中で最高優先度のスレッドが動作しています。
419 最高優先度のスレッドが複数存在する場合、
420 スケジューラはカレントスレッドを継続して動作させようと試みますので
421 通常はカレントスレッドが実行可能でなくならない限り
422 同優先度の他のスレッドは実行されません。
423
424 この関数はカレントスレッドを実行可能としたまま
425 同優先度の他のスレッドに実行権を明け渡します。
426 同優先度のスレッドが存在しない場合は何も起りません。
427
428 @return 無し。
429 */
430 static void Yield();
431
432 // スレッドの状態の取得・設定
433 // 非 static メンバ関数は、インスタンスに対して作用する。
434 // "Current" を含む名前の static メンバ関数は、カレントスレッドに対して作用する。
435 // "Default" を含む名前の static メンバ関数は、CreateThread で coreNo = CORE_NO_USE_PROCESS_VALUE のとき、
436 // 作成されるスレッドの属性のデフォルト値に作用する。
437
438 // コンテキストの取得
439 // TODO: 未実装
440 // void GetContext(nn::os::ThreadContext* pContext) const;
441 // static void GetCurrentContext(nn::os::ThreadContext* pContext);
442
443 /*!
444 @brief インスタンスのスレッドのスレッド ID を取得します。
445
446 @return インスタンスのスレッドのスレッド ID を返します。
447 */
448 bit32 GetId() const;
449
450 /*!
451 @brief カレントスレッドのスレッド ID を取得します。
452
453 @return カレントスレッドのスレッド ID を返します。
454 */
455 static bit32 GetCurrentId();
456
457 /*!
458 @brief インスタンスのスレッドの優先度を取得します。
459
460 @return インスタンスのスレッドの優先度を返します。
461 */
462 s32 GetPriority() const;
463
464 /*!
465 @brief カレントスレッドの優先度を取得します。
466
467 @return カレントスレッドの優先度を返します。
468 */
469 static s32 GetCurrentPriority();
470
471 /*!
472 @brief インスタンスのスレッドの優先度を設定します。
473
474 @param[in] priority スレッドの優先度を指定します。
475
476 @return 無し。
477 */
478 void ChangePriority(s32 priority);
479
480 /*!
481 @brief カレントスレッドの優先度を設定します。
482
483 @param[in] priority スレッドの優先度を指定します。
484
485 @return 無し。
486 */
487 static void ChangeCurrentPriority(s32 priority);
488
489 // スレッド Affinity の設定・取得
490 // AffinityMask は構造体やクラスで包む?
491 /*!
492 @brief インスタンスのアフィニティマスクを取得します。
493
494 @param[out] pAffinityMask 取得したアフィニティマスクを格納するバッファを指定します。
495 @param[in] numProcessor pAffinityMask が指すバッファのビット数を指定します。
496
497 @return 無し。
498
499 Bug: この関数は未実装です。この関数を使わないでください。
500 */
501 void GetAffinityMask(bit8* pAffinityMask, s32 numProcessor) const;
502
503 /*!
504 @brief カレントスレッドのアフィニティマスクを取得します。
505
506 @param[out] pAffinityMask 取得したアフィニティマスクを格納するバッファを指定します。
507 @param[in] numProcessor pAffinityMask が指すバッファのビット数を指定します。
508
509 @return 無し。
510
511 Bug: この関数は未実装です。この関数を使わないでください。
512 */
513 static void GetCurrentAffinityMask(bit8* pAffinityMask, s32 numProcessor);
514
515 /*!
516 @brief coreNo = CORE_NO_USE_PROCESS_VALUE で作成されるスレッドのアフィニティマスクを取得します。
517
518 @param[out] pAffinityMask 取得したアフィニティマスクを格納するバッファを指定します。
519 @param[in] numProcessor pAffinityMask が指すバッファのビット数を指定します。
520
521 @return 無し。
522
523 Bug: この関数は未実装です。この関数を使わないでください。
524 */
525 static void GetDefaultAffinityMask(bit8* pAffinityMask, s32 numProcessor);
526
527 /*!
528 @brief インスタンスのアフィニティマスクを設定します。
529
530 @param[in] pAffinityMask 新しく設定するアフィニティマスクを指定します。
531 @param[in] numProcessor pAffinityMask が指すビット列の有効なビット数を指定します。
532
533 @return 無し。
534
535 Bug: この関数は未実装です。この関数を使わないでください。
536 */
537 void ChangeAffinityMask(const bit8* pAffinityMask, s32 numProcessor);
538
539 /*!
540 @brief カレントスレッドのアフィニティマスクを設定します。
541
542 @param[in] pAffinityMask 新しく設定するアフィニティマスクを指定します。
543 @param[in] numProcessor pAffinityMask が指すビット列の有効なビット数を指定します。
544
545 @return 無し。
546
547 Bug: この関数は未実装です。この関数を使わないでください。
548 */
549 static void ChangeCurrentAffinityMask(const bit8* pAffinityMask, s32 numProcessor);
550
551 /*!
552 @brief coreNo = CORE_NO_USE_PROCESS_VALUE で作成されるスレッドのアフィニティマスクを設定します。
553
554 @param[in] pAffinityMask 新しく設定するアフィニティマスクを指定します。
555 @param[in] numProcessor pAffinityMask が指すビット列の有効なビット数を指定します。
556
557 @return 無し。
558
559 Bug: この関数は未実装です。この関数を使わないでください。
560 */
561 static void SetDefaultAffinityMask(const bit8* pAffinityMask, s32 numProcessor);
562
563 // IdealProcessor の取得・設定
564 /*!
565 @brief インスタンスの優先プロセッサ番号を取得します。
566
567 @return 優先プロセッサ番号を返します。
568
569 Bug: この関数は未実装です。この関数を使わないでください。
570 */
571 s32 GetIdealProcessor() const;
572
573 /*!
574 @brief カレントスレッドの優先プロセッサ番号を取得します。
575
576 @return 優先プロセッサ番号を返します。
577
578 Bug: この関数は未実装です。この関数を使わないでください。
579 */
580 static s32 GetCurrentIdealProcessor();
581
582 /*!
583 @brief coreNo = CORE_NO_USE_PROCESS_VALUE で作成されるスレッドの優先プロセッサ番号を取得します。
584
585 @return 優先プロセッサ番号を返します。
586
587 Bug: この関数は未実装です。この関数を使わないでください。
588 */
589 static s32 GetDefaultIdealProcessor();
590
591 /*!
592 @brief インスタンスの優先プロセッサ番号を設定します。
593
594 @param[in] coreNo 優先プロセッサ番号
595
596 @return 無し。
597
598 Bug: この関数は未実装です。この関数を使わないでください。
599 */
600 void ChangeIdealProcessor(s32 coreNo);
601
602 /*!
603 @brief カレントスレッドの優先プロセッサ番号を設定します。
604
605 @param[in] coreNo 優先プロセッサ番号
606
607 @return 無し。
608
609 Bug: この関数は未実装です。この関数を使わないでください。
610 */
611 static void ChangeCurrentIdealProcessor(s32 coreNo);
612
613 /*!
614 @brief coreNo = CORE_NO_USE_PROCESS_VALUE で作成されるスレッドの IdealProcessor を設定します。
615
616 @param[in] coreNo 優先プロセッサ番号
617
618 @return 無し。
619
620 Bug: この関数は未実装です。この関数を使わないでください。
621 */
622 static void SetDefaultIdealProcessor(s32 coreNo);
623
624 /*!
625 @brief カレントスレッドの動作しているプロセッサ番号の取得
626
627 @return カレントスレッドの動作しているプロセッサ番号を返します。
628
629 Bug: この関数は未実装です。この関数を使わないでください。
630 */
631 static s32 GetCurrentProcessorNumber();
632
633 /*!
634 @brief メインスレッドを表すオブジェクトを取得します。
635 @return メインスレッドを表すオブジェクト。
636 */
GetMainThread()637 static Thread& GetMainThread() { return s_MainThread; }
638
639 static void SetAutoStackManager(AutoStackManager* pManager);
640
641
642 private:
643 struct InitializeAsCurrentTag {};
644 struct TypeInfo;
645 struct FunctionInfo;
646
647 private:
648 bool m_CanFinalize;
649 bool m_UsingAutoStack;
650 NN_PADDING2;
651
652 static Thread s_MainThread;
653 static AutoStackManager* s_pAutoStackManager;
654
655 private:
656 Thread(const InitializeAsCurrentTag&);
657 void FinalizeImpl();
658
659 Result TryInitializeAndStartImpl(const TypeInfo& typeInfo, ThreadFunc f, const void* p, uptr stackBottom, s32 priority, s32 coreNo, bool isAutoStack);
660 Result TryInitializeAndStartImplUsingAutoStack(const TypeInfo& typeInfo, ThreadFunc f, const void* p, size_t stackSize, s32 priority, s32 coreNo);
661
662 private:
663 static void OnThreadStart();
664 static void OnThreadExit();
665
666 static void ThreadStart(uptr);
667 static void ThreadStartUsingAutoStack(uptr);
668 static void NoParameterFunc(void (*)());
669 static void SleepImpl(nn::fnd::TimeSpan span);
670
671 static void CallDestructorAndExit(void* pStackBottom);
672 };
673
674 /*!
675 @brief スレッド用のスタックを、static 領域や構造体の中などに配置したい場合に使うクラステンプレートです。
676
677 @ref GetStackBottom 関数の戻り値を @ref Thread::Start 関数などに渡すことで、
678 スレッドのスタックとしてこの領域を使用することができます。
679
680 @tparam Size スタックのサイズを表します。
681 */
682 template <size_t Size>
683 class StackBuffer
684 {
685 private:
686 typename nn::util::aligned_storage<Size, 8>::type m_Buffer;
687 public:
688
689 /*!
690 @brief スタックの底アドレスを返します。
691
692 @return スタックの底アドレス。
693 */
GetStackBottom()694 uptr GetStackBottom() const { return reinterpret_cast<uptr>(this + 1); }
695
696 void MarkCanary(bit32 value = 0xDEADBEEF) { reinterpret_cast<bit32*>(this)[0] = value; }
697 bool CheckCanary(bit32 value = 0xDEADBEEF) const { return reinterpret_cast<const bit32*>(this)[0] == value; }
698 };
699
700 }}
701
702 // インライン実装
703
704 #ifdef NN_SYSTEM_PROCESS
705
706 #include <new>
707
708 #include <nn/dbg/dbg_Logger.h>
709
710 namespace nn { namespace os {
711
712 struct Thread::TypeInfo
713 {
714 private:
715
716 template <typename T, typename U>
CopyTypeInfo717 static void Copy(const void* src, void* dst)
718 {
719 new (dst) T(*reinterpret_cast<const U*>(src));
720 }
721 template <typename T>
CopyTypeInfo722 static void Copy(const void* src, void* dst)
723 {
724 new (dst) T(*reinterpret_cast<const T*>(src));
725 }
726
727 template <typename T>
DestroyTypeInfo728 static void Destroy(void* p)
729 {
730 reinterpret_cast<T*>(p)->~T();
731 }
732
733 template <typename T>
InvokeTypeInfo734 static void Invoke(ThreadFunc f, const void* p)
735 {
736 (*reinterpret_cast<void (*)(T)>(f))(*reinterpret_cast<const T*>(p));
737 }
738 template <typename T>
Invoke2TypeInfo739 static void Invoke2(ThreadFunc f, const void* p)
740 {
741 (*reinterpret_cast<void (*)(const T*)>(f))(reinterpret_cast<const T*>(p));
742 }
743
744 public:
745
746 size_t size;
747 void (*copy)(const void* src, void* dst);
748 void (*destroy)(void* p);
749 void (*invoke)(ThreadFunc f, const void* p);
750
751 template <typename T, typename U>
752 void SetData(typename nn::util::enable_if<nn::util::is_convertible<U, T>::value>::type* = 0)
753 {
754 this->size = sizeof(T);
755 this->copy = &(Copy<T, U>);
756 this->destroy = &(Destroy<T>);
757 this->invoke = &(Invoke<T>);
758 }
759 template <typename T>
SetDataTypeInfo760 void SetData()
761 {
762 this->size = sizeof(T);
763 this->copy = &(Copy<T>);
764 this->destroy = &(Destroy<T>);
765 this->invoke = &(Invoke2<T>);
766 }
767
768 };
769
770 template <typename T, typename U, typename Stack>
Start(void (* f)(T),U param,Stack & stack,s32 priority,s32 coreNo)771 inline void Thread::Start(void (*f)(T), U param, Stack& stack, s32 priority, s32 coreNo)
772 {
773 TypeInfo info;
774 info.SetData<T, U>();
775 NN_ERR_THROW_FATAL(TryInitializeAndStartImpl(info, reinterpret_cast<ThreadFunc>(f), ¶m, stack.GetStackBottom(), priority, coreNo, false));
776 }
777
778 template <typename T, typename Stack>
Start(void (* f)(const T *),const T & param,Stack & stack,s32 priority,s32 coreNo)779 inline void Thread::Start(void (*f)(const T*), const T& param, Stack& stack, s32 priority, s32 coreNo)
780 {
781 TypeInfo info;
782 info.SetData<T>();
783 NN_ERR_THROW_FATAL(TryInitializeAndStartImpl(info, reinterpret_cast<ThreadFunc>(f), ¶m, stack.GetStackBottom(), priority, coreNo, false));
784 }
785
786 template <typename Stack>
Start(void (* f)(),Stack & stack,s32 priority,s32 coreNo)787 inline void Thread::Start(void (*f)(), Stack& stack, s32 priority, s32 coreNo)
788 {
789 Start(NoParameterFunc, f, stack, priority, coreNo);
790 }
791
792 template <typename T, typename U, typename Stack>
TryStart(void (* f)(T),U param,Stack & stack,s32 priority,s32 coreNo)793 inline nn::Result Thread::TryStart(void (*f)(T), U param, Stack& stack, s32 priority, s32 coreNo)
794 {
795 TypeInfo info;
796 info.SetData<T, U>();
797 Result result = TryInitializeAndStartImpl(info, reinterpret_cast<ThreadFunc>(f), ¶m, stack.GetStackBottom(), priority, coreNo, false);
798 if (result.GetSummary() == Result::SUMMARY_OUT_OF_RESOURCE)
799 {
800 return result;
801 }
802 NN_ERR_THROW_FATAL(result);
803 return result;
804 }
805
806 template <typename Stack>
TryStart(void (* f)(),Stack & stack,s32 priority,s32 coreNo)807 inline nn::Result Thread::TryStart(void (*f)(), Stack& stack, s32 priority, s32 coreNo)
808 {
809 return TryStart(NoParameterFunc, f, stack, priority, coreNo);
810 }
811
812 template <typename T, typename U>
StartUsingAutoStack(void (* f)(T),U param,size_t stackSize,s32 priority,s32 coreNo)813 inline void Thread::StartUsingAutoStack(void (*f)(T), U param, size_t stackSize, s32 priority, s32 coreNo)
814 {
815 TypeInfo info;
816 info.SetData<T, U>();
817 NN_ERR_THROW_FATAL(TryInitializeAndStartImplUsingAutoStack(info, reinterpret_cast<ThreadFunc>(f), ¶m, stackSize, priority, coreNo));
818 }
819
StartUsingAutoStack(void (* f)(),size_t stackSize,s32 priority,s32 coreNo)820 inline void Thread::StartUsingAutoStack(void (*f)(), size_t stackSize, s32 priority, s32 coreNo)
821 {
822 StartUsingAutoStack(NoParameterFunc, f, stackSize, priority, coreNo);
823 }
824
825 template <typename T, typename U>
TryStartUsingAutoStack(void (* f)(T),U param,size_t stackSize,s32 priority,s32 coreNo)826 inline nn::Result Thread::TryStartUsingAutoStack(void (*f)(T), U param, size_t stackSize, s32 priority, s32 coreNo)
827 {
828 TypeInfo info;
829 info.SetData<T, U>();
830 Result result = TryInitializeAndStartImplUsingAutoStack(info, reinterpret_cast<ThreadFunc>(f), ¶m, stackSize, priority, coreNo);
831 if (result.GetSummary() == Result::SUMMARY_OUT_OF_RESOURCE)
832 {
833 return result;
834 }
835 NN_ERR_THROW_FATAL(result);
836 return result;
837 }
838
TryStartUsingAutoStack(void (* f)(),size_t stackSize,s32 priority,s32 coreNo)839 inline nn::Result Thread::TryStartUsingAutoStack(void (*f)(), size_t stackSize, s32 priority, s32 coreNo)
840 {
841 return TryStartUsingAutoStack(NoParameterFunc, f, stackSize, priority, coreNo);
842 }
843
FinalizeImpl()844 inline void Thread::FinalizeImpl()
845 {
846 if (!m_CanFinalize)
847 {
848 NN_TPANIC_("Thread is not Joined or Detached either.");
849 }
850 }
851
Finalize()852 inline void Thread::Finalize()
853 {
854 FinalizeImpl();
855 this->WaitObject::Finalize();
856 }
857
~Thread()858 inline Thread::~Thread()
859 {
860 FinalizeImpl();
861 }
862
Join()863 inline void Thread::Join()
864 {
865 this->WaitOne();
866 this->m_CanFinalize = true;
867 }
868
Detach()869 inline void Thread::Detach()
870 {
871 NN_TASSERT_(m_UsingAutoStack);
872 this->m_CanFinalize = true;
873 Finalize();
874 }
875
Sleep(nn::fnd::TimeSpan span)876 inline void Thread::Sleep(nn::fnd::TimeSpan span)
877 {
878 SleepImpl(span);
879 }
880
Yield()881 inline void Thread::Yield()
882 {
883 nn::svc::SleepThread(0);
884 }
885
GetId()886 inline bit32 Thread::GetId() const
887 {
888 bit32 ret;
889 NN_ERR_THROW_FATAL(nn::svc::GetThreadId(&ret, GetHandle()));
890 return ret;
891 }
892
GetCurrentId()893 inline bit32 Thread::GetCurrentId()
894 {
895 bit32 ret;
896 NN_ERR_THROW_FATAL(nn::svc::GetThreadId(&ret, PSEUDO_HANDLE_CURRENT_THREAD));
897 return ret;
898 }
899
GetPriority()900 inline s32 Thread::GetPriority() const
901 {
902 s32 ret;
903 NN_ERR_THROW_FATAL(nn::svc::GetThreadPriority(&ret, GetHandle()));
904 return os::detail::ConvertSvcToLibraryPriority(ret);
905 }
906
GetCurrentPriority()907 inline s32 Thread::GetCurrentPriority()
908 {
909 s32 ret;
910 NN_ERR_THROW_FATAL(nn::svc::GetThreadPriority(&ret, PSEUDO_HANDLE_CURRENT_THREAD));
911 return os::detail::ConvertSvcToLibraryPriority(ret);
912 }
913
ChangePriority(s32 priority)914 inline void Thread::ChangePriority(s32 priority)
915 {
916 NN_ERR_THROW_FATAL(nn::svc::SetThreadPriority(GetHandle(), os::detail::ConvertLibraryToSvcPriority(priority)));
917 }
918
ChangeCurrentPriority(s32 priority)919 inline void Thread::ChangeCurrentPriority(s32 priority)
920 {
921 NN_ERR_THROW_FATAL(nn::svc::SetThreadPriority(PSEUDO_HANDLE_CURRENT_THREAD, os::detail::ConvertLibraryToSvcPriority(priority)));
922 }
923
GetAffinityMask(bit8 * pAffinityMask,s32 numProcessor)924 inline void Thread::GetAffinityMask(bit8* pAffinityMask, s32 numProcessor) const
925 {
926 NN_ERR_THROW_FATAL(nn::svc::GetThreadAffinityMask(pAffinityMask, GetHandle(), numProcessor));
927 }
928
GetCurrentAffinityMask(bit8 * pAffinityMask,s32 numProcessor)929 inline void Thread::GetCurrentAffinityMask(bit8* pAffinityMask, s32 numProcessor)
930 {
931 NN_ERR_THROW_FATAL(nn::svc::GetThreadAffinityMask(pAffinityMask, PSEUDO_HANDLE_CURRENT_THREAD, numProcessor));
932 }
933
GetDefaultAffinityMask(bit8 * pAffinityMask,s32 numProcessor)934 inline void Thread::GetDefaultAffinityMask(bit8* pAffinityMask, s32 numProcessor)
935 {
936 NN_ERR_THROW_FATAL(nn::svc::GetProcessAffinityMask(pAffinityMask, PSEUDO_HANDLE_CURRENT_PROCESS, numProcessor));
937 }
938
ChangeAffinityMask(const bit8 * pAffinityMask,s32 numProcessor)939 inline void Thread::ChangeAffinityMask(const bit8* pAffinityMask, s32 numProcessor)
940 {
941 NN_ERR_THROW_FATAL(nn::svc::SetThreadAffinityMask(GetHandle(), pAffinityMask, numProcessor));
942 }
943
ChangeCurrentAffinityMask(const bit8 * pAffinityMask,s32 numProcessor)944 inline void Thread::ChangeCurrentAffinityMask(const bit8* pAffinityMask, s32 numProcessor)
945 {
946 NN_ERR_THROW_FATAL(nn::svc::SetThreadAffinityMask(PSEUDO_HANDLE_CURRENT_THREAD, pAffinityMask, numProcessor));
947 }
948
SetDefaultAffinityMask(const bit8 * pAffinityMask,s32 numProcessor)949 inline void Thread::SetDefaultAffinityMask(const bit8* pAffinityMask, s32 numProcessor)
950 {
951 NN_ERR_THROW_FATAL(nn::svc::SetProcessAffinityMask(PSEUDO_HANDLE_CURRENT_PROCESS, pAffinityMask, numProcessor));
952 }
953
GetIdealProcessor()954 inline s32 Thread::GetIdealProcessor() const
955 {
956 s32 ret;
957 NN_ERR_THROW_FATAL(nn::svc::GetThreadIdealProcessor(&ret, GetHandle()));
958 return ret;
959 }
960
GetCurrentIdealProcessor()961 inline s32 Thread::GetCurrentIdealProcessor()
962 {
963 s32 ret;
964 NN_ERR_THROW_FATAL(nn::svc::GetThreadIdealProcessor(&ret, PSEUDO_HANDLE_CURRENT_THREAD));
965 return ret;
966 }
967
GetDefaultIdealProcessor()968 inline s32 Thread::GetDefaultIdealProcessor()
969 {
970 s32 ret;
971 NN_ERR_THROW_FATAL(nn::svc::GetProcessIdealProcessor(&ret, PSEUDO_HANDLE_CURRENT_PROCESS));
972 return ret;
973 }
974
ChangeIdealProcessor(s32 coreNo)975 inline void Thread::ChangeIdealProcessor(s32 coreNo)
976 {
977 NN_ERR_THROW_FATAL(nn::svc::SetThreadIdealProcessor(GetHandle(), coreNo));
978 }
979
ChangeCurrentIdealProcessor(s32 coreNo)980 inline void Thread::ChangeCurrentIdealProcessor(s32 coreNo)
981 {
982 NN_ERR_THROW_FATAL(nn::svc::SetThreadIdealProcessor(PSEUDO_HANDLE_CURRENT_THREAD, coreNo));
983 }
984
SetDefaultIdealProcessor(s32 coreNo)985 inline void Thread::SetDefaultIdealProcessor(s32 coreNo)
986 {
987 NN_ERR_THROW_FATAL(nn::svc::SetProcessIdealProcessor(PSEUDO_HANDLE_CURRENT_PROCESS, coreNo));
988 }
989
GetCurrentProcessorNumber()990 inline s32 Thread::GetCurrentProcessorNumber()
991 {
992 return nn::svc::GetCurrentProcessorNumber();
993 }
994
995
996 /*!
997 @}
998 */
999 /*!
1000 @}
1001 */
1002
1003 }} // namespace nn::os
1004
1005 #endif // NN_SYSTEM_PROCESS
1006
1007 #endif // __cplusplus
1008
1009 // 以下、C 用宣言
1010
1011 #include <nn/util/detail/util_CLibImpl.h>
1012
1013
1014 /*!
1015 @addtogroup nn_os os
1016 @{
1017
1018 @defgroup nn_os_Thread_c Thread (C)
1019
1020 @brief @ref nn::os::Thread の C インタフェースモジュールです。
1021
1022 @{
1023 */
1024
1025 /*!
1026 @struct nnosThread
1027 @brief スレッドを表す C の構造体です。
1028
1029 @brief 対応するクラス @ref nn::os::Thread を参照してください。
1030 */
1031 NN_UTIL_DETAIL_CLIBIMPL_DEFINE_BUFFER_CLASS(nnosThread, nn::os::Thread, 8, u32);
1032
1033 /*!
1034 @brief 対応する C++ 関数 @ref nn::os::Thread::Start を参照してください。
1035 */
1036 NN_EXTERN_C void nnosThreadInitializeAndStart(nnosThread* this_, void (*f)(uptr), uptr param, uptr stackBottom, s32 priority, s32 coreNo);
1037
1038 /*!
1039 @brief 対応する C++ 関数 @ref nn::os::Thread::TryStart を参照してください。
1040 */
1041 NN_EXTERN_C bool nnosThreadTryInitializeAndStart(nnosThread* this_, void (*f)(uptr), uptr param, uptr stackBottom, s32 priority, s32 coreNo);
1042
1043 /*!
1044 @brief 対応する C++ 関数 @ref nn::os::Thread::Finalize を参照してください。
1045 */
1046 NN_EXTERN_C void nnosThreadFinalize(nnosThread* this_);
1047
1048 /*!
1049 @brief 対応する C++ 関数 @ref nn::os::Thread::Join を参照してください。
1050 */
1051 NN_EXTERN_C void nnosThreadJoin(nnosThread* this_);
1052
1053 /*!
1054 @brief 対応する C++ 関数 @ref nn::os::Thread::Sleep を参照してください。
1055 */
1056 NN_EXTERN_C void nnosThreadSleep(s64 nanoSeconds);
1057
1058 /*!
1059 @brief 対応する C++ 関数 @ref nn::os::Thread::Yield を参照してください。
1060 */
1061 NN_EXTERN_C void nnosThreadYield(void);
1062
1063 /*!
1064 @brief 対応する C++ 関数 @ref nn::os::Thread::GetCurrentId を参照してください。
1065 */
1066 NN_EXTERN_C bit32 nnosThreadGetCurrentId(void);
1067
1068 /*!
1069 @brief 対応する C++ 関数 @ref nn::os::Thread::GetPriority を参照してください。
1070 */
1071 NN_EXTERN_C s32 nnosThreadGetPriority(const nnosThread* this_);
1072
1073 /*!
1074 @brief 対応する C++ 関数 @ref nn::os::Thread::GetCurrentPriority を参照してください。
1075 */
1076 NN_EXTERN_C s32 nnosThreadGetCurrentPriority(void);
1077
1078 /*!
1079 @brief 対応する C++ 関数 @ref nn::os::Thread::ChangePriority を参照してください。
1080 */
1081 NN_EXTERN_C void nnosThreadChangePriority(nnosThread* this_, s32 priority);
1082
1083 /*!
1084 @brief 対応する C++ 関数 @ref nn::os::Thread::ChangeCurrentPriority を参照してください。
1085 */
1086 NN_EXTERN_C void nnosThreadChangeCurrentPriority(s32 priority);
1087
1088 // スレッド Affinity の設定・取得
1089
1090 /*!
1091 @brief 対応する C++ 関数 @ref nn::os::Thread::GetAffinityMask を参照してください。
1092 */
1093 NN_EXTERN_C void nnosThreadGetAffinityMask(const nnosThread* this_, bit8* pAffinityMask, s32 numProcessor);
1094
1095 /*!
1096 @brief 対応する C++ 関数 @ref nn::os::Thread::GetCurrentAffinityMask を参照してください。
1097 */
1098 NN_EXTERN_C void nnosThreadGetCurrentAffinityMask(bit8* pAffinityMask, s32 numProcessor);
1099
1100 /*!
1101 @brief 対応する C++ 関数 @ref nn::os::Thread::GetDefaultAffinityMask を参照してください。
1102 */
1103 NN_EXTERN_C void nnosThreadGetDefaultAffinityMask(bit8* pAffinityMask, s32 numProcessor);
1104
1105 /*!
1106 @brief 対応する C++ 関数 @ref nn::os::Thread::ChangeAffinityMask を参照してください。
1107 */
1108 NN_EXTERN_C void nnosThreadChangeAffinityMask(nnosThread* this_, const bit8* pAffinityMask, s32 numProcessor);
1109
1110 /*!
1111 @brief 対応する C++ 関数 @ref nn::os::Thread::ChangeCurrentAffinityMask を参照してください。
1112 */
1113 NN_EXTERN_C void nnosThreadChangeCurrentAffinityMask(const bit8* pAffinityMask, s32 numProcessor);
1114
1115 /*!
1116 @brief 対応する C++ 関数 @ref nn::os::Thread::SetDefaultAffinityMask を参照してください。
1117 */
1118 NN_EXTERN_C void nnosThreadSetDefaultAffinityMask(const bit8* pAffinityMask, s32 numProcessor);
1119
1120 // IdealProcessor の取得・設定
1121
1122 /*!
1123 @brief 対応する C++ 関数 @ref nn::os::Thread::GetIdealProcessor を参照してください。
1124 */
1125 NN_EXTERN_C s32 nnosThreadGetIdealProcessor(const nnosThread* this_);
1126
1127 /*!
1128 @brief 対応する C++ 関数 @ref nn::os::Thread::GetCurrentIdealProcessor を参照してください。
1129 */
1130 NN_EXTERN_C s32 nnosThreadGetCurrentIdealProcessor(void);
1131
1132 /*!
1133 @brief 対応する C++ 関数 @ref nn::os::Thread::GetDefaultIdealProcessor を参照してください。
1134 */
1135 NN_EXTERN_C s32 nnosThreadGetDefaultIdealProcessor(void);
1136
1137 /*!
1138 @brief 対応する C++ 関数 @ref nn::os::Thread::ChangeIdealProcessor を参照してください。
1139 */
1140 NN_EXTERN_C void nnosThreadChangeIdealProcessor(nnosThread* this_, s32 coreNo);
1141
1142 /*!
1143 @brief 対応する C++ 関数 @ref nn::os::Thread::ChangeCurrentIdealProcessor を参照してください。
1144 */
1145 NN_EXTERN_C void nnosThreadChangeCurrentIdealProcessor(s32 coreNo);
1146
1147 /*!
1148 @brief 対応する C++ 関数 @ref nn::os::Thread::SetDefaultIdealProcessor を参照してください。
1149 */
1150 NN_EXTERN_C void nnosThreadSetDefaultIdealProcessor(s32 coreNo);
1151
1152 // カレントスレッドの動作しているプロセッサ番号の取得
1153
1154 /*!
1155 @brief 対応する C++ 関数 @ref nn::os::Thread::GetCurrentProcessorNumber を参照してください。
1156 */
1157 NN_EXTERN_C s32 nnosThreadGetCurrentProcessorNumber(void);
1158
1159 /*!
1160 @brief 対応する C++ 関数 @ref nn::os::Thread::GetID を参照してください。
1161 */
1162 NN_EXTERN_C bit32 nnosThreadGetId(nnosThread* this_);
1163
1164 /*!
1165 @brief 対応する C++ 関数 @ref nn::os::Thread::IsAlive を参照してください。
1166 */
1167 NN_EXTERN_C bool nnosThreadIsAlive(nnosThread* this_);
1168
1169 /*!
1170 @brief 対応する C++ 関数 @ref nn::os::Thread::GetMainThread を参照してください。
1171 */
1172 NN_EXTERN_C nnosThread* nnosThreadGetMainThread(void);
1173
1174 /*!
1175 @}
1176 @}
1177 */
1178
1179 /* NN_OS_THREAD_H_ */
1180 #endif
1181
1182