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: 30270 $
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 virtual ~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 class SingleThreadPool : public ITaskInvoker, private nn::util::NonCopyable<SingleThreadPool>
223 {
224 public:
SingleThreadPool()225 SingleThreadPool() : m_Finalizing(false) {}
~SingleThreadPool()226 virtual ~SingleThreadPool() { Finalize(); }
227 void Initialize(uptr workerThreadStackBottom, s32 workerPriority = DEFAULT_THREAD_PRIORITY);
228 void Finalize();
229
AddTask(QueueableTask * task)230 virtual void AddTask(QueueableTask* task) { AddToExecuteQueue(task); }
231
232 static void ExecuteThreadFunc(SingleThreadPool* pInstance);
233 void ExecuteThreadFunc();
234
235 private:
236 nn::os::Thread m_WorkerThread;
237 nn::fnd::IntrusiveQueue<QueueableTask> m_ExecuteQueue;
238 nn::os::CriticalSection m_ExecuteLock;
239 nn::os::LightEvent m_ExecuteEvent;
240
241 bool m_Finalizing;
242 NN_PADDING3;
243
244 void AddToExecuteQueue(QueueableTask*);
245 };
246
247
248 }}
249
250 #endif // __cplusplus
251
252 // 以下、C 用宣言
253
254
255 #ifdef __cplusplus
256
257 namespace nn { namespace os {
258
259 namespace detail
260 {
261 class ThreadPoolTaskForC : public QueueableTask
262 {
263 public:
ThreadPoolTaskForC(void (* f)(uptr),uptr param)264 ThreadPoolTaskForC(void (*f)(uptr), uptr param) : m_F(f), m_Param(param) {}
Invoke()265 virtual void Invoke() { m_F(m_Param); }
266 private:
267 void (*m_F)(uptr);
268 uptr m_Param;
269 };
270
271 class ThreadPoolWaitTaskForC : public QueueableWaitTask
272 {
273 public:
ThreadPoolWaitTaskForC(nnosWaitObject * waitObject,void (* f)(uptr),uptr param)274 ThreadPoolWaitTaskForC(nnosWaitObject* waitObject, void (*f)(uptr), uptr param) : m_WaitObject(waitObject), m_F(f), m_Param(param) {}
GetWaitObject()275 virtual nn::os::WaitObject* GetWaitObject() { return reinterpret_cast<nn::os::WaitObject*&>(m_WaitObject); }
Invoke()276 virtual void Invoke() { m_F(m_Param); }
277 private:
278 nnosWaitObject* m_WaitObject;
279 void (*m_F)(uptr);
280 uptr m_Param;
281 };
282 }
283
284 }}
285
286 #endif
287
288 #include <nn/util/detail/util_CLibImpl.h>
289
290 /*!
291 @addtogroup nn_os os
292 @{
293
294 @defgroup nn_os_ThreadPool_c ThreadPool (C)
295
296 @brief @ref nn::os::ThreadPool の C インタフェースモジュールです。
297
298 :private
299
300 @{
301 */
302
303 /*!
304 :private
305
306 @struct nnosThreadPoolTask
307 @brief スレッドプールで処理するタスクを表す C の構造体です。
308
309 @brief 対応するクラス @ref nn::os::QueueableTask を参照してください。
310 */
311 NN_UTIL_DETAIL_CLIBIMPL_DEFINE_BUFFER_CLASS(nnosThreadPoolTask, nn::os::detail::ThreadPoolTaskForC, 16, u32);
312
313 /*!
314 @brief タスクを初期化します。
315 */
316 NN_EXTERN_C void nnosThreadPoolTaskInitialize(nnosThreadPoolTask* this_, void (*f)(uptr), uptr param);
317
318 /*!
319 @brief タスクを破棄します。
320 */
321
322 NN_EXTERN_C void nnosThreadPoolTaskFinalize(nnosThreadPoolTask* this_);
323
324
325 /*!
326 :private
327
328 @struct nnosThreadPoolWaitTask
329 @brief スレッドプールで処理する同期タスクを表す C の構造体です。
330
331 @brief 対応するクラス @ref nn::os::QueueableWaitTask を参照してください。
332 */
333 NN_UTIL_DETAIL_CLIBIMPL_DEFINE_BUFFER_CLASS(nnosThreadPoolWaitTask, nn::os::detail::ThreadPoolWaitTaskForC, 20, u32);
334
335 /*!
336 @brief 同期タスクを初期化します。
337 */
338 NN_EXTERN_C void nnosThreadPoolWaitTaskInitialize(nnosThreadPoolWaitTask* this_, nnosWaitObject* waitObject, void (*f)(uptr), uptr param);
339
340 /*!
341 @brief 同期タスクを破棄します。
342 */
343 NN_EXTERN_C void nnosThreadPoolWaitTaskFinalize(nnosThreadPoolWaitTask* this_);
344
345
346 /*!
347 :private
348
349 @struct nnosThreadPool
350 @brief スレッドプールを表す C の構造体です。
351
352 @brief 対応するクラス @ref nn::os::ThreadPool を参照してください。
353 */
354 NN_UTIL_DETAIL_CLIBIMPL_DEFINE_BUFFER_CLASS(nnosThreadPool, nn::os::ThreadPool, 472, bit64);
355
356 /*!
357 @brief 対応する C++ 関数 @ref nn::os::ThreadPool::Initialize を参照してください。
358 */
359 NN_EXTERN_C void nnosThreadPoolInitialize(nnosThreadPool* this_, void* workBuffer, size_t numMaxWaitObjects, size_t numWorkerThreads, uptr workerStackBottoms[], s32 workerPriority);
360 #if NN_PLATFORM_HAS_MMU
361 NN_EXTERN_C void nnosThreadPoolInitializeWithStackMemoryBlock(nnosThreadPool* this_, void* workBuffer, size_t numMaxWaitObjects, size_t numWorkerThreads, nnosStackMemoryBlock workerStacks[], s32 workerPriority);
362 #endif // if NN_PLATFORM_HAS_MMU
363
364 /*!
365 @brief 対応する C++ 関数 @ref nn::os::ThreadPool::Finalize を参照してください。
366 */
367 NN_EXTERN_C void nnosThreadPoolFinalize(nnosThreadPool* this_);
368
369 /*!
370 @brief 対応する C++ 関数 @ref nn::os::ThreadPool::AddWaitTask を参照してください。
371 */
372 NN_EXTERN_C void nnosThreadPoolAddWaitTask(nnosThreadPool* this_, nnosThreadPoolWaitTask* task);
373
374 /*!
375 @brief 対応する C++ 関数 @ref nn::os::ThreadPool::AddTask を参照してください。
376 */
377 NN_EXTERN_C void nnosThreadPoolAddTask(nnosThreadPool* this_, nnosThreadPoolTask* task);
378
379 /*!
380 @brief 対応する C++ 関数 @ref nn::os::ThreadPool::GetWorkBufferSize を参照してください。
381 */
382 NN_EXTERN_C size_t nnosThreadPoolGetWorkBufferSize(size_t numMaxWaitObjects, size_t numWorkerThreads);
383
384 /*!
385 @}
386
387 @}
388 */
389
390 #endif // NN_OS_OS_THREADPOOL_H_
391