/*---------------------------------------------------------------------------* Project: Horizon File: os_Thread.h Copyright (C)2009 Nintendo Co., Ltd. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Rev: 25856 $ *---------------------------------------------------------------------------*/ /*! @file @brief Thread に関する API の宣言 :include nn/os.h */ #ifndef NN_OS_OS_THREAD_H_ #define NN_OS_OS_THREAD_H_ #include #include #include #include #include #include #include #include /* @def NN_OS_CORE_NO_ALL @brief 対応する C++ 関数を参照してください。@ref nn::os::CORE_NO_ALL */ #define NN_OS_CORE_NO_ALL (-1) /* @def NN_OS_CORE_NO_USE_PROCESS_VALUE @brief 対応する C++ 関数を参照してください。@ref nn::os::CORE_NO_USE_PROCESS_VALUE */ #define NN_OS_CORE_NO_USE_PROCESS_VALUE (-2) #define NN_OS_THREAD_PRIORITY_RANGE_SIZE 32 /* @def NN_OS_LOWEST_THREAD_PRIORITY @brief 対応する C++ 関数を参照してください。@ref nn::os::LOWEST_THREAD_PRIORITY */ #define NN_OS_LOWEST_THREAD_PRIORITY (NN_OS_THREAD_PRIORITY_RANGE_SIZE - 1) /* @def NN_OS_HIGHEST_THREAD_PRIORITY @brief 対応する C++ 関数を参照してください。@ref nn::os::HIGHEST_THREAD_PRIORITY */ #define NN_OS_HIGHEST_THREAD_PRIORITY 0 /* @def NN_OS_DEFAULT_THREAD_PRIORITY @brief 対応する C++ 関数を参照してください。@ref nn::os::DEFAULT_THREAD_PRIORITY */ #define NN_OS_DEFAULT_THREAD_PRIORITY 16 #ifdef __cplusplus #include namespace nn{ namespace os{ namespace detail { s32 ConvertSvcToLibraryPriority(s32 svc); s32 ConvertLibraryToSvcPriority(s32 lib); } /* @brief スレッドの最低優先度を表す定数です。31 です。 */ const s32 LOWEST_THREAD_PRIORITY = NN_OS_LOWEST_THREAD_PRIORITY; /* @brief スレッドの最高優先度を表す定数です。0 です。 */ const s32 HIGHEST_THREAD_PRIORITY = NN_OS_HIGHEST_THREAD_PRIORITY; /* @brief デフォルトのスレッド優先度を表す定数です。16 です。 */ const s32 DEFAULT_THREAD_PRIORITY = NN_OS_DEFAULT_THREAD_PRIORITY; /* @brief スレッドを実行するプロセッサ番号がどれでも良いことを表します。 */ const s32 CORE_NO_ALL = NN_OS_CORE_NO_ALL; /* @brief スレッドの実行をするプロセッサ番号を指定する際、アプリケーションで設定されているデフォルトの番号を使うことを表します。 */ const s32 CORE_NO_USE_PROCESS_VALUE = NN_OS_CORE_NO_USE_PROCESS_VALUE; const s32 THREAD_PRIORITY_RANGE_SIZE = NN_OS_THREAD_PRIORITY_RANGE_SIZE; /* @typedef void (*ThreadFunc)(uptr param) @brief スレッドで実行する関数の型を表します。 */ /*! @brief スレッドを表すクラスです。 Bug: 現在の実装では、優先プロセッサやアフィニティマスクの設定はできません。 スレッドには優先度があります。 スレッド優先度には 0~31 までの整数で指定することができ、0 が一番高い優先度を表します。 標準的なスレッドは @ref DEFAULT_THREAD_PRIORITY (16)を指定します。 スレッドの動作にはスタック領域が必要ですが、 スタック領域の管理は、自分で管理することもライブラリに任せることもできます。 自分でスタック領域を管理する場合は @ref Start 関数にスタック領域を渡し、スレッドを開始します。 スタック領域は uptr GetStackBottom() 関数を持つようなクラスのインスタンスを渡します。 @ref StackMemoryBlock や @ref StackBuffer はこの条件を満たすクラスのため、直接渡すことができます。 自分でスタック領域を管理する場合は、 スレッドが終了する前にスタック領域が無効になる(解放されるなど)ことがないように十分に注意してください。 ライブラリにスタック領域の管理を任せる場合は @ref StartUsingAutoStack 関数にスタックサイズを渡し、スレッドを開始します。 ライブラリが確保するスタック領域のサイズは4096byte単位です。 @ref Start によって開始された Thread オブジェクトを破棄する前には、 必ず明示的に @ref Joinを呼ぶ必要があります。 @ref Detach を呼ぶことはできません。 @ref StartUsingAutoStack によって開始された Thread オブジェクトを破棄する前には、 必ず明示的に @ref Join か @ref Detach を呼ぶ必要があります。 Thread オブジェクトは @ref WaitObject を継承しており、Wait 動作の解放はスレッドの終了を意味します。 @ref Join 動作をブロック無しに行う必要がある際は、 先に @ref WaitOne や @ref WaitObject::WaitAny などを呼んで Wait 動作の解放を確認しておきます。 ※現在の実装では優先プロセッサやアフィニティマスクをスレッド開始時以外に指定することはできません。 スレッドには、優先プロセッサおよびアフィニティマスクを指定することができます。 優先プロセッサには、0 ~ (コア数-1) まで指定することができます。 また、@ref CORE_NO_ALL を指定すると全てのプロセッサを平等に扱うように優先プロセッサを設定し、 全てのプロセッサを含むアフィニティマスクを使用します。 @ref CORE_NO_USE_PROCESS_VALUE を指定すると、所属するアプリケーションのデフォルトの値を使用します。 優先プロセッサを指定すると、スレッドは指定されたプロセッサ上で優先して動作しますが、 必ずしも指定どおりのプロセッサ上で動作するわけではありません。 アフィニティマスクは、スレッドがどのプロセッサ上で実行されるべきかを指定するものです。 bit8の配列で表現し、各要素は下位1ビット目が最初のプロセッサを表します。 ビットを1にすることで、対象のプロセッサで走行する許可を与えます。 必ず、どれかのプロセッサをしてする必要があり、全てのビット0にしたマスクを指定することはできません。 スレッドの開始時には優先プロセッサを指定することができますが、 ここでプロセッサ番号を指定した場合、 スレッド開始時のアフィニティマスクはそのプロセッサ番号のみが指定されたことになります。 */ class Thread : public WaitObject { public: class AutoStackManager { public: virtual void* Construct(size_t stackSize) = 0; virtual void Destruct(void* pStackBottom, bool isError) = 0; }; public: /*! @brief コンストラクタです。 スレッドを開始するには、@ref Start または @ref TryStart を使います。 */ Thread() : m_CanFinalize(true) {} /*! @brief デストラクタ スレッドオブジェクトを破棄します。 破棄時の注意は @ref Finalize を参照してください。 */ ~Thread(); /*! @brief スレッドを初期化し実行します。 ユーザが用意したスタックを使ってスレッドを初期化し、スレッドを開始します。 スレッドの終了が確認されるまで、スタック領域は維持されている必要があります。 @param[in] f 実行を開始する関数へのポインタ @param[in] stack スタック領域を表すオブジェクト @param[in] priority スレッドの優先度 @param[in] coreNo スレッドの優先プロセッサ @tparam Stack スタックを表す型 @return 無し。 :overload partialtemplate */ template void Start(void (*f)(), Stack& stack, s32 priority = DEFAULT_THREAD_PRIORITY, s32 coreNo = CORE_NO_USE_PROCESS_VALUE); /*! @brief スレッドを初期化し実行します。 ユーザが用意したスタックを使ってスレッドを初期化し、スレッドを開始します。 スレッドの終了が確認されるまで、スタック領域は維持されている必要があります。 @param[in] f 実行を開始する関数へのポインタ @param[in] param 実行を開始する関数へ渡す引数 @param[in] stack スタック領域を表すオブジェクト @param[in] priority スレッドの優先度 @param[in] coreNo スレッドの優先プロセッサ @tparam T 実行する関数の引数の型(コピーできる型である必要があります) @tparam U T に変換できる型 @tparam Stack スタックを表す型 @return 無し。 :overload fulltemplate */ template void Start(void (*f)(T), U param, Stack& stack, s32 priority = DEFAULT_THREAD_PRIORITY, s32 coreNo = CORE_NO_USE_PROCESS_VALUE); template void Start(void (*f)(const T*), const T& param, Stack& stack, s32 priority = DEFAULT_THREAD_PRIORITY, s32 coreNo = CORE_NO_USE_PROCESS_VALUE); template void Start(void (*f)(const T&), const T& param, Stack& stack, s32 priority = DEFAULT_THREAD_PRIORITY, s32 coreNo = CORE_NO_USE_PROCESS_VALUE); /*! @brief スレッドの初期化と実行を試みます。 スレッドを初期化し実行をしますが、 リソース不足などが原因で失敗した場合にエラーを返します。 @sa Start @param[in] f 実行を開始する関数へのポインタ @param[in] stack スタック領域を表すオブジェクト @param[in] priority スレッドの優先度 @param[in] coreNo スレッドの優先プロセッサおよびアフィニティマスクの指定 @tparam Stack スタックを表す型 @return 関数の実行結果を返します。 */ template nn::Result TryStart(void (*f)(), Stack& stack, s32 priority = DEFAULT_THREAD_PRIORITY, s32 coreNo = CORE_NO_USE_PROCESS_VALUE); /*! @brief スレッドの初期化と実行を試みます。 スレッドを初期化し実行をしますが、 リソース不足などが原因で失敗した場合にエラーを返します。 @sa Start @param[in] f 実行を開始する関数へのポインタ @param[in] param 実行を開始する関数へ渡す引数 @param[in] stack スタック領域を表すオブジェクト @param[in] priority スレッドの優先度 @param[in] coreNo スレッドの優先プロセッサおよびアフィニティマスクの指定 @tparam T 実行する関数の引数の型(コピーできる型である必要があります) @tparam U T に変換できる型 @tparam Stack スタックを表す型 @return 関数の実行結果を返します。 */ template nn::Result TryStart(void (*f)(T), U param, Stack& stack, s32 priority = DEFAULT_THREAD_PRIORITY, s32 coreNo = CORE_NO_USE_PROCESS_VALUE); /*! @brief スレッドを初期化し実行します。 スタックは指定されたサイズ以上のサイズに自動的に確保され、 スレッド終了時に自動的に破棄されます。 @param[in] f 実行を開始する関数へのポインタ @param[in] stackSize スタックサイズ @param[in] priority スレッドの優先度 @param[in] coreNo スレッドの優先プロセッサおよびアフィニティマスクの指定 @return 無し。 */ void StartUsingAutoStack(void (*f)(), size_t stackSize, s32 priority = DEFAULT_THREAD_PRIORITY, s32 coreNo = CORE_NO_USE_PROCESS_VALUE); /*! @brief スレッドを初期化し実行します。 スタックは指定されたサイズ以上のサイズに自動的に確保され、 スレッド終了時に自動的に破棄されます。 @param[in] f 実行を開始する関数へのポインタ @param[in] param 実行を開始する関数へ渡す引数 @param[in] stackSize スタックサイズ @param[in] priority スレッドの優先度 @param[in] coreNo スレッドの優先プロセッサおよびアフィニティマスクの指定 @tparam T 実行する関数の引数の型(コピーできる型である必要があります) @tparam U T に変換できる型 @return 無し。 */ template void StartUsingAutoStack(void (*f)(T), U param, size_t stackSize, s32 priority = DEFAULT_THREAD_PRIORITY, s32 coreNo = CORE_NO_USE_PROCESS_VALUE); /*! :overload notemplate @brief スレッドの初期化と実行を試みます。 スレッドを初期化し実行をしますが、 リソース不足などが原因で失敗した場合にエラーを返します。 @sa StartUsingAutoStack @param[in] f 実行を開始する関数へのポインタ @param[in] stackSize スタックサイズ @param[in] priority スレッドの優先度 @param[in] coreNo スレッドの優先プロセッサおよびアフィニティマスクの指定 @return 関数の実行結果を返します。 */ nn::Result TryStartUsingAutoStack(void (*f)(), size_t stackSize, s32 priority = DEFAULT_THREAD_PRIORITY, s32 coreNo = CORE_NO_USE_PROCESS_VALUE); /*! :overload template @brief スレッドの初期化と実行を試みます。 スレッドを初期化し実行をしますが、 リソース不足などが原因で失敗した場合にエラーを返します。 @sa StartUsingAutoStack @param[in] f 実行を開始する関数へのポインタ @param[in] param 実行を開始する関数へ渡す引数 @param[in] stackSize スタックサイズ @param[in] priority スレッドの優先度 @param[in] coreNo スレッドの優先プロセッサおよびアフィニティマスクの指定 @tparam T 実行する関数の引数の型(コピーできる型である必要があります) @tparam U T に変換できる型 @return 関数の実行結果を返します。 */ template nn::Result TryStartUsingAutoStack(void (*f)(T), U param, size_t stackSize, s32 priority = DEFAULT_THREAD_PRIORITY, s32 coreNo = CORE_NO_USE_PROCESS_VALUE); /*! @brief スレッドオブジェクトを破棄します。 スレッドを破棄する前に、必ず @ref Detach か @ref Join を呼んでいる必要があります。 呼んでいなかった場合、PANIC します。 @return 無し。 */ void Finalize(); /*! @brief スレッドの終了を待ちます。 この関数はスレッドの終了を無条件で待ちます。 タイムアウトつきで待つなど、細かい制御が必要な場合は、 @ref WaitObject にある関数を使ってスレッドの終了を待った後、 この関数を呼び出すようにしてください。 @return 無し。 */ void Join(); /*! @brief スレッドのデタッチを行います。 このオブジェクトがスレッドに対して今後一切の操作を行わないことを宣言します。 このオブジェクトに対しては、@ref Finalize とデストラクタ以外を呼ぶことができなくなります。 @ref Start を使って開始したスレッドに対してこの関数を呼ぶことはできません。 @return 無し。 */ void Detach(); /*! @brief スレッドが生きているかどうかを取得します。 @return スレッドが生きているならtrue、そうでないならfalseを返します。 */ bool IsAlive() const { return !const_cast(this)->WaitOne(0); } /*! @brief カレントスレッドを指定時間だけ休止状態にします。 @param[in] span 休止する時間 @return 無し。 */ static void Sleep(nn::fnd::TimeSpan span); /*! @brief カレントスレッドと同じ優先度のスレッドに実行機会を与えます。 スケジューラは優先度スケジューリングを行いますので 常に実行可能なスレッドの中で最高優先度のスレッドが動作しています。 最高優先度のスレッドが複数存在する場合、 スケジューラはカレントスレッドを継続して動作させようと試みますので 通常はカレントスレッドが実行可能でなくならない限り 同優先度の他のスレッドは実行されません。 この関数はカレントスレッドを実行可能としたまま 同優先度の他のスレッドに実行権を明け渡します。 同優先度のスレッドが存在しない場合は何も起りません。 @return 無し。 */ static void Yield(); // スレッドの状態の取得・設定 // 非 static メンバ関数は、インスタンスに対して作用する。 // "Current" を含む名前の static メンバ関数は、カレントスレッドに対して作用する。 // "Default" を含む名前の static メンバ関数は、CreateThread で coreNo = CORE_NO_USE_PROCESS_VALUE のとき、 // 作成されるスレッドの属性のデフォルト値に作用する。 // コンテキストの取得 // TODO: 未実装 // void GetContext(nn::os::ThreadContext* pContext) const; // static void GetCurrentContext(nn::os::ThreadContext* pContext); /*! @brief インスタンスのスレッドのスレッド ID を取得します。 @return インスタンスのスレッドのスレッド ID を返します。 */ bit32 GetId() const; /*! @brief カレントスレッドのスレッド ID を取得します。 @return カレントスレッドのスレッド ID を返します。 */ static bit32 GetCurrentId(); /*! @brief インスタンスのスレッドの優先度を取得します。 @return インスタンスのスレッドの優先度を返します。 */ s32 GetPriority() const; /*! @brief カレントスレッドの優先度を取得します。 @return カレントスレッドの優先度を返します。 */ static s32 GetCurrentPriority(); /*! @brief インスタンスのスレッドの優先度を設定します。 @param[in] priority スレッドの優先度を指定します。 @return 無し。 */ void ChangePriority(s32 priority); /*! @brief カレントスレッドの優先度を設定します。 @param[in] priority スレッドの優先度を指定します。 @return 無し。 */ static void ChangeCurrentPriority(s32 priority); // スレッド Affinity の設定・取得 // AffinityMask は構造体やクラスで包む? /*! @brief インスタンスのアフィニティマスクを取得します。 @param[out] pAffinityMask 取得したアフィニティマスクを格納するバッファを指定します。 @param[in] numProcessor pAffinityMask が指すバッファのビット数を指定します。 @return 無し。 Bug: この関数は未実装です。この関数を使わないでください。 */ void GetAffinityMask(bit8* pAffinityMask, s32 numProcessor) const; /*! @brief カレントスレッドのアフィニティマスクを取得します。 @param[out] pAffinityMask 取得したアフィニティマスクを格納するバッファを指定します。 @param[in] numProcessor pAffinityMask が指すバッファのビット数を指定します。 @return 無し。 Bug: この関数は未実装です。この関数を使わないでください。 */ static void GetCurrentAffinityMask(bit8* pAffinityMask, s32 numProcessor); /*! @brief coreNo = CORE_NO_USE_PROCESS_VALUE で作成されるスレッドのアフィニティマスクを取得します。 @param[out] pAffinityMask 取得したアフィニティマスクを格納するバッファを指定します。 @param[in] numProcessor pAffinityMask が指すバッファのビット数を指定します。 @return 無し。 Bug: この関数は未実装です。この関数を使わないでください。 */ static void GetDefaultAffinityMask(bit8* pAffinityMask, s32 numProcessor); /*! @brief インスタンスのアフィニティマスクを設定します。 @param[in] pAffinityMask 新しく設定するアフィニティマスクを指定します。 @param[in] numProcessor pAffinityMask が指すビット列の有効なビット数を指定します。 @return 無し。 Bug: この関数は未実装です。この関数を使わないでください。 */ void ChangeAffinityMask(const bit8* pAffinityMask, s32 numProcessor); /*! @brief カレントスレッドのアフィニティマスクを設定します。 @param[in] pAffinityMask 新しく設定するアフィニティマスクを指定します。 @param[in] numProcessor pAffinityMask が指すビット列の有効なビット数を指定します。 @return 無し。 Bug: この関数は未実装です。この関数を使わないでください。 */ static void ChangeCurrentAffinityMask(const bit8* pAffinityMask, s32 numProcessor); /*! @brief coreNo = CORE_NO_USE_PROCESS_VALUE で作成されるスレッドのアフィニティマスクを設定します。 @param[in] pAffinityMask 新しく設定するアフィニティマスクを指定します。 @param[in] numProcessor pAffinityMask が指すビット列の有効なビット数を指定します。 @return 無し。 Bug: この関数は未実装です。この関数を使わないでください。 */ static void SetDefaultAffinityMask(const bit8* pAffinityMask, s32 numProcessor); // IdealProcessor の取得・設定 /*! @brief インスタンスの優先プロセッサ番号を取得します。 @return 優先プロセッサ番号を返します。 Bug: この関数は未実装です。この関数を使わないでください。 */ s32 GetIdealProcessor() const; /*! @brief カレントスレッドの優先プロセッサ番号を取得します。 @return 優先プロセッサ番号を返します。 Bug: この関数は未実装です。この関数を使わないでください。 */ static s32 GetCurrentIdealProcessor(); /*! @brief coreNo = CORE_NO_USE_PROCESS_VALUE で作成されるスレッドの優先プロセッサ番号を取得します。 @return 優先プロセッサ番号を返します。 Bug: この関数は未実装です。この関数を使わないでください。 */ static s32 GetDefaultIdealProcessor(); /*! @brief インスタンスの優先プロセッサ番号を設定します。 @param[in] coreNo 優先プロセッサ番号 @return 無し。 Bug: この関数は未実装です。この関数を使わないでください。 */ void ChangeIdealProcessor(s32 coreNo); /*! @brief カレントスレッドの優先プロセッサ番号を設定します。 @param[in] coreNo 優先プロセッサ番号 @return 無し。 Bug: この関数は未実装です。この関数を使わないでください。 */ static void ChangeCurrentIdealProcessor(s32 coreNo); /*! @brief coreNo = CORE_NO_USE_PROCESS_VALUE で作成されるスレッドの IdealProcessor を設定します。 @param[in] coreNo 優先プロセッサ番号 @return 無し。 Bug: この関数は未実装です。この関数を使わないでください。 */ static void SetDefaultIdealProcessor(s32 coreNo); /*! @brief カレントスレッドの動作しているプロセッサ番号の取得 @return カレントスレッドの動作しているプロセッサ番号を返します。 Bug: この関数は未実装です。この関数を使わないでください。 */ static s32 GetCurrentProcessorNumber(); /*! @brief メインスレッドを表すオブジェクトを取得します。 @return メインスレッドを表すオブジェクト。 */ static Thread& GetMainThread() { return s_MainThread; } static void SetAutoStackManager(AutoStackManager* pManager); private: struct InitializeAsCurrentTag {}; struct TypeInfo; struct FunctionInfo; private: bool m_CanFinalize; bool m_UsingAutoStack; NN_PADDING2; static Thread s_MainThread; static AutoStackManager* s_pAutoStackManager; private: Thread(const InitializeAsCurrentTag&); void FinalizeImpl(); Result TryInitializeAndStartImpl(const TypeInfo& typeInfo, ThreadFunc f, const void* p, uptr stackBottom, s32 priority, s32 coreNo, bool isAutoStack); Result TryInitializeAndStartImplUsingAutoStack(const TypeInfo& typeInfo, ThreadFunc f, const void* p, size_t stackSize, s32 priority, s32 coreNo); private: static void OnThreadStart(); static void OnThreadExit(); static void ThreadStart(uptr); static void ThreadStartUsingAutoStack(uptr); static void NoParameterFunc(void (*)()); static void SleepImpl(nn::fnd::TimeSpan span); static void CallDestructorAndExit(void* pStackBottom); }; /*! @brief スレッド用のスタックを、static 領域や構造体の中などに配置したい場合に使うクラステンプレートです。 @ref GetStackBottom 関数の戻り値を @ref Thread::Start 関数などに渡すことで、 スレッドのスタックとしてこの領域を使用することができます。 @tparam Size スタックのサイズを表します。 */ template class StackBuffer { private: typename nn::util::aligned_storage::type m_Buffer; public: /*! @brief スタックの底アドレスを返します。 @return スタックの底アドレス。 */ uptr GetStackBottom() const { return reinterpret_cast(this + 1); } }; }} // インライン実装 #ifdef NN_SYSTEM_PROCESS #include #include namespace nn { namespace os { struct Thread::TypeInfo { private: template static void Copy(const void* src, void* dst) { new (dst) T(*reinterpret_cast(src)); } template static void Copy(const void* src, void* dst) { new (dst) T(*reinterpret_cast(src)); } template static void Destroy(void* p) { reinterpret_cast(p)->~T(); } template static void Invoke(ThreadFunc f, const void* p) { (*reinterpret_cast(f))(*reinterpret_cast(p)); } template static void Invoke2(ThreadFunc f, const void* p) { (*reinterpret_cast(f))(reinterpret_cast(p)); } public: size_t size; void (*copy)(const void* src, void* dst); void (*destroy)(void* p); void (*invoke)(ThreadFunc f, const void* p); template void SetData(typename nn::util::enable_if::value>::type* = 0) { this->size = sizeof(T); this->copy = &(Copy); this->destroy = &(Destroy); this->invoke = &(Invoke); } template void SetData() { this->size = sizeof(T); this->copy = &(Copy); this->destroy = &(Destroy); this->invoke = &(Invoke2); } }; template inline void Thread::Start(void (*f)(T), U param, Stack& stack, s32 priority, s32 coreNo) { TypeInfo info; info.SetData(); NN_UTIL_PANIC_IF_FAILED(TryInitializeAndStartImpl(info, reinterpret_cast(f), ¶m, stack.GetStackBottom(), priority, coreNo, false)); } template inline void Thread::Start(void (*f)(const T*), const T& param, Stack& stack, s32 priority, s32 coreNo) { TypeInfo info; info.SetData(); NN_UTIL_PANIC_IF_FAILED(TryInitializeAndStartImpl(info, reinterpret_cast(f), ¶m, stack.GetStackBottom(), priority, coreNo, false)); } template inline void Thread::Start(void (*f)(), Stack& stack, s32 priority, s32 coreNo) { Start(NoParameterFunc, f, stack, priority, coreNo); } template inline nn::Result Thread::TryStart(void (*f)(T), U param, Stack& stack, s32 priority, s32 coreNo) { TypeInfo info; info.SetData(); Result result = TryInitializeAndStartImpl(info, reinterpret_cast(f), ¶m, stack.GetStackBottom(), priority, coreNo, false); if (result.GetSummary() == Result::SUMMARY_OUT_OF_RESOURCE) { return result; } NN_UTIL_PANIC_IF_FAILED(result); return result; } template inline nn::Result Thread::TryStart(void (*f)(), Stack& stack, s32 priority, s32 coreNo) { return TryStart(NoParameterFunc, f, stack, priority, coreNo); } template inline void Thread::StartUsingAutoStack(void (*f)(T), U param, size_t stackSize, s32 priority, s32 coreNo) { TypeInfo info; info.SetData(); NN_UTIL_PANIC_IF_FAILED(TryInitializeAndStartImplUsingAutoStack(info, reinterpret_cast(f), ¶m, stackSize, priority, coreNo)); } inline void Thread::StartUsingAutoStack(void (*f)(), size_t stackSize, s32 priority, s32 coreNo) { StartUsingAutoStack(NoParameterFunc, f, stackSize, priority, coreNo); } template inline nn::Result Thread::TryStartUsingAutoStack(void (*f)(T), U param, size_t stackSize, s32 priority, s32 coreNo) { TypeInfo info; info.SetData(); Result result = TryInitializeAndStartImplUsingAutoStack(info, reinterpret_cast(f), ¶m, stackSize, priority, coreNo); if (result.GetSummary() == Result::SUMMARY_OUT_OF_RESOURCE) { return result; } NN_UTIL_PANIC_IF_FAILED(result); return result; } inline nn::Result Thread::TryStartUsingAutoStack(void (*f)(), size_t stackSize, s32 priority, s32 coreNo) { return TryStartUsingAutoStack(NoParameterFunc, f, stackSize, priority, coreNo); } inline void Thread::FinalizeImpl() { if (!m_CanFinalize) { NN_TPANIC_("Thread is not Joined or Detached either."); } } inline void Thread::Finalize() { FinalizeImpl(); this->WaitObject::Finalize(); } inline Thread::~Thread() { FinalizeImpl(); } inline void Thread::Join() { this->WaitOne(); this->m_CanFinalize = true; } inline void Thread::Detach() { NN_TASSERT_(m_UsingAutoStack); this->m_CanFinalize = true; Finalize(); } inline void Thread::Sleep(nn::fnd::TimeSpan span) { SleepImpl(span); } inline void Thread::Yield() { nn::svc::SleepThread(0); } inline bit32 Thread::GetId() const { bit32 ret; NN_UTIL_PANIC_IF_FAILED(nn::svc::GetThreadId(&ret, GetHandle())); return ret; } inline bit32 Thread::GetCurrentId() { bit32 ret; NN_UTIL_PANIC_IF_FAILED(nn::svc::GetThreadId(&ret, PSEUDO_HANDLE_CURRENT_THREAD)); return ret; } inline s32 Thread::GetPriority() const { s32 ret; NN_UTIL_PANIC_IF_FAILED(nn::svc::GetThreadPriority(&ret, GetHandle())); return os::detail::ConvertSvcToLibraryPriority(ret); } inline s32 Thread::GetCurrentPriority() { s32 ret; NN_UTIL_PANIC_IF_FAILED(nn::svc::GetThreadPriority(&ret, PSEUDO_HANDLE_CURRENT_THREAD)); return os::detail::ConvertSvcToLibraryPriority(ret); } inline void Thread::ChangePriority(s32 priority) { NN_UTIL_PANIC_IF_FAILED(nn::svc::SetThreadPriority(GetHandle(), os::detail::ConvertLibraryToSvcPriority(priority))); } inline void Thread::ChangeCurrentPriority(s32 priority) { NN_UTIL_PANIC_IF_FAILED(nn::svc::SetThreadPriority(PSEUDO_HANDLE_CURRENT_THREAD, os::detail::ConvertLibraryToSvcPriority(priority))); } inline void Thread::GetAffinityMask(bit8* pAffinityMask, s32 numProcessor) const { NN_UTIL_PANIC_IF_FAILED(nn::svc::GetThreadAffinityMask(pAffinityMask, GetHandle(), numProcessor)); } inline void Thread::GetCurrentAffinityMask(bit8* pAffinityMask, s32 numProcessor) { NN_UTIL_PANIC_IF_FAILED(nn::svc::GetThreadAffinityMask(pAffinityMask, PSEUDO_HANDLE_CURRENT_THREAD, numProcessor)); } inline void Thread::GetDefaultAffinityMask(bit8* pAffinityMask, s32 numProcessor) { NN_UTIL_PANIC_IF_FAILED(nn::svc::GetProcessAffinityMask(pAffinityMask, PSEUDO_HANDLE_CURRENT_PROCESS, numProcessor)); } inline void Thread::ChangeAffinityMask(const bit8* pAffinityMask, s32 numProcessor) { NN_UTIL_PANIC_IF_FAILED(nn::svc::SetThreadAffinityMask(GetHandle(), pAffinityMask, numProcessor)); } inline void Thread::ChangeCurrentAffinityMask(const bit8* pAffinityMask, s32 numProcessor) { NN_UTIL_PANIC_IF_FAILED(nn::svc::SetThreadAffinityMask(PSEUDO_HANDLE_CURRENT_THREAD, pAffinityMask, numProcessor)); } inline void Thread::SetDefaultAffinityMask(const bit8* pAffinityMask, s32 numProcessor) { NN_UTIL_PANIC_IF_FAILED(nn::svc::SetProcessAffinityMask(PSEUDO_HANDLE_CURRENT_PROCESS, pAffinityMask, numProcessor)); } inline s32 Thread::GetIdealProcessor() const { s32 ret; NN_UTIL_PANIC_IF_FAILED(nn::svc::GetThreadIdealProcessor(&ret, GetHandle())); return ret; } inline s32 Thread::GetCurrentIdealProcessor() { s32 ret; NN_UTIL_PANIC_IF_FAILED(nn::svc::GetThreadIdealProcessor(&ret, PSEUDO_HANDLE_CURRENT_THREAD)); return ret; } inline s32 Thread::GetDefaultIdealProcessor() { s32 ret; NN_UTIL_PANIC_IF_FAILED(nn::svc::GetProcessIdealProcessor(&ret, PSEUDO_HANDLE_CURRENT_PROCESS)); return ret; } inline void Thread::ChangeIdealProcessor(s32 coreNo) { NN_UTIL_PANIC_IF_FAILED(nn::svc::SetThreadIdealProcessor(GetHandle(), coreNo)); } inline void Thread::ChangeCurrentIdealProcessor(s32 coreNo) { NN_UTIL_PANIC_IF_FAILED(nn::svc::SetThreadIdealProcessor(PSEUDO_HANDLE_CURRENT_THREAD, coreNo)); } inline void Thread::SetDefaultIdealProcessor(s32 coreNo) { NN_UTIL_PANIC_IF_FAILED(nn::svc::SetProcessIdealProcessor(PSEUDO_HANDLE_CURRENT_PROCESS, coreNo)); } inline s32 Thread::GetCurrentProcessorNumber() { return nn::svc::GetCurrentProcessorNumber(); } /*! @} */ /*! @} */ }} // namespace nn::os #endif // NN_SYSTEM_PROCESS #endif // __cplusplus // 以下、C 用宣言 #include /*! @addtogroup nn_os os @{ @defgroup nn_os_Thread_c Thread (C) @brief @ref nn::os::Thread の C インタフェースモジュールです。 @{ */ /*! @struct nnosThread @brief スレッドを表す C の構造体です。 @brief 対応するクラス @ref nn::os::Thread を参照してください。 */ NN_UTIL_DETAIL_CLIBIMPL_DEFINE_BUFFER_CLASS(nnosThread, nn::os::Thread, 8, u32); /*! @brief 対応する C++ 関数 @ref nn::os::Thread::Start を参照してください。 */ NN_EXTERN_C void nnosThreadInitializeAndStart(nnosThread* this_, void (*f)(uptr), uptr param, uptr stackBottom, s32 priority, s32 coreNo); /*! @brief 対応する C++ 関数 @ref nn::os::Thread::TryStart を参照してください。 */ NN_EXTERN_C bool nnosThreadTryInitializeAndStart(nnosThread* this_, void (*f)(uptr), uptr param, uptr stackBottom, s32 priority, s32 coreNo); /*! @brief 対応する C++ 関数 @ref nn::os::Thread::Finalize を参照してください。 */ NN_EXTERN_C void nnosThreadFinalize(nnosThread* this_); /*! @brief 対応する C++ 関数 @ref nn::os::Thread::Join を参照してください。 */ NN_EXTERN_C void nnosThreadJoin(nnosThread* this_); /*! @brief 対応する C++ 関数 @ref nn::os::Thread::Sleep を参照してください。 */ NN_EXTERN_C void nnosThreadSleep(s64 nanoSeconds); /*! @brief 対応する C++ 関数 @ref nn::os::Thread::Yield を参照してください。 */ NN_EXTERN_C void nnosThreadYield(void); /*! @brief 対応する C++ 関数 @ref nn::os::Thread::GetCurrentId を参照してください。 */ NN_EXTERN_C bit32 nnosThreadGetCurrentId(void); /*! @brief 対応する C++ 関数 @ref nn::os::Thread::GetPriority を参照してください。 */ NN_EXTERN_C s32 nnosThreadGetPriority(const nnosThread* this_); /*! @brief 対応する C++ 関数 @ref nn::os::Thread::GetCurrentPriority を参照してください。 */ NN_EXTERN_C s32 nnosThreadGetCurrentPriority(void); /*! @brief 対応する C++ 関数 @ref nn::os::Thread::ChangePriority を参照してください。 */ NN_EXTERN_C void nnosThreadChangePriority(nnosThread* this_, s32 priority); /*! @brief 対応する C++ 関数 @ref nn::os::Thread::ChangeCurrentPriority を参照してください。 */ NN_EXTERN_C void nnosThreadChangeCurrentPriority(s32 priority); // スレッド Affinity の設定・取得 /*! @brief 対応する C++ 関数 @ref nn::os::Thread::GetAffinityMask を参照してください。 */ NN_EXTERN_C void nnosThreadGetAffinityMask(const nnosThread* this_, bit8* pAffinityMask, s32 numProcessor); /*! @brief 対応する C++ 関数 @ref nn::os::Thread::GetCurrentAffinityMask を参照してください。 */ NN_EXTERN_C void nnosThreadGetCurrentAffinityMask(bit8* pAffinityMask, s32 numProcessor); /*! @brief 対応する C++ 関数 @ref nn::os::Thread::GetDefaultAffinityMask を参照してください。 */ NN_EXTERN_C void nnosThreadGetDefaultAffinityMask(bit8* pAffinityMask, s32 numProcessor); /*! @brief 対応する C++ 関数 @ref nn::os::Thread::ChangeAffinityMask を参照してください。 */ NN_EXTERN_C void nnosThreadChangeAffinityMask(nnosThread* this_, const bit8* pAffinityMask, s32 numProcessor); /*! @brief 対応する C++ 関数 @ref nn::os::Thread::ChangeCurrentAffinityMask を参照してください。 */ NN_EXTERN_C void nnosThreadChangeCurrentAffinityMask(const bit8* pAffinityMask, s32 numProcessor); /*! @brief 対応する C++ 関数 @ref nn::os::Thread::SetDefaultAffinityMask を参照してください。 */ NN_EXTERN_C void nnosThreadSetDefaultAffinityMask(const bit8* pAffinityMask, s32 numProcessor); // IdealProcessor の取得・設定 /*! @brief 対応する C++ 関数 @ref nn::os::Thread::GetIdealProcessor を参照してください。 */ NN_EXTERN_C s32 nnosThreadGetIdealProcessor(const nnosThread* this_); /*! @brief 対応する C++ 関数 @ref nn::os::Thread::GetCurrentIdealProcessor を参照してください。 */ NN_EXTERN_C s32 nnosThreadGetCurrentIdealProcessor(void); /*! @brief 対応する C++ 関数 @ref nn::os::Thread::GetDefaultIdealProcessor を参照してください。 */ NN_EXTERN_C s32 nnosThreadGetDefaultIdealProcessor(void); /*! @brief 対応する C++ 関数 @ref nn::os::Thread::ChangeIdealProcessor を参照してください。 */ NN_EXTERN_C void nnosThreadChangeIdealProcessor(nnosThread* this_, s32 coreNo); /*! @brief 対応する C++ 関数 @ref nn::os::Thread::ChangeCurrentIdealProcessor を参照してください。 */ NN_EXTERN_C void nnosThreadChangeCurrentIdealProcessor(s32 coreNo); /*! @brief 対応する C++ 関数 @ref nn::os::Thread::SetDefaultIdealProcessor を参照してください。 */ NN_EXTERN_C void nnosThreadSetDefaultIdealProcessor(s32 coreNo); // カレントスレッドの動作しているプロセッサ番号の取得 /*! @brief 対応する C++ 関数 @ref nn::os::Thread::GetCurrentProcessorNumber を参照してください。 */ NN_EXTERN_C s32 nnosThreadGetCurrentProcessorNumber(void); /*! @brief 対応する C++ 関数 @ref nn::os::Thread::GetID を参照してください。 */ NN_EXTERN_C bit32 nnosThreadGetId(nnosThread* this_); /*! @brief 対応する C++ 関数 @ref nn::os::Thread::IsAlive を参照してください。 */ NN_EXTERN_C bool nnosThreadIsAlive(nnosThread* this_); /*! @brief 対応する C++ 関数 @ref nn::os::Thread::GetMainThread を参照してください。 */ NN_EXTERN_C nnosThread* nnosThreadGetMainThread(void); /*! @} @} */ /* NN_OS_THREAD_H_ */ #endif