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: 34337 $
14 *---------------------------------------------------------------------------*/
15
16 /* Please see man pages for details
17
18
19
20
21
22
23
24
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 /* Please see man pages for details
45
46
47
48 */
49 class ThreadPool : public IWaitTaskInvoker, private nn::util::NonCopyable<ThreadPool>
50 {
51 public:
52
53 // Size of buffer to pass to the first argument at initialization.
54 // This buffer must be allocated by the user.
55 /* Please see man pages for details
56
57
58
59
60
61
62 */
63 static size_t GetWorkBufferSize(size_t numMaxWaitObjects, size_t numWorkerThreads);
64
65 /* Please see man pages for details
66
67
68
69 */
70 ThreadPool();
71 /* Please see man pages for details
72
73
74
75
76
77
78
79
80 */
81 ThreadPool(void* workBuffer, size_t numMaxWaitObjects, size_t numWorkerThreads, uptr workerStackBottoms[], s32 workerPriority = DEFAULT_THREAD_PRIORITY, s32 waitPriority = 0);
82
83 #if NN_PLATFORM_HAS_MMU
84 /* Please see man pages for details
85
86
87
88
89
90
91
92
93 */
94 ThreadPool(void* workBuffer, size_t numMaxWaitObjects, size_t numWorkerThreads, nn::os::StackMemoryBlock workerStacks[], s32 workerPriority = DEFAULT_THREAD_PRIORITY, s32 waitPriority = 0);
95 #endif // if NN_PLATFORM_HAS_MMU
96
97 /* Please see man pages for details
98
99
100
101 */
~ThreadPool()102 virtual ~ThreadPool() { Finalize(); }
103
104 /* Please see man pages for details
105
106
107
108
109
110
111
112
113
114
115 */
116 void Initialize(void* workBuffer, size_t numMaxWaitObjects, size_t numWorkerThreads, uptr workerStackBottoms[], s32 workerPriority = DEFAULT_THREAD_PRIORITY, s32 waitPriority = 0);
117 #if NN_PLATFORM_HAS_MMU
118 /* Please see man pages for details
119
120
121
122
123
124
125
126
127
128
129 */
130 void Initialize(void* workBuffer, size_t numMaxWaitObjects, size_t numWorkerThreads, nn::os::StackMemoryBlock workerStacks[], s32 workerPriority = DEFAULT_THREAD_PRIORITY, s32 waitPriority = 0);
131 #endif // if NN_PLATFORM_HAS_MMU
132
133 // TODO: Need TryInitialize? Implementation is low priority as it is very difficult to rewind.
134
135 /* Please see man pages for details
136
137
138
139 */
140 void Finalize();
141
142 /* Please see man pages for details
143
144
145
146
147
148
149
150
151 */
AddTask(QueueableTask * task)152 virtual void AddTask(QueueableTask* task) { AddToExecuteQueue(task); }
153
154 /* Please see man pages for details
155
156
157
158
159
160
161
162
163
164
165 */
AddWaitTask(QueueableWaitTask * task)166 virtual void AddWaitTask(QueueableWaitTask* task) { AddToWaitQueue(task); }
167
168 private:
169
170 size_t m_NumMaxWaitObjects;
171 size_t m_NumThreads;
172
173 uptr m_Buffer;
174 Thread* GetThreads() const;
175 nn::Handle* GetWaitHandleBuffer() const;
176 QueueableWaitTask** GetWaitTaskBuffer() const;
177
178 s32 m_WaitingCount;
179
180 bool m_Finalizing;
181 bit8 m_Padding[3];
182
183 static const size_t WAIT_THREAD_STACK_SIZE = 392;
184 StackBuffer<WAIT_THREAD_STACK_SIZE> m_WaitThreadStack;
185
186 Thread m_WaitThread;
187 nn::fnd::IntrusiveQueue<QueueableTask> m_WaitQueue;
188 nn::os::CriticalSection m_WaitLock;
189 nn::os::Event m_WaitEvent;
190 void AddToWaitQueue(QueueableWaitTask*);
191
192 nn::fnd::IntrusiveQueue<QueueableTask> m_ExecuteQueue;
193 nn::os::CriticalSection m_ExecuteLock;
194 nn::os::LightEvent m_ExecuteEvent;
195 void AddToExecuteQueue(QueueableTask*);
196
197
198 static void WaitThreadFunc(ThreadPool*);
199 void WaitThreadFunc();
200 static void ExecuteThreadFunc(ThreadPool*);
201 void ExecuteThreadFunc();
202
203 void InitializeCommon(size_t numMaxWaitObjects, size_t numWorkerThreads, void* workBuffer);
204 void StartWaitThread(s32 priority);
205 void StartExecuteThread(size_t i, uptr stackBottom, s32 priority);
206
207 };
208
ThreadPool()209 inline ThreadPool::ThreadPool() : m_Buffer(0) {}
210
ThreadPool(void * workBuffer,size_t numMaxWaitObjects,size_t numWorkerThreads,uptr workerStackBottoms[],s32 workerPriority,s32 waitPriority)211 inline ThreadPool::ThreadPool(void* workBuffer, size_t numMaxWaitObjects, size_t numWorkerThreads, uptr workerStackBottoms[], s32 workerPriority, s32 waitPriority)
212 : m_Buffer(0)
213 {
214 Initialize(workBuffer, numMaxWaitObjects, numWorkerThreads, workerStackBottoms, workerPriority, waitPriority);
215 }
216
217 #if NN_PLATFORM_HAS_MMU
ThreadPool(void * workBuffer,size_t numMaxWaitObjects,size_t numWorkerThreads,nn::os::StackMemoryBlock workerStacks[],s32 workerPriority,s32 waitPriority)218 inline ThreadPool::ThreadPool(void* workBuffer, size_t numMaxWaitObjects, size_t numWorkerThreads, nn::os::StackMemoryBlock workerStacks[], s32 workerPriority, s32 waitPriority)
219 : m_Buffer(0)
220 {
221 Initialize(workBuffer, numMaxWaitObjects, numWorkerThreads, workerStacks, workerPriority, waitPriority);
222 }
223 #endif // if NN_PLATFORM_HAS_MMU
224
225
226 class SingleThreadPool : public ITaskInvoker, private nn::util::NonCopyable<SingleThreadPool>
227 {
228 public:
SingleThreadPool()229 SingleThreadPool() : m_Finalizing(false) {}
~SingleThreadPool()230 virtual ~SingleThreadPool() { Finalize(); }
231 void Initialize(uptr workerThreadStackBottom, s32 workerPriority = DEFAULT_THREAD_PRIORITY);
232 void Finalize();
233
AddTask(QueueableTask * task)234 virtual void AddTask(QueueableTask* task) { AddToExecuteQueue(task); }
235
236 static void ExecuteThreadFunc(SingleThreadPool* pInstance);
237 void ExecuteThreadFunc();
238
239 private:
240 nn::os::Thread m_WorkerThread;
241 nn::fnd::IntrusiveQueue<QueueableTask> m_ExecuteQueue;
242 nn::os::CriticalSection m_ExecuteLock;
243 nn::os::LightEvent m_ExecuteEvent;
244
245 bool m_Finalizing;
246 NN_PADDING3;
247
248 void AddToExecuteQueue(QueueableTask*);
249 };
250
251
252 }}
253
254 #endif // __cplusplus
255
256 // C declarations follow
257
258
259 #ifdef __cplusplus
260
261 namespace nn { namespace os {
262
263 namespace detail
264 {
265 class ThreadPoolTaskForC : public QueueableTask
266 {
267 public:
ThreadPoolTaskForC(void (* f)(uptr),uptr param)268 ThreadPoolTaskForC(void (*f)(uptr), uptr param) : m_F(f), m_Param(param) {}
Invoke()269 virtual void Invoke() { m_F(m_Param); }
270 private:
271 void (*m_F)(uptr);
272 uptr m_Param;
273 };
274
275 class ThreadPoolWaitTaskForC : public QueueableWaitTask
276 {
277 public:
ThreadPoolWaitTaskForC(nnosWaitObject * waitObject,void (* f)(uptr),uptr param)278 ThreadPoolWaitTaskForC(nnosWaitObject* waitObject, void (*f)(uptr), uptr param) : m_WaitObject(waitObject), m_F(f), m_Param(param) {}
GetWaitObject()279 virtual nn::os::WaitObject* GetWaitObject() { return reinterpret_cast<nn::os::WaitObject*&>(m_WaitObject); }
Invoke()280 virtual void Invoke() { m_F(m_Param); }
281 private:
282 nnosWaitObject* m_WaitObject;
283 void (*m_F)(uptr);
284 uptr m_Param;
285 };
286 }
287
288 }}
289
290 #endif
291
292 #include <nn/util/detail/util_CLibImpl.h>
293
294 /* Please see man pages for details
295
296
297
298
299
300
301
302
303
304
305 */
306
307 /* Please see man pages for details
308
309
310
311
312
313
314 */
315 NN_UTIL_DETAIL_CLIBIMPL_DEFINE_BUFFER_CLASS(nnosThreadPoolTask, nn::os::detail::ThreadPoolTaskForC, 16, u32);
316
317 /* Please see man pages for details
318
319 */
320 NN_EXTERN_C void nnosThreadPoolTaskInitialize(nnosThreadPoolTask* this_, void (*f)(uptr), uptr param);
321
322 /* Please see man pages for details
323
324 */
325
326 NN_EXTERN_C void nnosThreadPoolTaskFinalize(nnosThreadPoolTask* this_);
327
328
329 /* Please see man pages for details
330
331
332
333
334
335
336 */
337 NN_UTIL_DETAIL_CLIBIMPL_DEFINE_BUFFER_CLASS(nnosThreadPoolWaitTask, nn::os::detail::ThreadPoolWaitTaskForC, 20, u32);
338
339 /* Please see man pages for details
340
341 */
342 NN_EXTERN_C void nnosThreadPoolWaitTaskInitialize(nnosThreadPoolWaitTask* this_, nnosWaitObject* waitObject, void (*f)(uptr), uptr param);
343
344 /* Please see man pages for details
345
346 */
347 NN_EXTERN_C void nnosThreadPoolWaitTaskFinalize(nnosThreadPoolWaitTask* this_);
348
349
350 /* Please see man pages for details
351
352
353
354
355
356
357 */
358 NN_UTIL_DETAIL_CLIBIMPL_DEFINE_BUFFER_CLASS(nnosThreadPool, nn::os::ThreadPool, 472, bit64);
359
360 /* Please see man pages for details
361
362 */
363 NN_EXTERN_C void nnosThreadPoolInitialize(nnosThreadPool* this_, void* workBuffer, size_t numMaxWaitObjects, size_t numWorkerThreads, uptr workerStackBottoms[], s32 workerPriority);
364 #if NN_PLATFORM_HAS_MMU
365 NN_EXTERN_C void nnosThreadPoolInitializeWithStackMemoryBlock(nnosThreadPool* this_, void* workBuffer, size_t numMaxWaitObjects, size_t numWorkerThreads, nnosStackMemoryBlock workerStacks[], s32 workerPriority);
366 #endif // if NN_PLATFORM_HAS_MMU
367
368 /* Please see man pages for details
369
370 */
371 NN_EXTERN_C void nnosThreadPoolFinalize(nnosThreadPool* this_);
372
373 /* Please see man pages for details
374
375 */
376 NN_EXTERN_C void nnosThreadPoolAddWaitTask(nnosThreadPool* this_, nnosThreadPoolWaitTask* task);
377
378 /* Please see man pages for details
379
380 */
381 NN_EXTERN_C void nnosThreadPoolAddTask(nnosThreadPool* this_, nnosThreadPoolTask* task);
382
383 /* Please see man pages for details
384
385 */
386 NN_EXTERN_C size_t nnosThreadPoolGetWorkBufferSize(size_t numMaxWaitObjects, size_t numWorkerThreads);
387
388 /*
389
390
391
392 */
393
394 #endif // NN_OS_OS_THREADPOOL_H_
395