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