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 subsystem 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 * Subsystem APIs implementation for built-in threading support provider.
29 */
30
31
32 #include <ode/common.h>
33 #include <ode/threading_impl.h>
34 #include "config.h"
35 #include "threading_impl_posix.h"
36 #include "threading_impl_win.h"
37 #include "threading_impl.h"
38
39
40 static dMutexGroupID AllocMutexGroup(dThreadingImplementationID impl, dmutexindex_t Mutex_count, const char *const *Mutex_names_ptr/*=NULL*/);
41 static void FreeMutexGroup(dThreadingImplementationID impl, dMutexGroupID mutex_group);
42 static void LockMutexGroupMutex(dThreadingImplementationID impl, dMutexGroupID mutex_group, dmutexindex_t mutex_index);
43 // static int TryLockMutexGroupMutex(dThreadingImplementationID impl, dMutexGroupID mutex_group, dmutexindex_t mutex_index);
44 static void UnlockMutexGroupMutex(dThreadingImplementationID impl, dMutexGroupID mutex_group, dmutexindex_t mutex_index);
45
46 static dCallWaitID AllocThreadedCallWait(dThreadingImplementationID impl);
47 static void ResetThreadedCallWait(dThreadingImplementationID impl, dCallWaitID call_wait);
48 static void FreeThreadedCallWait(dThreadingImplementationID impl, dCallWaitID call_wait);
49
50 static void PostThreadedCall(
51 dThreadingImplementationID impl, int *out_summary_fault/*=NULL*/,
52 dCallReleaseeID *out_post_releasee/*=NULL*/, ddependencycount_t dependencies_count, dCallReleaseeID dependent_releasee/*=NULL*/,
53 dCallWaitID call_wait/*=NULL*/,
54 dThreadedCallFunction *call_func, void *call_context, dcallindex_t instance_index,
55 const char *call_name/*=NULL*/);
56 static void AlterThreadedCallDependenciesCount(
57 dThreadingImplementationID impl, dCallReleaseeID target_releasee,
58 ddependencychange_t dependencies_count_change);
59 static void WaitThreadedCall(
60 dThreadingImplementationID impl, int *out_wait_status/*=NULL*/,
61 dCallWaitID call_wait, const dThreadedWaitTime *timeout_time_ptr/*=NULL*/,
62 const char *wait_name/*=NULL*/);
63
64 static unsigned RetrieveThreadingThreadCount(dThreadingImplementationID impl);
65 static int PreallocateResourcesForThreadedCalls(dThreadingImplementationID impl, ddependencycount_t max_simultaneous_calls_estimate);
66
67
68 static const dxThreadingFunctionsInfo g_builtin_threading_functions =
69 {
70 sizeof(dxThreadingFunctionsInfo), // unsigned struct_size;
71
72 &AllocMutexGroup, // dMutexGroupAllocFunction *alloc_mutex_group;
73 &FreeMutexGroup, // dMutexGroupFreeFunction *free_mutex_group;
74 &LockMutexGroupMutex, // dMutexGroupMutexLockFunction *lock_group_mutex;
75 &UnlockMutexGroupMutex, // dMutexGroupMutexUnlockFunction *unlock_group_mutex;
76
77 &AllocThreadedCallWait, // dThreadedCallWaitAllocFunction *alloc_call_wait;
78 &ResetThreadedCallWait, // dThreadedCallWaitResetFunction *reset_call_wait;
79 &FreeThreadedCallWait, // dThreadedCallWaitFreeFunction *free_call_wait;
80
81 &PostThreadedCall, // dThreadedCallPostFunction *post_call;
82 &AlterThreadedCallDependenciesCount, // dThreadedCallDependenciesCountAlterFunction *alter_call_dependencies_count;
83 &WaitThreadedCall, // dThreadedCallWaitFunction *wait_call;
84
85 &RetrieveThreadingThreadCount, // dThreadingImplThreadCountRetrieveFunction *retrieve_thread_count;
86 &PreallocateResourcesForThreadedCalls, // dThreadingImplResourcesForCallsPreallocateFunction *preallocate_resources_for_calls;
87
88 // &TryLockMutexGroupMutex, // dMutexGroupMutexTryLockFunction *trylock_group_mutex;
89 };
90
91
dThreadingAllocateSelfThreadedImplementation()92 /*extern */dThreadingImplementationID dThreadingAllocateSelfThreadedImplementation()
93 {
94 dxSelfThreadedThreading *threading = new dxSelfThreadedThreading();
95
96 if (threading != NULL && !threading->InitializeObject())
97 {
98 delete threading;
99 threading = NULL;
100 }
101
102 dxIThreadingImplementation *impl = threading;
103 return (dThreadingImplementationID)impl;
104 }
105
dThreadingAllocateMultiThreadedImplementation()106 /*extern */dThreadingImplementationID dThreadingAllocateMultiThreadedImplementation()
107 {
108 #if dBUILTIN_THREADING_IMPL_ENABLED
109 dxMultiThreadedThreading *threading = new dxMultiThreadedThreading();
110
111 if (threading != NULL && !threading->InitializeObject())
112 {
113 delete threading;
114 threading = NULL;
115 }
116 #else
117 dxIThreadingImplementation *threading = NULL;
118 #endif // #if dBUILTIN_THREADING_IMPL_ENABLED
119
120 dxIThreadingImplementation *impl = threading;
121 return (dThreadingImplementationID)impl;
122 }
123
dThreadingImplementationGetFunctions(dThreadingImplementationID impl)124 /*extern */const dThreadingFunctionsInfo *dThreadingImplementationGetFunctions(dThreadingImplementationID impl)
125 {
126 #if dBUILTIN_THREADING_IMPL_ENABLED
127 dAASSERT(impl != NULL);
128 #endif // #if dBUILTIN_THREADING_IMPL_ENABLED
129
130 const dThreadingFunctionsInfo *functions = NULL;
131
132 #if !dBUILTIN_THREADING_IMPL_ENABLED
133 if (impl != NULL)
134 #endif // #if !dBUILTIN_THREADING_IMPL_ENABLED
135 {
136 functions = &g_builtin_threading_functions;
137 }
138
139 return functions;
140 }
141
dThreadingImplementationShutdownProcessing(dThreadingImplementationID impl)142 /*extern */void dThreadingImplementationShutdownProcessing(dThreadingImplementationID impl)
143 {
144 #if dBUILTIN_THREADING_IMPL_ENABLED
145 dAASSERT(impl != NULL);
146 #endif // #if dBUILTIN_THREADING_IMPL_ENABLED
147
148 #if !dBUILTIN_THREADING_IMPL_ENABLED
149 if (impl != NULL)
150 #endif // #if !dBUILTIN_THREADING_IMPL_ENABLED
151 {
152 ((dxIThreadingImplementation *)impl)->ShutdownProcessing();
153 }
154 }
155
dThreadingImplementationCleanupForRestart(dThreadingImplementationID impl)156 /*extern */void dThreadingImplementationCleanupForRestart(dThreadingImplementationID impl)
157 {
158 #if dBUILTIN_THREADING_IMPL_ENABLED
159 dAASSERT(impl != NULL);
160 #endif // #if dBUILTIN_THREADING_IMPL_ENABLED
161
162 #if !dBUILTIN_THREADING_IMPL_ENABLED
163 if (impl != NULL)
164 #endif // #if !dBUILTIN_THREADING_IMPL_ENABLED
165 {
166 ((dxIThreadingImplementation *)impl)->CleanupForRestart();
167 }
168 }
169
dThreadingFreeImplementation(dThreadingImplementationID impl)170 /*extern */void dThreadingFreeImplementation(dThreadingImplementationID impl)
171 {
172 if (impl != NULL)
173 {
174 ((dxIThreadingImplementation *)impl)->FreeInstance();
175 }
176 }
177
178
dExternalThreadingServeMultiThreadedImplementation(dThreadingImplementationID impl,dThreadReadyToServeCallback * readiness_callback,void * callback_context)179 /*extern */void dExternalThreadingServeMultiThreadedImplementation(dThreadingImplementationID impl,
180 dThreadReadyToServeCallback *readiness_callback/*=NULL*/, void *callback_context/*=NULL*/)
181 {
182 #if dBUILTIN_THREADING_IMPL_ENABLED
183 dAASSERT(impl != NULL);
184 #endif // #if dBUILTIN_THREADING_IMPL_ENABLED
185
186 #if !dBUILTIN_THREADING_IMPL_ENABLED
187 if (impl != NULL)
188 #endif // #if !dBUILTIN_THREADING_IMPL_ENABLED
189 {
190 ((dxIThreadingImplementation *)impl)->StickToJobsProcessing(readiness_callback, callback_context);
191 }
192 }
193
194
195 //////////////////////////////////////////////////////////////////////////
196
AllocMutexGroup(dThreadingImplementationID impl,dmutexindex_t Mutex_count,const char * const * Mutex_names_ptr)197 static dMutexGroupID AllocMutexGroup(dThreadingImplementationID impl, dmutexindex_t Mutex_count, const char *const *Mutex_names_ptr/*=NULL*/)
198 {
199 dIMutexGroup *mutex_group = ((dxIThreadingImplementation *)impl)->AllocMutexGroup(Mutex_count);
200 return (dMutexGroupID)mutex_group;
201 }
202
FreeMutexGroup(dThreadingImplementationID impl,dMutexGroupID mutex_group)203 static void FreeMutexGroup(dThreadingImplementationID impl, dMutexGroupID mutex_group)
204 {
205 ((dxIThreadingImplementation *)impl)->FreeMutexGroup((dIMutexGroup *)mutex_group);
206 }
207
LockMutexGroupMutex(dThreadingImplementationID impl,dMutexGroupID mutex_group,dmutexindex_t mutex_index)208 static void LockMutexGroupMutex(dThreadingImplementationID impl, dMutexGroupID mutex_group, dmutexindex_t mutex_index)
209 {
210 ((dxIThreadingImplementation *)impl)->LockMutexGroupMutex((dIMutexGroup *)mutex_group, mutex_index);
211 }
212
213 // static int TryLockMutexGroupMutex(dThreadingImplementationID impl, dMutexGroupID mutex_group, dmutexindex_t mutex_index)
214 // {
215 // bool trylock_result = ((dxIThreadingImplementation *)impl)->TryLockMutexGroupMutex((dIMutexGroup *)mutex_group, mutex_index);
216 // return trylock_result;
217 // }
218
UnlockMutexGroupMutex(dThreadingImplementationID impl,dMutexGroupID mutex_group,dmutexindex_t mutex_index)219 static void UnlockMutexGroupMutex(dThreadingImplementationID impl, dMutexGroupID mutex_group, dmutexindex_t mutex_index)
220 {
221 ((dxIThreadingImplementation *)impl)->UnlockMutexGroupMutex((dIMutexGroup *)mutex_group, mutex_index);
222 }
223
224
AllocThreadedCallWait(dThreadingImplementationID impl)225 static dCallWaitID AllocThreadedCallWait(dThreadingImplementationID impl)
226 {
227 dxICallWait *call_wait = ((dxIThreadingImplementation *)impl)->AllocACallWait();
228 return (dCallWaitID)call_wait;
229 }
230
ResetThreadedCallWait(dThreadingImplementationID impl,dCallWaitID call_wait)231 static void ResetThreadedCallWait(dThreadingImplementationID impl, dCallWaitID call_wait)
232 {
233 ((dxIThreadingImplementation *)impl)->ResetACallWait((dxICallWait *)call_wait);
234 }
235
FreeThreadedCallWait(dThreadingImplementationID impl,dCallWaitID call_wait)236 static void FreeThreadedCallWait(dThreadingImplementationID impl, dCallWaitID call_wait)
237 {
238 ((dxIThreadingImplementation *)impl)->FreeACallWait((dxICallWait *)call_wait);
239 }
240
241
PostThreadedCall(dThreadingImplementationID impl,int * out_summary_fault,dCallReleaseeID * out_post_releasee,ddependencycount_t dependencies_count,dCallReleaseeID dependent_releasee,dCallWaitID call_wait,dThreadedCallFunction * call_func,void * call_context,dcallindex_t instance_index,const char * call_name)242 static void PostThreadedCall(
243 dThreadingImplementationID impl, int *out_summary_fault/*=NULL*/,
244 dCallReleaseeID *out_post_releasee/*=NULL*/, ddependencycount_t dependencies_count, dCallReleaseeID dependent_releasee/*=NULL*/,
245 dCallWaitID call_wait/*=NULL*/,
246 dThreadedCallFunction *call_func, void *call_context, dcallindex_t instance_index,
247 const char *call_name/*=NULL*/)
248 {
249 ((dxIThreadingImplementation *)impl)->ScheduleNewJob(out_summary_fault, out_post_releasee,
250 dependencies_count, dependent_releasee, (dxICallWait *)call_wait, call_func, call_context, instance_index);
251 }
252
AlterThreadedCallDependenciesCount(dThreadingImplementationID impl,dCallReleaseeID target_releasee,ddependencychange_t dependencies_count_change)253 static void AlterThreadedCallDependenciesCount(
254 dThreadingImplementationID impl, dCallReleaseeID target_releasee,
255 ddependencychange_t dependencies_count_change)
256 {
257 ((dxIThreadingImplementation *)impl)->AlterJobDependenciesCount(target_releasee, dependencies_count_change);
258 }
259
WaitThreadedCall(dThreadingImplementationID impl,int * out_wait_status,dCallWaitID call_wait,const dThreadedWaitTime * timeout_time_ptr,const char * wait_name)260 static void WaitThreadedCall(
261 dThreadingImplementationID impl, int *out_wait_status/*=NULL*/,
262 dCallWaitID call_wait, const dThreadedWaitTime *timeout_time_ptr/*=NULL*/,
263 const char *wait_name/*=NULL*/)
264 {
265 ((dxIThreadingImplementation *)impl)->WaitJobCompletion(out_wait_status, (dxICallWait *)call_wait, timeout_time_ptr);
266 }
267
268
RetrieveThreadingThreadCount(dThreadingImplementationID impl)269 static unsigned RetrieveThreadingThreadCount(dThreadingImplementationID impl)
270 {
271 return ((dxIThreadingImplementation *)impl)->RetrieveActiveThreadsCount();
272 }
273
PreallocateResourcesForThreadedCalls(dThreadingImplementationID impl,ddependencycount_t max_simultaneous_calls_estimate)274 static int PreallocateResourcesForThreadedCalls(dThreadingImplementationID impl, ddependencycount_t max_simultaneous_calls_estimate)
275 {
276 return ((dxIThreadingImplementation *)impl)->PreallocateJobInfos(max_simultaneous_calls_estimate);
277 }
278
279
280