1 /*---------------------------------------------------------------------------*
2 Project: Horizon
3 File: os_ThreadPool.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: 24261 $
14 *---------------------------------------------------------------------------*/
15
16 /*! @file
17 @brief ThreadPool に関する API の宣言
18
19 このファイル内の記述は将来的に大幅に変更される可能性があります。
20 直接使わないでください。
21
22 @deprecated
23
24 :include nn/os.h
25 */
26
27 #ifndef NN_OS_OS_THREADPOOL_H_
28 #define NN_OS_OS_THREADPOOL_H_
29
30 #include <nn/os/os_Synchronization.h>
31 #include <nn/os/os_StackMemoryBlock.h>
32 #include <nn/os/os_Thread.h>
33 #include <nn/os/os_Event.h>
34 #include <nn/os/os_LightEvent.h>
35 #include <nn/os/os_CriticalSection.h>
36 #include <nn/fnd/fnd_Queue.h>
37 #include <nn/util/util_NonCopyable.h>
38 #include <nn/os/os_Task.h>
39
40 #ifdef __cplusplus
41
42 namespace nn { namespace os {
43
44 /*!
45 @brief スレッドプールクラスです。
46
47 :private
48 */
49 class ThreadPool : public IWaitTaskInvoker, private nn::util::NonCopyable<ThreadPool>
50 {
51 public:
52
53 // 初期化時の第1引数に与えるバッファのサイズ。
54 // このバッファはユーザ側で確保する必要がある。
55 /*!
56 @brief スレッドプールで使用するバッファのサイズを計算します。
57
58 @param[in] numMaxWaitObjects 同期オブジェクトの最大数を指定します。
59 @param[in] numWorkerThreads ワーカスレッドの数を指定します。
60
61 @return スレッドプールで使用するバッファのサイズを返します。
62 */
63 static size_t GetWorkBufferSize(size_t numMaxWaitObjects, size_t numWorkerThreads);
64
65 /*!
66 @brief コンストラクタ
67
68 スレッドプールの初期化を行いません。
69 */
70 ThreadPool();
71 /*!
72 @brief コンストラクタ
73
74 @param[in] workBuffer スレッドプールで使用するバッファを指定します。バッファサイズは GetWorkBufferSize() で計算します。
75 @param[in] numMaxWaitObjects 同期オブジェクトの最大数を指定します。
76 @param[in] numWorkerThreads ワーカスレッドの数を指定します。
77 @param[in] workerStackBottoms ワーカスレッドのスタックポインタの開始アドレスを指定します。
78 @param[in] workerPriority ワーカスレッドの優先度を指定します。
79 */
80 ThreadPool(void* workBuffer, size_t numMaxWaitObjects, size_t numWorkerThreads, uptr workerStackBottoms[], s32 workerPriority = DEFAULT_THREAD_PRIORITY);
81
82 #if NN_PLATFORM_HAS_MMU
83 /*!
84 @brief コンストラクタ
85
86 @param[in] workBuffer スレッドプールで使用するバッファを指定します。バッファサイズは GetWorkBufferSize() で計算します。
87 @param[in] numMaxWaitObjects 同期オブジェクトの最大数を指定します。
88 @param[in] numWorkerThreads ワーカスレッドの数を指定します。
89 @param[in] workerStacks ワーカスレッドのスタックポインタを指定します。
90 @param[in] workerPriority ワーカスレッドの優先度を指定します。
91 */
92 ThreadPool(void* workBuffer, size_t numMaxWaitObjects, size_t numWorkerThreads, nn::os::StackMemoryBlock workerStacks[], s32 workerPriority = DEFAULT_THREAD_PRIORITY);
93 #endif // if NN_PLATFORM_HAS_MMU
94
95 /*!
96 @brief デストラクタ
97
98 内部で Finalize() を呼びます。
99 */
~ThreadPool()100 ~ThreadPool() { Finalize(); }
101
102 /*!
103 @brief スレッドプールの初期化を行います。
104
105 @param[in] workBuffer スレッドプールで使用するバッファを指定します。バッファサイズは GetWorkBufferSize() で計算します。
106 @param[in] numMaxWaitObjects 同期オブジェクトの最大数を指定します。
107 @param[in] numWorkerThreads ワーカスレッドの数を指定します。
108 @param[in] workerStackBottoms ワーカスレッドのスタックポインタの開始アドレスを指定します。
109 @param[in] workerPriority ワーカスレッドの優先度を指定します。
110
111 @return 無し。
112 */
113 void Initialize(void* workBuffer, size_t numMaxWaitObjects, size_t numWorkerThreads, uptr workerStackBottoms[], s32 workerPriority = DEFAULT_THREAD_PRIORITY);
114 #if NN_PLATFORM_HAS_MMU
115 /*!
116 @brief スレッドプールの初期化を行います。
117
118 @param[in] workBuffer スレッドプールで使用するバッファを指定します。バッファサイズは GetWorkBufferSize() で計算します。
119 @param[in] numMaxWaitObjects 同期オブジェクトの最大数を指定します。
120 @param[in] numWorkerThreads ワーカスレッドの数を指定します。
121 @param[in] workerStacks ワーカスレッドのスタックを指定します。
122 @param[in] workerPriority ワーカスレッドの優先度を指定します。
123
124 @return 無し。
125 */
126 void Initialize(void* workBuffer, size_t numMaxWaitObjects, size_t numWorkerThreads, nn::os::StackMemoryBlock workerStacks[], s32 workerPriority = DEFAULT_THREAD_PRIORITY);
127 #endif // if NN_PLATFORM_HAS_MMU
128
129 // TODO: TryInitialize 必要? 巻き戻しが非常に大変なため、実装の優先度は低。
130
131 /*!
132 @brief スレッドプールを破棄します。
133
134 @return 無し。
135 */
136 void Finalize();
137
138 /*!
139 @brief プールスレッドで処理するタスクを追加します。
140
141 空いているプールスレッドがあれば、プールスレッドで即座に task->Invoke() を実行します。
142 空いているプールスレッドがなければ、タスクをキューに入れプールスレッドが空くのを待ちます。
143
144 @param[in] task プールスレッドで処理するタスクを指定します。
145
146 @return 無し。
147 */
AddTask(QueueableTask * task)148 virtual void AddTask(QueueableTask* task) { AddToExecuteQueue(task); }
149
150 /*!
151 @brief 同期して処理を開始するタスクを追加します。
152
153 同期スレッドに空きがあれば、タスクを同期タスクに登録し task->GetWaitObject() を待った後、
154 プールスレッドで task->Invoke() を実行します。
155 同期スレッドに空きがなければ、タスクをキューに入れ同期スレッドが空くのを待ちます。
156 タスクがキューに入っている間は同期待ちは行われません。
157
158 @param[in] task 同期スレッドで処理するタスクを指定します。
159
160 @return 無し。
161 */
AddWaitTask(QueueableWaitTask * task)162 virtual void AddWaitTask(QueueableWaitTask* task) { AddToWaitQueue(task); }
163
164 private:
165
166 size_t m_NumMaxWaitObjects;
167 size_t m_NumThreads;
168
169 uptr m_Buffer;
170 Thread* GetThreads() const;
171 nn::Handle* GetWaitHandleBuffer() const;
172 QueueableWaitTask** GetWaitTaskBuffer() const;
173
174 s32 m_WaitingCount;
175
176 bool m_Finalizing;
177 bit8 m_Padding[3];
178
179 static const size_t WAIT_THREAD_STACK_SIZE = 392;
180 StackBuffer<WAIT_THREAD_STACK_SIZE> m_WaitThreadStack;
181
182 Thread m_WaitThread;
183 nn::fnd::IntrusiveQueue<QueueableTask> m_WaitQueue;
184 nn::os::CriticalSection m_WaitLock;
185 nn::os::Event m_WaitEvent;
186 void AddToWaitQueue(QueueableWaitTask*);
187
188 nn::fnd::IntrusiveQueue<QueueableTask> m_ExecuteQueue;
189 nn::os::CriticalSection m_ExecuteLock;
190 nn::os::LightEvent m_ExecuteEvent;
191 void AddToExecuteQueue(QueueableTask*);
192
193
194 static void WaitThreadFunc(ThreadPool*);
195 void WaitThreadFunc();
196 static void ExecuteThreadFunc(ThreadPool*);
197 void ExecuteThreadFunc();
198
199 void InitializeCommon(size_t numMaxWaitObjects, size_t numWorkerThreads, void* workBuffer);
200 void StartWaitThread();
201 void StartExecuteThread(size_t i, uptr stackBottom, s32 priority);
202
203 };
204
ThreadPool()205 inline ThreadPool::ThreadPool() : m_Buffer(0) {}
206
ThreadPool(void * workBuffer,size_t numMaxWaitObjects,size_t numWorkerThreads,uptr workerStackBottoms[],s32 workerPriority)207 inline ThreadPool::ThreadPool(void* workBuffer, size_t numMaxWaitObjects, size_t numWorkerThreads, uptr workerStackBottoms[], s32 workerPriority)
208 : m_Buffer(0)
209 {
210 Initialize(workBuffer, numMaxWaitObjects, numWorkerThreads, workerStackBottoms, workerPriority);
211 }
212
213 #if NN_PLATFORM_HAS_MMU
ThreadPool(void * workBuffer,size_t numMaxWaitObjects,size_t numWorkerThreads,nn::os::StackMemoryBlock workerStacks[],s32 workerPriority)214 inline ThreadPool::ThreadPool(void* workBuffer, size_t numMaxWaitObjects, size_t numWorkerThreads, nn::os::StackMemoryBlock workerStacks[], s32 workerPriority)
215 : m_Buffer(0)
216 {
217 Initialize(workBuffer, numMaxWaitObjects, numWorkerThreads, workerStacks, workerPriority);
218 }
219 #endif // if NN_PLATFORM_HAS_MMU
220
221 }}
222
223 #endif // __cplusplus
224
225 // 以下、C 用宣言
226
227
228 #ifdef __cplusplus
229
230 namespace nn { namespace os {
231
232 namespace detail
233 {
234 class ThreadPoolTaskForC : public QueueableTask
235 {
236 public:
ThreadPoolTaskForC(void (* f)(uptr),uptr param)237 ThreadPoolTaskForC(void (*f)(uptr), uptr param) : m_F(f), m_Param(param) {}
Invoke()238 virtual void Invoke() { m_F(m_Param); }
239 private:
240 void (*m_F)(uptr);
241 uptr m_Param;
242 };
243
244 class ThreadPoolWaitTaskForC : public QueueableWaitTask
245 {
246 public:
ThreadPoolWaitTaskForC(nnosWaitObject * waitObject,void (* f)(uptr),uptr param)247 ThreadPoolWaitTaskForC(nnosWaitObject* waitObject, void (*f)(uptr), uptr param) : m_WaitObject(waitObject), m_F(f), m_Param(param) {}
GetWaitObject()248 virtual nn::os::WaitObject* GetWaitObject() { return reinterpret_cast<nn::os::WaitObject*&>(m_WaitObject); }
Invoke()249 virtual void Invoke() { m_F(m_Param); }
250 private:
251 nnosWaitObject* m_WaitObject;
252 void (*m_F)(uptr);
253 uptr m_Param;
254 };
255 }
256
257 }}
258
259 #endif
260
261 #include <nn/util/detail/util_CLibImpl.h>
262
263 /*!
264 @addtogroup nn_os os
265 @{
266
267 @defgroup nn_os_ThreadPool_c ThreadPool (C)
268
269 @brief @ref nn::os::ThreadPool の C インタフェースモジュールです。
270
271 :private
272
273 @{
274 */
275
276 /*!
277 :private
278
279 @struct nnosThreadPoolTask
280 @brief スレッドプールで処理するタスクを表す C の構造体です。
281
282 @brief 対応するクラス @ref nn::os::QueueableTask を参照してください。
283 */
284 NN_UTIL_DETAIL_CLIBIMPL_DEFINE_BUFFER_CLASS(nnosThreadPoolTask, nn::os::detail::ThreadPoolTaskForC, 16, u32);
285
286 /*!
287 @brief タスクを初期化します。
288 */
289 NN_EXTERN_C void nnosThreadPoolTaskInitialize(nnosThreadPoolTask* this_, void (*f)(uptr), uptr param);
290
291 /*!
292 @brief タスクを破棄します。
293 */
294
295 NN_EXTERN_C void nnosThreadPoolTaskFinalize(nnosThreadPoolTask* this_);
296
297
298 /*!
299 :private
300
301 @struct nnosThreadPoolWaitTask
302 @brief スレッドプールで処理する同期タスクを表す C の構造体です。
303
304 @brief 対応するクラス @ref nn::os::QueueableWaitTask を参照してください。
305 */
306 NN_UTIL_DETAIL_CLIBIMPL_DEFINE_BUFFER_CLASS(nnosThreadPoolWaitTask, nn::os::detail::ThreadPoolWaitTaskForC, 20, u32);
307
308 /*!
309 @brief 同期タスクを初期化します。
310 */
311 NN_EXTERN_C void nnosThreadPoolWaitTaskInitialize(nnosThreadPoolWaitTask* this_, nnosWaitObject* waitObject, void (*f)(uptr), uptr param);
312
313 /*!
314 @brief 同期タスクを破棄します。
315 */
316 NN_EXTERN_C void nnosThreadPoolWaitTaskFinalize(nnosThreadPoolWaitTask* this_);
317
318
319 /*!
320 :private
321
322 @struct nnosThreadPool
323 @brief スレッドプールを表す C の構造体です。
324
325 @brief 対応するクラス @ref nn::os::ThreadPool を参照してください。
326 */
327 NN_UTIL_DETAIL_CLIBIMPL_DEFINE_BUFFER_CLASS(nnosThreadPool, nn::os::ThreadPool, 472, bit64);
328
329 /*!
330 @brief 対応する C++ 関数 @ref nn::os::ThreadPool::Initialize を参照してください。
331 */
332 NN_EXTERN_C void nnosThreadPoolInitialize(nnosThreadPool* this_, void* workBuffer, size_t numMaxWaitObjects, size_t numWorkerThreads, uptr workerStackBottoms[], s32 workerPriority);
333 #if NN_PLATFORM_HAS_MMU
334 NN_EXTERN_C void nnosThreadPoolInitializeWithStackMemoryBlock(nnosThreadPool* this_, void* workBuffer, size_t numMaxWaitObjects, size_t numWorkerThreads, nnosStackMemoryBlock workerStacks[], s32 workerPriority);
335 #endif // if NN_PLATFORM_HAS_MMU
336
337 /*!
338 @brief 対応する C++ 関数 @ref nn::os::ThreadPool::Finalize を参照してください。
339 */
340 NN_EXTERN_C void nnosThreadPoolFinalize(nnosThreadPool* this_);
341
342 /*!
343 @brief 対応する C++ 関数 @ref nn::os::ThreadPool::AddWaitTask を参照してください。
344 */
345 NN_EXTERN_C void nnosThreadPoolAddWaitTask(nnosThreadPool* this_, nnosThreadPoolWaitTask* task);
346
347 /*!
348 @brief 対応する C++ 関数 @ref nn::os::ThreadPool::AddTask を参照してください。
349 */
350 NN_EXTERN_C void nnosThreadPoolAddTask(nnosThreadPool* this_, nnosThreadPoolTask* task);
351
352 /*!
353 @brief 対応する C++ 関数 @ref nn::os::ThreadPool::GetWorkBufferSize を参照してください。
354 */
355 NN_EXTERN_C size_t nnosThreadPoolGetWorkBufferSize(size_t numMaxWaitObjects, size_t numWorkerThreads);
356
357 /*!
358 @}
359
360 @}
361 */
362
363 #endif // NN_OS_OS_THREADPOOL_H_
364