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