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