/*---------------------------------------------------------------------------* Project: Horizon File: os_ThreadPool.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: 24261 $ *---------------------------------------------------------------------------*/ /*! @file @brief ThreadPool に関する API の宣言 このファイル内の記述は将来的に大幅に変更される可能性があります。 直接使わないでください。 @deprecated :include nn/os.h */ #ifndef NN_OS_OS_THREADPOOL_H_ #define NN_OS_OS_THREADPOOL_H_ #include #include #include #include #include #include #include #include #include #ifdef __cplusplus namespace nn { namespace os { /*! @brief スレッドプールクラスです。 :private */ class ThreadPool : public IWaitTaskInvoker, private nn::util::NonCopyable { public: // 初期化時の第1引数に与えるバッファのサイズ。 // このバッファはユーザ側で確保する必要がある。 /*! @brief スレッドプールで使用するバッファのサイズを計算します。 @param[in] numMaxWaitObjects 同期オブジェクトの最大数を指定します。 @param[in] numWorkerThreads ワーカスレッドの数を指定します。 @return スレッドプールで使用するバッファのサイズを返します。 */ static size_t GetWorkBufferSize(size_t numMaxWaitObjects, size_t numWorkerThreads); /*! @brief コンストラクタ スレッドプールの初期化を行いません。 */ ThreadPool(); /*! @brief コンストラクタ @param[in] workBuffer スレッドプールで使用するバッファを指定します。バッファサイズは GetWorkBufferSize() で計算します。 @param[in] numMaxWaitObjects 同期オブジェクトの最大数を指定します。 @param[in] numWorkerThreads ワーカスレッドの数を指定します。 @param[in] workerStackBottoms ワーカスレッドのスタックポインタの開始アドレスを指定します。 @param[in] workerPriority ワーカスレッドの優先度を指定します。 */ ThreadPool(void* workBuffer, size_t numMaxWaitObjects, size_t numWorkerThreads, uptr workerStackBottoms[], s32 workerPriority = DEFAULT_THREAD_PRIORITY); #if NN_PLATFORM_HAS_MMU /*! @brief コンストラクタ @param[in] workBuffer スレッドプールで使用するバッファを指定します。バッファサイズは GetWorkBufferSize() で計算します。 @param[in] numMaxWaitObjects 同期オブジェクトの最大数を指定します。 @param[in] numWorkerThreads ワーカスレッドの数を指定します。 @param[in] workerStacks ワーカスレッドのスタックポインタを指定します。 @param[in] workerPriority ワーカスレッドの優先度を指定します。 */ ThreadPool(void* workBuffer, size_t numMaxWaitObjects, size_t numWorkerThreads, nn::os::StackMemoryBlock workerStacks[], s32 workerPriority = DEFAULT_THREAD_PRIORITY); #endif // if NN_PLATFORM_HAS_MMU /*! @brief デストラクタ 内部で Finalize() を呼びます。 */ ~ThreadPool() { Finalize(); } /*! @brief スレッドプールの初期化を行います。 @param[in] workBuffer スレッドプールで使用するバッファを指定します。バッファサイズは GetWorkBufferSize() で計算します。 @param[in] numMaxWaitObjects 同期オブジェクトの最大数を指定します。 @param[in] numWorkerThreads ワーカスレッドの数を指定します。 @param[in] workerStackBottoms ワーカスレッドのスタックポインタの開始アドレスを指定します。 @param[in] workerPriority ワーカスレッドの優先度を指定します。 @return 無し。 */ void Initialize(void* workBuffer, size_t numMaxWaitObjects, size_t numWorkerThreads, uptr workerStackBottoms[], s32 workerPriority = DEFAULT_THREAD_PRIORITY); #if NN_PLATFORM_HAS_MMU /*! @brief スレッドプールの初期化を行います。 @param[in] workBuffer スレッドプールで使用するバッファを指定します。バッファサイズは GetWorkBufferSize() で計算します。 @param[in] numMaxWaitObjects 同期オブジェクトの最大数を指定します。 @param[in] numWorkerThreads ワーカスレッドの数を指定します。 @param[in] workerStacks ワーカスレッドのスタックを指定します。 @param[in] workerPriority ワーカスレッドの優先度を指定します。 @return 無し。 */ void Initialize(void* workBuffer, size_t numMaxWaitObjects, size_t numWorkerThreads, nn::os::StackMemoryBlock workerStacks[], s32 workerPriority = DEFAULT_THREAD_PRIORITY); #endif // if NN_PLATFORM_HAS_MMU // TODO: TryInitialize 必要? 巻き戻しが非常に大変なため、実装の優先度は低。 /*! @brief スレッドプールを破棄します。 @return 無し。 */ void Finalize(); /*! @brief プールスレッドで処理するタスクを追加します。 空いているプールスレッドがあれば、プールスレッドで即座に task->Invoke() を実行します。 空いているプールスレッドがなければ、タスクをキューに入れプールスレッドが空くのを待ちます。 @param[in] task プールスレッドで処理するタスクを指定します。 @return 無し。 */ virtual void AddTask(QueueableTask* task) { AddToExecuteQueue(task); } /*! @brief 同期して処理を開始するタスクを追加します。 同期スレッドに空きがあれば、タスクを同期タスクに登録し task->GetWaitObject() を待った後、 プールスレッドで task->Invoke() を実行します。 同期スレッドに空きがなければ、タスクをキューに入れ同期スレッドが空くのを待ちます。 タスクがキューに入っている間は同期待ちは行われません。 @param[in] task 同期スレッドで処理するタスクを指定します。 @return 無し。 */ virtual void AddWaitTask(QueueableWaitTask* task) { AddToWaitQueue(task); } private: size_t m_NumMaxWaitObjects; size_t m_NumThreads; uptr m_Buffer; Thread* GetThreads() const; nn::Handle* GetWaitHandleBuffer() const; QueueableWaitTask** GetWaitTaskBuffer() const; s32 m_WaitingCount; bool m_Finalizing; bit8 m_Padding[3]; static const size_t WAIT_THREAD_STACK_SIZE = 392; StackBuffer m_WaitThreadStack; Thread m_WaitThread; nn::fnd::IntrusiveQueue m_WaitQueue; nn::os::CriticalSection m_WaitLock; nn::os::Event m_WaitEvent; void AddToWaitQueue(QueueableWaitTask*); nn::fnd::IntrusiveQueue m_ExecuteQueue; nn::os::CriticalSection m_ExecuteLock; nn::os::LightEvent m_ExecuteEvent; void AddToExecuteQueue(QueueableTask*); static void WaitThreadFunc(ThreadPool*); void WaitThreadFunc(); static void ExecuteThreadFunc(ThreadPool*); void ExecuteThreadFunc(); void InitializeCommon(size_t numMaxWaitObjects, size_t numWorkerThreads, void* workBuffer); void StartWaitThread(); void StartExecuteThread(size_t i, uptr stackBottom, s32 priority); }; inline ThreadPool::ThreadPool() : m_Buffer(0) {} inline ThreadPool::ThreadPool(void* workBuffer, size_t numMaxWaitObjects, size_t numWorkerThreads, uptr workerStackBottoms[], s32 workerPriority) : m_Buffer(0) { Initialize(workBuffer, numMaxWaitObjects, numWorkerThreads, workerStackBottoms, workerPriority); } #if NN_PLATFORM_HAS_MMU inline ThreadPool::ThreadPool(void* workBuffer, size_t numMaxWaitObjects, size_t numWorkerThreads, nn::os::StackMemoryBlock workerStacks[], s32 workerPriority) : m_Buffer(0) { Initialize(workBuffer, numMaxWaitObjects, numWorkerThreads, workerStacks, workerPriority); } #endif // if NN_PLATFORM_HAS_MMU }} #endif // __cplusplus // 以下、C 用宣言 #ifdef __cplusplus namespace nn { namespace os { namespace detail { class ThreadPoolTaskForC : public QueueableTask { public: ThreadPoolTaskForC(void (*f)(uptr), uptr param) : m_F(f), m_Param(param) {} virtual void Invoke() { m_F(m_Param); } private: void (*m_F)(uptr); uptr m_Param; }; class ThreadPoolWaitTaskForC : public QueueableWaitTask { public: ThreadPoolWaitTaskForC(nnosWaitObject* waitObject, void (*f)(uptr), uptr param) : m_WaitObject(waitObject), m_F(f), m_Param(param) {} virtual nn::os::WaitObject* GetWaitObject() { return reinterpret_cast(m_WaitObject); } virtual void Invoke() { m_F(m_Param); } private: nnosWaitObject* m_WaitObject; void (*m_F)(uptr); uptr m_Param; }; } }} #endif #include /*! @addtogroup nn_os os @{ @defgroup nn_os_ThreadPool_c ThreadPool (C) @brief @ref nn::os::ThreadPool の C インタフェースモジュールです。 :private @{ */ /*! :private @struct nnosThreadPoolTask @brief スレッドプールで処理するタスクを表す C の構造体です。 @brief 対応するクラス @ref nn::os::QueueableTask を参照してください。 */ NN_UTIL_DETAIL_CLIBIMPL_DEFINE_BUFFER_CLASS(nnosThreadPoolTask, nn::os::detail::ThreadPoolTaskForC, 16, u32); /*! @brief タスクを初期化します。 */ NN_EXTERN_C void nnosThreadPoolTaskInitialize(nnosThreadPoolTask* this_, void (*f)(uptr), uptr param); /*! @brief タスクを破棄します。 */ NN_EXTERN_C void nnosThreadPoolTaskFinalize(nnosThreadPoolTask* this_); /*! :private @struct nnosThreadPoolWaitTask @brief スレッドプールで処理する同期タスクを表す C の構造体です。 @brief 対応するクラス @ref nn::os::QueueableWaitTask を参照してください。 */ NN_UTIL_DETAIL_CLIBIMPL_DEFINE_BUFFER_CLASS(nnosThreadPoolWaitTask, nn::os::detail::ThreadPoolWaitTaskForC, 20, u32); /*! @brief 同期タスクを初期化します。 */ NN_EXTERN_C void nnosThreadPoolWaitTaskInitialize(nnosThreadPoolWaitTask* this_, nnosWaitObject* waitObject, void (*f)(uptr), uptr param); /*! @brief 同期タスクを破棄します。 */ NN_EXTERN_C void nnosThreadPoolWaitTaskFinalize(nnosThreadPoolWaitTask* this_); /*! :private @struct nnosThreadPool @brief スレッドプールを表す C の構造体です。 @brief 対応するクラス @ref nn::os::ThreadPool を参照してください。 */ NN_UTIL_DETAIL_CLIBIMPL_DEFINE_BUFFER_CLASS(nnosThreadPool, nn::os::ThreadPool, 472, bit64); /*! @brief 対応する C++ 関数 @ref nn::os::ThreadPool::Initialize を参照してください。 */ NN_EXTERN_C void nnosThreadPoolInitialize(nnosThreadPool* this_, void* workBuffer, size_t numMaxWaitObjects, size_t numWorkerThreads, uptr workerStackBottoms[], s32 workerPriority); #if NN_PLATFORM_HAS_MMU NN_EXTERN_C void nnosThreadPoolInitializeWithStackMemoryBlock(nnosThreadPool* this_, void* workBuffer, size_t numMaxWaitObjects, size_t numWorkerThreads, nnosStackMemoryBlock workerStacks[], s32 workerPriority); #endif // if NN_PLATFORM_HAS_MMU /*! @brief 対応する C++ 関数 @ref nn::os::ThreadPool::Finalize を参照してください。 */ NN_EXTERN_C void nnosThreadPoolFinalize(nnosThreadPool* this_); /*! @brief 対応する C++ 関数 @ref nn::os::ThreadPool::AddWaitTask を参照してください。 */ NN_EXTERN_C void nnosThreadPoolAddWaitTask(nnosThreadPool* this_, nnosThreadPoolWaitTask* task); /*! @brief 対応する C++ 関数 @ref nn::os::ThreadPool::AddTask を参照してください。 */ NN_EXTERN_C void nnosThreadPoolAddTask(nnosThreadPool* this_, nnosThreadPoolTask* task); /*! @brief 対応する C++ 関数 @ref nn::os::ThreadPool::GetWorkBufferSize を参照してください。 */ NN_EXTERN_C size_t nnosThreadPoolGetWorkBufferSize(size_t numMaxWaitObjects, size_t numWorkerThreads); /*! @} @} */ #endif // NN_OS_OS_THREADPOOL_H_