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, ¶ms, 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