1 /*---------------------------------------------------------------------------*
2 Project: Horizon
3 File: os_ThreadPool.h
4
5 Copyright (C)2009-2012 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: 46347 $
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 size_t m_NumMaxWaitObjects;
170 size_t m_NumThreads;
171
172 uptr m_Buffer;
173 s32 m_WaitingCount;
174
175 bool m_Finalizing;
176 bit8 m_Padding[3];
177
178 static const size_t WAIT_THREAD_STACK_SIZE = 392;
179 StackBuffer<WAIT_THREAD_STACK_SIZE> m_WaitThreadStack;
180
181 Thread m_WaitThread;
182 nn::fnd::IntrusiveQueue<QueueableTask> m_WaitQueue;
183 nn::os::CriticalSection m_WaitLock;
184 nn::os::Event m_WaitEvent;
185
186 nn::fnd::IntrusiveQueue<QueueableTask> m_ExecuteQueue;
187 nn::os::CriticalSection m_ExecuteLock;
188 nn::os::LightEvent m_ExecuteEvent;
189 NN_PADDING4;
190
191 private:
192 Thread* GetThreads() const;
193 nn::Handle* GetWaitHandleBuffer() const;
194 QueueableWaitTask** GetWaitTaskBuffer() const;
195
196 void AddToWaitQueue(QueueableWaitTask*);
197
198 void AddToExecuteQueue(QueueableTask*);
199
200 static void WaitThreadFunc(ThreadPool*);
201 void WaitThreadFunc();
202 static void ExecuteThreadFunc(ThreadPool*);
203 void ExecuteThreadFunc();
204
205 void InitializeCommon(size_t numMaxWaitObjects, size_t numWorkerThreads, void* workBuffer);
206 void StartWaitThread(s32 priority);
207 void StartExecuteThread(size_t i, uptr stackBottom, s32 priority);
208
209 };
210
ThreadPool()211 inline ThreadPool::ThreadPool() : m_Buffer(0) {}
212
ThreadPool(void * workBuffer,size_t numMaxWaitObjects,size_t numWorkerThreads,uptr workerStackBottoms[],s32 workerPriority,s32 waitPriority)213 inline ThreadPool::ThreadPool(void* workBuffer, size_t numMaxWaitObjects, size_t numWorkerThreads, uptr workerStackBottoms[], s32 workerPriority, s32 waitPriority)
214 : m_Buffer(0)
215 {
216 Initialize(workBuffer, numMaxWaitObjects, numWorkerThreads, workerStackBottoms, workerPriority, waitPriority);
217 }
218
219 #if NN_PLATFORM_HAS_MMU
ThreadPool(void * workBuffer,size_t numMaxWaitObjects,size_t numWorkerThreads,nn::os::StackMemoryBlock workerStacks[],s32 workerPriority,s32 waitPriority)220 inline ThreadPool::ThreadPool(void* workBuffer, size_t numMaxWaitObjects, size_t numWorkerThreads, nn::os::StackMemoryBlock workerStacks[], s32 workerPriority, s32 waitPriority)
221 : m_Buffer(0)
222 {
223 Initialize(workBuffer, numMaxWaitObjects, numWorkerThreads, workerStacks, workerPriority, waitPriority);
224 }
225 #endif // if NN_PLATFORM_HAS_MMU
226
227
228 class SingleThreadPool : public ITaskInvoker, private nn::util::NonCopyable<SingleThreadPool>
229 {
230 public:
SingleThreadPool()231 SingleThreadPool() : m_Finalizing(false) {}
~SingleThreadPool()232 virtual ~SingleThreadPool() { Finalize(); }
233 void Initialize(uptr workerThreadStackBottom, s32 workerPriority = DEFAULT_THREAD_PRIORITY);
234 void Finalize();
235
AddTask(QueueableTask * task)236 virtual void AddTask(QueueableTask* task) { AddToExecuteQueue(task); }
237
238 static void ExecuteThreadFunc(SingleThreadPool* pInstance);
239 void ExecuteThreadFunc();
240
241 private:
242 nn::os::Thread m_WorkerThread;
243 nn::fnd::IntrusiveQueue<QueueableTask> m_ExecuteQueue;
244 nn::os::CriticalSection m_ExecuteLock;
245 nn::os::LightEvent m_ExecuteEvent;
246
247 bool m_Finalizing;
248 NN_PADDING3;
249
250 void AddToExecuteQueue(QueueableTask*);
251 };
252
253
254 }}
255
256 #endif // __cplusplus
257
258 // C declarations follow
259
260
261 #ifdef __cplusplus
262
263 namespace nn { namespace os {
264
265 namespace detail
266 {
267 class ThreadPoolTaskForC : public QueueableTask
268 {
269 public:
ThreadPoolTaskForC(void (* f)(uptr),uptr param)270 ThreadPoolTaskForC(void (*f)(uptr), uptr param) : m_F(f), m_Param(param) {}
Invoke()271 virtual void Invoke() { m_F(m_Param); }
272 private:
273 void (*m_F)(uptr);
274 uptr m_Param;
275 };
276
277 class ThreadPoolWaitTaskForC : public QueueableWaitTask
278 {
279 public:
ThreadPoolWaitTaskForC(nnosWaitObject * waitObject,void (* f)(uptr),uptr param)280 ThreadPoolWaitTaskForC(nnosWaitObject* waitObject, void (*f)(uptr), uptr param) : m_WaitObject(waitObject), m_F(f), m_Param(param) {}
GetWaitObject()281 virtual nn::os::WaitObject* GetWaitObject() { return reinterpret_cast<nn::os::WaitObject*&>(m_WaitObject); }
Invoke()282 virtual void Invoke() { m_F(m_Param); }
283 private:
284 nnosWaitObject* m_WaitObject;
285 void (*m_F)(uptr);
286 uptr m_Param;
287 };
288 }
289
290 }}
291
292 #endif
293
294 #include <nn/util/detail/util_CLibImpl.h>
295
296 /* Please see man pages for details
297
298
299
300
301
302
303
304
305
306
307 */
308
309 /* Please see man pages for details
310
311
312
313
314
315
316 */
317 NN_UTIL_DETAIL_CLIBIMPL_DEFINE_BUFFER_CLASS(nnosThreadPoolTask, nn::os::detail::ThreadPoolTaskForC, 16, u32);
318
319 /* Please see man pages for details
320
321 */
322 NN_EXTERN_C void nnosThreadPoolTaskInitialize(nnosThreadPoolTask* this_, void (*f)(uptr), uptr param);
323
324 /* Please see man pages for details
325
326 */
327
328 NN_EXTERN_C void nnosThreadPoolTaskFinalize(nnosThreadPoolTask* this_);
329
330
331 /* Please see man pages for details
332
333
334
335
336
337
338 */
339 NN_UTIL_DETAIL_CLIBIMPL_DEFINE_BUFFER_CLASS(nnosThreadPoolWaitTask, nn::os::detail::ThreadPoolWaitTaskForC, 20, u32);
340
341 /* Please see man pages for details
342
343 */
344 NN_EXTERN_C void nnosThreadPoolWaitTaskInitialize(nnosThreadPoolWaitTask* this_, nnosWaitObject* waitObject, void (*f)(uptr), uptr param);
345
346 /* Please see man pages for details
347
348 */
349 NN_EXTERN_C void nnosThreadPoolWaitTaskFinalize(nnosThreadPoolWaitTask* this_);
350
351
352 /* Please see man pages for details
353
354
355
356
357
358
359 */
360 NN_UTIL_DETAIL_CLIBIMPL_DEFINE_BUFFER_CLASS(nnosThreadPool, nn::os::ThreadPool, 480, bit64);
361
362 /* Please see man pages for details
363
364 */
365 NN_EXTERN_C void nnosThreadPoolInitialize(nnosThreadPool* this_, void* workBuffer, size_t numMaxWaitObjects, size_t numWorkerThreads, uptr workerStackBottoms[], s32 workerPriority);
366 #if NN_PLATFORM_HAS_MMU
367 NN_EXTERN_C void nnosThreadPoolInitializeWithStackMemoryBlock(nnosThreadPool* this_, void* workBuffer, size_t numMaxWaitObjects, size_t numWorkerThreads, nnosStackMemoryBlock workerStacks[], s32 workerPriority);
368 #endif // if NN_PLATFORM_HAS_MMU
369
370 /* Please see man pages for details
371
372 */
373 NN_EXTERN_C void nnosThreadPoolFinalize(nnosThreadPool* this_);
374
375 /* Please see man pages for details
376
377 */
378 NN_EXTERN_C void nnosThreadPoolAddWaitTask(nnosThreadPool* this_, nnosThreadPoolWaitTask* task);
379
380 /* Please see man pages for details
381
382 */
383 NN_EXTERN_C void nnosThreadPoolAddTask(nnosThreadPool* this_, nnosThreadPoolTask* task);
384
385 /* Please see man pages for details
386
387 */
388 NN_EXTERN_C size_t nnosThreadPoolGetWorkBufferSize(size_t numMaxWaitObjects, size_t numWorkerThreads);
389
390 /*
391
392
393
394 */
395
396 #endif // NN_OS_OS_THREADPOOL_H_
397