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