1 /*************************************************************************
2  *                                                                       *
3  * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith.       *
4  * All rights reserved.  Email: russ@q12.org   Web: www.q12.org          *
5  *                                                                       *
6  * Threading POSIX thread pool implementation file.                      *
7  * Copyright (C) 2011-2012 Oleh Derevenko. All rights reserved.          *
8  * e-mail: odar@eleks.com (change all "a" to "e")                        *
9  *                                                                       *
10  * This library is free software; you can redistribute it and/or         *
11  * modify it under the terms of EITHER:                                  *
12  *   (1) The GNU Lesser General Public License as published by the Free  *
13  *       Software Foundation; either version 2.1 of the License, or (at  *
14  *       your option) any later version. The text of the GNU Lesser      *
15  *       General Public License is included with this library in the     *
16  *       file LICENSE.TXT.                                               *
17  *   (2) The BSD-style license that is included with this library in     *
18  *       the file LICENSE-BSD.TXT.                                       *
19  *                                                                       *
20  * This library is distributed in the hope that it will be useful,       *
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files    *
23  * LICENSE.TXT and LICENSE-BSD.TXT for more details.                     *
24  *                                                                       *
25  *************************************************************************/
26 
27 /*
28  *  POSIX thread pool implementation for built-in threading support provider.
29  */
30 
31 
32 #if !defined(_WIN32)
33 
34 #include <ode/odeconfig.h>
35 #include <ode/error.h>
36 #include <ode/threading_impl.h>
37 #include <ode/odeinit.h>
38 #include "config.h"
39 #include "objects.h"
40 #include "threading_impl_templates.h"
41 
42 
43 #if dBUILTIN_THREADING_IMPL_ENABLED
44 
45 #include <new>
46 #include <pthread.h>
47 #include <signal.h>
48 #include <errno.h>
49 
50 #if !defined(EOK)
51 #define EOK   0
52 #endif
53 
54 
55 #endif // #if dBUILTIN_THREADING_IMPL_ENABLED
56 
57 
58 #if dBUILTIN_THREADING_IMPL_ENABLED
59 
60 struct dxEventObject
61 {
62 public:
dxEventObjectdxEventObject63     dxEventObject(): m_event_allocated(false), m_event_manual(false), m_event_value(false) {}
~dxEventObjectdxEventObject64     ~dxEventObject() { FinalizeObject(); }
65 
66     bool InitializeObject(bool manual_reset, bool initial_state);
67     void FinalizeObject();
68 
69     // WARNING! To make implementation simpler, event only releases a single thread even for manual mode.
70     bool WaitInfinitely();
71     void SetEvent();
72     void ResetEvent();
73 
74 private:
75     bool              m_event_allocated;
76     bool              m_event_manual;
77     bool              m_event_value;
78     pthread_mutex_t   m_event_mutex;
79     pthread_cond_t    m_event_cond;
80 };
81 
InitializeObject(bool manual_reset,bool initial_state)82 bool dxEventObject::InitializeObject(bool manual_reset, bool initial_state)
83 {
84     dIASSERT(!m_event_allocated);
85 
86     bool result = false;
87 
88     bool cond_allocated = false;
89 
90     do
91     {
92         int cond_result = pthread_cond_init(&m_event_cond, NULL);
93         if (cond_result != EOK)
94         {
95             errno = cond_result;
96             break;
97         }
98 
99         cond_allocated = true;
100 
101         int mutex_result = pthread_mutex_init(&m_event_mutex, NULL);
102         if (mutex_result != EOK)
103         {
104             errno = mutex_result;
105             break;
106         }
107 
108         m_event_manual = manual_reset;
109         m_event_value = initial_state;
110         m_event_allocated = true;
111         result = true;
112     }
113     while (false);
114 
115     if (!result)
116     {
117         if (cond_allocated)
118         {
119             int cond_destroy_result = pthread_cond_destroy(&m_event_cond);
120             dIVERIFY(cond_destroy_result == EOK);
121         }
122     }
123 
124     return result;
125 }
126 
FinalizeObject()127 void dxEventObject::FinalizeObject()
128 {
129     if (m_event_allocated)
130     {
131         int mutex_destroy_result = pthread_mutex_destroy(&m_event_mutex);
132         dICHECK(mutex_destroy_result == EOK); // Why would mutex be unable to be destroyed?
133 
134         int cond_destroy_result = pthread_cond_destroy(&m_event_cond);
135         dICHECK(cond_destroy_result == EOK); // Why would condvar be unable to be destroyed?
136 
137         m_event_allocated = false;
138     }
139 }
140 
WaitInfinitely()141 bool dxEventObject::WaitInfinitely()
142 {
143     bool result = false;
144 
145     int lock_result = pthread_mutex_lock(&m_event_mutex);
146     dICHECK(lock_result == EOK);
147 
148     int wait_result = EOK;
149     if (!m_event_value)
150     {
151         wait_result = pthread_cond_wait(&m_event_cond, &m_event_mutex);
152         dICHECK(wait_result != EINTR); // Would caller be so kind to disable signal handling for thread for duration of the call to ODE at least?
153     }
154 
155     if (wait_result == EOK)
156     {
157         dIASSERT(m_event_value);
158 
159         if (!m_event_manual)
160         {
161             m_event_value = false;
162         }
163 
164         result = true;
165     }
166 
167     int unlock_result = pthread_mutex_unlock(&m_event_mutex);
168     dICHECK(unlock_result == EOK);
169 
170     return result;
171 }
172 
SetEvent()173 void dxEventObject::SetEvent()
174 {
175     int lock_result = pthread_mutex_lock(&m_event_mutex);
176     dICHECK(lock_result == EOK);
177 
178     if (!m_event_value)
179     {
180         m_event_value = true;
181 
182         // NOTE! Event only releases a single thread even for manual mode to simplify implementation.
183         int signal_result = pthread_cond_signal(&m_event_cond);
184         dICHECK(signal_result == EOK);
185     }
186 
187     int unlock_result = pthread_mutex_unlock(&m_event_mutex);
188     dICHECK(unlock_result == EOK);
189 }
190 
ResetEvent()191 void dxEventObject::ResetEvent()
192 {
193     int lock_result = pthread_mutex_lock(&m_event_mutex);
194     dICHECK(lock_result == EOK);
195 
196     m_event_value = false;
197 
198     int unlock_result = pthread_mutex_unlock(&m_event_mutex);
199     dICHECK(unlock_result == EOK);
200 }
201 
202 
203 struct dxThreadPoolThreadInfo
204 {
205 public:
206     dxThreadPoolThreadInfo();
207     ~dxThreadPoolThreadInfo();
208 
209     bool Initialize(size_t stack_size, unsigned int ode_data_allocate_flags);
210 
211 private:
212     bool InitializeThreadAttributes(pthread_attr_t *thread_attr, size_t stack_size);
213     void FinalizeThreadAttributes(pthread_attr_t *thread_attr);
214     bool WaitInitStatus();
215 
216 private:
217     void Finalize();
218     void WaitAndCloseThreadHandle(pthread_t thread_handle);
219 
220 public:
221     enum dxTHREADCOMMAND
222     {
223         dxTHREAD_COMMAND_EXIT,
224         dxTHREAD_COMMAND_NOOP,
225         dxTHREAD_COMMAND_SERVE_IMPLEMENTATION,
226     };
227 
228     struct dxServeImplementationParams
229     {
dxServeImplementationParamsdxThreadPoolThreadInfo::dxServeImplementationParams230         dxServeImplementationParams(dThreadingImplementationID impl, dxEventObject *ready_wait_event):
231     m_impl(impl), m_ready_wait_event(ready_wait_event)
232     {
233     }
234 
235     dThreadingImplementationID m_impl;
236     dxEventObject *m_ready_wait_event;
237     };
238 
239     void ExecuteThreadCommand(dxTHREADCOMMAND command, void *param, bool wait_response);
240 
241 private:
242     static void *ThreadProcedure_Callback(void *thread_param);
243     void ThreadProcedure();
244     bool DisableSignalHandlers();
245     void ReportInitStatus(bool init_result);
246     void RunCommandHandlingLoop();
247 
248     void ThreadedServeImplementation(dThreadingImplementationID impl, dxEventObject *ready_wait_event);
249     static void ProcessThreadServeReadiness_Callback(void *context);
250 
251 private:
252     pthread_t   m_thread_handle;
253     bool        m_thread_allocated;
254 
255     unsigned int m_ode_data_allocate_flags;
256     dxTHREADCOMMAND m_command_code;
257     dxEventObject m_command_event;
258     dxEventObject m_acknowledgement_event;
259     void        *m_command_param;
260 };
261 
262 
dxThreadPoolThreadInfo()263 dxThreadPoolThreadInfo::dxThreadPoolThreadInfo():
264 m_thread_handle(),
265 m_thread_allocated(false),
266 m_ode_data_allocate_flags(0),
267 m_command_code(dxTHREAD_COMMAND_EXIT),
268 m_command_event(),
269 m_acknowledgement_event(),
270 m_command_param(NULL)
271 {
272 }
273 
~dxThreadPoolThreadInfo()274 dxThreadPoolThreadInfo::~dxThreadPoolThreadInfo()
275 {
276     Finalize();
277 }
278 
279 
Initialize(size_t stack_size,unsigned int ode_data_allocate_flags)280 bool dxThreadPoolThreadInfo::Initialize(size_t stack_size, unsigned int ode_data_allocate_flags)
281 {
282     bool result = false;
283 
284     bool command_event_allocated = false, acknowledgement_event_allocated = false;
285 
286     do
287     {
288         // -- There is no implicit limit on stack size in POSIX implementation
289         // if (stack_size > ...)
290         // {
291         //   errno = EINVAL;
292         //   break;
293         // }
294 
295         if (!m_command_event.InitializeObject(false, false))
296         {
297             break;
298         }
299 
300         command_event_allocated = true;
301 
302         if (!m_acknowledgement_event.InitializeObject(true, false))
303         {
304             break;
305         }
306 
307         acknowledgement_event_allocated = true;
308 
309         m_ode_data_allocate_flags = ode_data_allocate_flags;
310 
311         pthread_attr_t thread_attr;
312         if (!InitializeThreadAttributes(&thread_attr, stack_size))
313         {
314             break;
315         }
316 
317         int thread_create_result = pthread_create(&m_thread_handle, &thread_attr, &ThreadProcedure_Callback, (void *)this);
318 
319         FinalizeThreadAttributes(&thread_attr);
320 
321         if (thread_create_result != EOK)
322         {
323             errno = thread_create_result;
324             break;
325         }
326 
327         bool thread_init_result = WaitInitStatus();
328         if (!thread_init_result)
329         {
330             WaitAndCloseThreadHandle(m_thread_handle);
331             break;
332         }
333 
334         m_thread_allocated = true;
335         result = true;
336     }
337     while (false);
338 
339     if (!result)
340     {
341         if (command_event_allocated)
342         {
343             if (acknowledgement_event_allocated)
344             {
345                 m_acknowledgement_event.FinalizeObject();
346             }
347 
348             m_command_event.FinalizeObject();
349         }
350     }
351 
352     return result;
353 }
354 
InitializeThreadAttributes(pthread_attr_t * thread_attr,size_t stack_size)355 bool dxThreadPoolThreadInfo::InitializeThreadAttributes(pthread_attr_t *thread_attr, size_t stack_size)
356 {
357     bool result = false;
358 
359     bool attr_inited = false;
360 
361     do
362     {
363         int init_result = pthread_attr_init(thread_attr);
364         if (init_result != EOK)
365         {
366             errno = init_result;
367             break;
368         }
369 
370         attr_inited = true;
371 
372         int set_result;
373         if ((set_result = pthread_attr_setdetachstate(thread_attr, PTHREAD_CREATE_JOINABLE)) != EOK
374             || (set_result = pthread_attr_setinheritsched(thread_attr, PTHREAD_INHERIT_SCHED)) != EOK
375 #if (HAVE_PTHREAD_ATTR_SETSTACKLAZY)
376             || (set_result = pthread_attr_setstacklazy(thread_attr, PTHREAD_STACK_NOTLAZY)) != EOK
377 #endif
378             || (stack_size != 0 && (set_result = pthread_attr_setstacksize(thread_attr, stack_size)) != EOK))
379         {
380             errno = set_result;
381             break;
382         }
383 
384         result = true;
385     }
386     while (false);
387 
388     if (!result)
389     {
390         if (attr_inited)
391         {
392             int destroy_result = pthread_attr_destroy(thread_attr);
393             dIVERIFY(destroy_result == EOK);
394         }
395     }
396 
397     return result;
398 }
399 
FinalizeThreadAttributes(pthread_attr_t * thread_attr)400 void dxThreadPoolThreadInfo::FinalizeThreadAttributes(pthread_attr_t *thread_attr)
401 {
402     int destroy_result = pthread_attr_destroy(thread_attr);
403     dIVERIFY(destroy_result == EOK);
404 }
405 
WaitInitStatus()406 bool dxThreadPoolThreadInfo::WaitInitStatus()
407 {
408     bool acknowledgement_wait_result = m_acknowledgement_event.WaitInfinitely();
409     dICHECK(acknowledgement_wait_result);
410 
411     int error_code = (int)(size_t)m_command_param;
412 
413     bool init_status = error_code == EOK ? true : ((errno = error_code), false);
414     return init_status;
415 }
416 
Finalize()417 void dxThreadPoolThreadInfo::Finalize()
418 {
419     if (m_thread_allocated)
420     {
421         ExecuteThreadCommand(dxTHREAD_COMMAND_EXIT, NULL, false);
422 
423         WaitAndCloseThreadHandle(m_thread_handle);
424         m_thread_allocated = false;
425 
426         m_command_event.FinalizeObject();
427         m_acknowledgement_event.FinalizeObject();
428     }
429 }
430 
WaitAndCloseThreadHandle(pthread_t thread_handle)431 void dxThreadPoolThreadInfo::WaitAndCloseThreadHandle(pthread_t thread_handle)
432 {
433     int join_result = pthread_join(thread_handle, NULL);
434     dICHECK(join_result == EOK);
435 }
436 
ExecuteThreadCommand(dxTHREADCOMMAND command,void * param,bool wait_response)437 void dxThreadPoolThreadInfo::ExecuteThreadCommand(dxTHREADCOMMAND command, void *param, bool wait_response)
438 {
439     bool acknowledgement_wait_result = m_acknowledgement_event.WaitInfinitely();
440     dICHECK(acknowledgement_wait_result);
441 
442     m_acknowledgement_event.ResetEvent();
443 
444     m_command_code = command;
445     m_command_param = param;
446 
447     m_command_event.SetEvent();
448 
449     if (wait_response)
450     {
451         bool new_acknowledgement_wait_result = m_acknowledgement_event.WaitInfinitely();
452         dICHECK(new_acknowledgement_wait_result);
453     }
454 }
455 
ThreadProcedure_Callback(void * thread_param)456 void *dxThreadPoolThreadInfo::ThreadProcedure_Callback(void *thread_param)
457 {
458     dxThreadPoolThreadInfo *thread_info = (dxThreadPoolThreadInfo *)thread_param;
459     thread_info->ThreadProcedure();
460 
461     return 0;
462 }
463 
ThreadProcedure()464 void dxThreadPoolThreadInfo::ThreadProcedure()
465 {
466     bool init_result = dAllocateODEDataForThread(m_ode_data_allocate_flags) != 0
467         && DisableSignalHandlers();
468 
469     ReportInitStatus(init_result);
470 
471     if (init_result)
472     {
473         RunCommandHandlingLoop();
474 
475         // dCleanupODEAllDataForThread(); -- this function can only be called if ODE was initialized for manual cleanup. And that is unknown here...
476     }
477 }
478 
DisableSignalHandlers()479 bool dxThreadPoolThreadInfo::DisableSignalHandlers()
480 {
481     bool result = false;
482 
483     sigset_t set;
484     sigfillset( &set );
485 
486     if (sigprocmask( SIG_BLOCK, &set, NULL ) != -1)
487     {
488         result = true;
489     }
490 
491     return result;
492 }
493 
ReportInitStatus(bool init_result)494 void dxThreadPoolThreadInfo::ReportInitStatus(bool init_result)
495 {
496     m_command_param = (void *)(size_t)(init_result ? EOK : ((errno != EOK) ? errno : EFAULT));
497 
498     m_acknowledgement_event.SetEvent();
499 }
500 
RunCommandHandlingLoop()501 void dxThreadPoolThreadInfo::RunCommandHandlingLoop()
502 {
503     bool exit_requested = false;
504 
505     while (!exit_requested)
506     {
507         bool command_wait_result = m_command_event.WaitInfinitely();
508         dICHECK(command_wait_result);
509 
510         const dxTHREADCOMMAND command_code = m_command_code;
511         switch (command_code)
512         {
513             case dxTHREAD_COMMAND_EXIT:
514             {
515                 m_acknowledgement_event.SetEvent();
516 
517                 exit_requested = true;
518                 break;
519             }
520 
521             default:
522             {
523                 dIASSERT(false);
524                 // break; -- proceed to case dxTHREAD_COMMAND_NOOP
525             }
526 
527             case dxTHREAD_COMMAND_NOOP:
528             {
529                 m_acknowledgement_event.SetEvent();
530 
531                 // Do nothing
532                 break;
533             }
534 
535             case dxTHREAD_COMMAND_SERVE_IMPLEMENTATION:
536             {
537                 const dxServeImplementationParams *serve_params = (const dxServeImplementationParams *)m_command_param;
538                 dThreadingImplementationID impl = serve_params->m_impl;
539                 dxEventObject *ready_wait_event = serve_params->m_ready_wait_event;
540 
541                 m_acknowledgement_event.SetEvent();
542 
543                 ThreadedServeImplementation(impl, ready_wait_event);
544                 break;
545             }
546         }
547     }
548 }
549 
ThreadedServeImplementation(dThreadingImplementationID impl,dxEventObject * ready_wait_event)550 void dxThreadPoolThreadInfo::ThreadedServeImplementation(dThreadingImplementationID impl, dxEventObject *ready_wait_event)
551 {
552     ((dxIThreadingImplementation *)impl)->StickToJobsProcessing(&ProcessThreadServeReadiness_Callback, (void *)ready_wait_event);
553 }
554 
ProcessThreadServeReadiness_Callback(void * context)555 void dxThreadPoolThreadInfo::ProcessThreadServeReadiness_Callback(void *context)
556 {
557     dxEventObject *ready_wait_event = (dxEventObject *)context;
558 
559     ready_wait_event->SetEvent();
560 }
561 
562 
563 
564 struct dxThreadingThreadPool:
565     public dBase
566 {
567 public:
568     dxThreadingThreadPool();
569     ~dxThreadingThreadPool();
570 
571     bool InitializeThreads(size_t thread_count, size_t stack_size, unsigned int ode_data_allocate_flags);
572 
573 private:
574     void FinalizeThreads();
575 
576     bool InitializeIndividualThreadInfos(dxThreadPoolThreadInfo *thread_infos, size_t thread_count, size_t stack_size, unsigned int ode_data_allocate_flags);
577     void FinalizeIndividualThreadInfos(dxThreadPoolThreadInfo *thread_infos, size_t thread_count);
578 
579     bool InitializeSingleThreadInfo(dxThreadPoolThreadInfo *thread_info, size_t stack_size, unsigned int ode_data_allocate_flags);
580     void FinalizeSingleThreadInfo(dxThreadPoolThreadInfo *thread_info);
581 
582 public:
583     void ServeThreadingImplementation(dThreadingImplementationID impl);
584     void WaitIdleState();
585 
586 private:
587     dxThreadPoolThreadInfo  *m_thread_infos;
588     size_t                  m_thread_count;
589     dxEventObject           m_ready_wait_event;
590 };
591 
592 
dxThreadingThreadPool()593 dxThreadingThreadPool::dxThreadingThreadPool():
594 m_thread_infos(NULL),
595 m_thread_count(0),
596 m_ready_wait_event()
597 {
598 }
599 
~dxThreadingThreadPool()600 dxThreadingThreadPool::~dxThreadingThreadPool()
601 {
602     FinalizeThreads();
603 }
604 
605 
InitializeThreads(size_t thread_count,size_t stack_size,unsigned int ode_data_allocate_flags)606 bool dxThreadingThreadPool::InitializeThreads(size_t thread_count, size_t stack_size, unsigned int ode_data_allocate_flags)
607 {
608     dIASSERT(m_thread_infos == NULL);
609 
610     bool result = false;
611 
612     bool wait_event_allocated = false;
613 
614     dxThreadPoolThreadInfo *thread_infos = NULL;
615     bool thread_infos_allocated = false;
616 
617     do
618     {
619         if (!m_ready_wait_event.InitializeObject(false, false))
620         {
621             break;
622         }
623 
624         wait_event_allocated = true;
625 
626         thread_infos = (dxThreadPoolThreadInfo *)dAlloc(thread_count * sizeof(dxThreadPoolThreadInfo));
627         if (thread_infos == NULL)
628         {
629             break;
630         }
631 
632         thread_infos_allocated = true;
633 
634         if (!InitializeIndividualThreadInfos(thread_infos, thread_count, stack_size, ode_data_allocate_flags))
635         {
636             break;
637         }
638 
639         m_thread_infos = thread_infos;
640         m_thread_count = thread_count;
641         result = true;
642     }
643     while (false);
644 
645     if (!result)
646     {
647         if (wait_event_allocated)
648         {
649             if (thread_infos_allocated)
650             {
651                 dFree(thread_infos, thread_count * sizeof(dxThreadPoolThreadInfo));
652             }
653 
654             m_ready_wait_event.FinalizeObject();
655         }
656     }
657 
658     return result;
659 }
660 
FinalizeThreads()661 void dxThreadingThreadPool::FinalizeThreads()
662 {
663     dxThreadPoolThreadInfo *thread_infos = m_thread_infos;
664     if (thread_infos != NULL)
665     {
666         size_t thread_count = m_thread_count;
667 
668         FinalizeIndividualThreadInfos(thread_infos, thread_count);
669         dFree(thread_infos, thread_count * sizeof(dxThreadPoolThreadInfo));
670 
671         m_ready_wait_event.FinalizeObject();
672     }
673 }
674 
675 
InitializeIndividualThreadInfos(dxThreadPoolThreadInfo * thread_infos,size_t thread_count,size_t stack_size,unsigned int ode_data_allocate_flags)676 bool dxThreadingThreadPool::InitializeIndividualThreadInfos(dxThreadPoolThreadInfo *thread_infos, size_t thread_count, size_t stack_size, unsigned int ode_data_allocate_flags)
677 {
678     bool any_fault = false;
679 
680     dxThreadPoolThreadInfo *const infos_end = thread_infos + thread_count;
681     for (dxThreadPoolThreadInfo *current_info = thread_infos; current_info != infos_end; ++current_info)
682     {
683         if (!InitializeSingleThreadInfo(current_info, stack_size, ode_data_allocate_flags))
684         {
685             FinalizeIndividualThreadInfos(thread_infos, current_info - thread_infos);
686 
687             any_fault = true;
688             break;
689         }
690     }
691 
692     bool result = !any_fault;
693     return result;
694 }
695 
FinalizeIndividualThreadInfos(dxThreadPoolThreadInfo * thread_infos,size_t thread_count)696 void dxThreadingThreadPool::FinalizeIndividualThreadInfos(dxThreadPoolThreadInfo *thread_infos, size_t thread_count)
697 {
698     dxThreadPoolThreadInfo *const infos_end = thread_infos + thread_count;
699     for (dxThreadPoolThreadInfo *current_info = thread_infos; current_info != infos_end; ++current_info)
700     {
701         FinalizeSingleThreadInfo(current_info);
702     }
703 }
704 
705 
InitializeSingleThreadInfo(dxThreadPoolThreadInfo * thread_info,size_t stack_size,unsigned int ode_data_allocate_flags)706 bool dxThreadingThreadPool::InitializeSingleThreadInfo(dxThreadPoolThreadInfo *thread_info, size_t stack_size, unsigned int ode_data_allocate_flags)
707 {
708     bool result = false;
709 
710     new(thread_info) dxThreadPoolThreadInfo();
711 
712     if (thread_info->Initialize(stack_size, ode_data_allocate_flags))
713     {
714         result = true;
715     }
716     else
717     {
718         thread_info->dxThreadPoolThreadInfo::~dxThreadPoolThreadInfo();
719     }
720 
721     return result;
722 }
723 
FinalizeSingleThreadInfo(dxThreadPoolThreadInfo * thread_info)724 void dxThreadingThreadPool::FinalizeSingleThreadInfo(dxThreadPoolThreadInfo *thread_info)
725 {
726     if (thread_info != NULL)
727     {
728         thread_info->dxThreadPoolThreadInfo::~dxThreadPoolThreadInfo();
729     }
730 }
731 
732 
ServeThreadingImplementation(dThreadingImplementationID impl)733 void dxThreadingThreadPool::ServeThreadingImplementation(dThreadingImplementationID impl)
734 {
735     dxThreadPoolThreadInfo::dxServeImplementationParams params(impl, &m_ready_wait_event);
736 
737     dxThreadPoolThreadInfo *const infos_end = m_thread_infos + m_thread_count;
738     for (dxThreadPoolThreadInfo *current_info = m_thread_infos; current_info != infos_end; ++current_info)
739     {
740         current_info->ExecuteThreadCommand(dxThreadPoolThreadInfo::dxTHREAD_COMMAND_SERVE_IMPLEMENTATION, &params, true);
741 
742         bool ready_wait_result = m_ready_wait_event.WaitInfinitely();
743         dICHECK(ready_wait_result);
744     }
745 }
746 
WaitIdleState()747 void dxThreadingThreadPool::WaitIdleState()
748 {
749     dxThreadPoolThreadInfo *const infos_end = m_thread_infos + m_thread_count;
750     for (dxThreadPoolThreadInfo *current_info = m_thread_infos; current_info != infos_end; ++current_info)
751     {
752         current_info->ExecuteThreadCommand(dxThreadPoolThreadInfo::dxTHREAD_COMMAND_NOOP, NULL, true);
753     }
754 }
755 
756 
757 #endif // #if dBUILTIN_THREADING_IMPL_ENABLED
758 
759 
dThreadingAllocateThreadPool(unsigned thread_count,size_t stack_size,unsigned int ode_data_allocate_flags,void * reserved)760 /*extern */dThreadingThreadPoolID dThreadingAllocateThreadPool(unsigned thread_count,
761                                                                size_t stack_size, unsigned int ode_data_allocate_flags, void *reserved/*=NULL*/)
762 {
763     dAASSERT(thread_count != 0);
764 
765 #if dBUILTIN_THREADING_IMPL_ENABLED
766     dxThreadingThreadPool *thread_pool = new dxThreadingThreadPool();
767     if (thread_pool != NULL)
768     {
769         if (thread_pool->InitializeThreads(thread_count, stack_size, ode_data_allocate_flags))
770         {
771             // do nothing
772         }
773         else
774         {
775             delete thread_pool;
776             thread_pool = NULL;
777         }
778     }
779 #else
780     dThreadingThreadPoolID thread_pool = NULL;
781 #endif // #if dBUILTIN_THREADING_IMPL_ENABLED
782 
783     return (dThreadingThreadPoolID)thread_pool;
784 }
785 
dThreadingThreadPoolServeMultiThreadedImplementation(dThreadingThreadPoolID pool,dThreadingImplementationID impl)786 /*extern */void dThreadingThreadPoolServeMultiThreadedImplementation(dThreadingThreadPoolID pool, dThreadingImplementationID impl)
787 {
788 #if dBUILTIN_THREADING_IMPL_ENABLED
789     dxThreadingThreadPool *thread_pool = (dxThreadingThreadPool *)pool;
790     thread_pool->ServeThreadingImplementation(impl);
791 #endif // #if dBUILTIN_THREADING_IMPL_ENABLED
792 }
793 
dThreadingThreadPoolWaitIdleState(dThreadingThreadPoolID pool)794 /*extern */void dThreadingThreadPoolWaitIdleState(dThreadingThreadPoolID pool)
795 {
796 #if dBUILTIN_THREADING_IMPL_ENABLED
797     dxThreadingThreadPool *thread_pool = (dxThreadingThreadPool *)pool;
798     thread_pool->WaitIdleState();
799 #endif // #if dBUILTIN_THREADING_IMPL_ENABLED
800 }
801 
dThreadingFreeThreadPool(dThreadingThreadPoolID pool)802 /*extern */void dThreadingFreeThreadPool(dThreadingThreadPoolID pool)
803 {
804 #if dBUILTIN_THREADING_IMPL_ENABLED
805     dxThreadingThreadPool *thread_pool = (dxThreadingThreadPool *)pool;
806     delete thread_pool;
807 #endif // #if dBUILTIN_THREADING_IMPL_ENABLED
808 }
809 
810 
811 #endif // #if !defined(_WIN32)
812