]> de.git.xonotic.org Git - xonotic/xonotic.git/blob - misc/builddeps/linux64/ode/include/ode/threading.h
9602b8ffdba3277582eaf9948b10d46a04d97320
[xonotic/xonotic.git] / misc / builddeps / linux64 / ode / include / ode / threading.h
1 /*************************************************************************
2  *                                                                       *
3  * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith.       *
4  * All rights reserved.  Email: russ@q12.org   Web: www.q12.org          *
5  *                                                                       *
6  * Threading support header file.                                        *
7  * Copyright (C) 2011-2019 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  *   ODE threading support interfaces   
29  */
30
31
32 #ifndef _ODE_THREADING_H_
33 #define _ODE_THREADING_H_
34
35 #include <ode/odeconfig.h>
36 // Include <time.h> since time_t is used and it is not available by default in some OSes
37 #include <time.h>
38
39
40 #ifdef __cplusplus
41 extern "C" {
42 #endif
43
44
45 struct dxThreadingImplementation;
46 typedef struct dxThreadingImplementation *dThreadingImplementationID;
47
48 typedef unsigned dmutexindex_t;
49 struct dxMutexGroup;
50 typedef struct dxMutexGroup *dMutexGroupID;
51
52
53 #define dTHREADING_THREAD_COUNT_UNLIMITED       0U
54
55
56
57 /**
58  * @brief Allocates a group of muteces.
59  *
60  * The Mutex allocated do not need to support recursive locking.
61  *
62  * The Mutex names are provided to aid in debugging and thread state tracking.
63  *
64  * @param impl Threading implementation ID
65  * @param Mutex_count Number of Mutex to create
66  * @Mutex_names_ptr Pointer to optional Mutex names array to be associated with individual Mutex
67  * @returns MutexGroup ID or NULL if error occurred.
68  *
69  * @ingroup threading
70  * @see dMutexGroupFreeFunction
71  * @see dMutexGroupMutexLockFunction
72  * @see dMutexGroupMutexUnlockFunction
73  */
74 typedef dMutexGroupID dMutexGroupAllocFunction (dThreadingImplementationID impl, dmutexindex_t Mutex_count, const char *const *Mutex_names_ptr/*=NULL*/);
75
76 /**
77  * @brief Deletes a group of muteces.
78  *
79  * @param impl Threading implementation ID
80  * @param mutex_group Mutex group to deallocate
81  *
82  * @ingroup threading
83  * @see dMutexGroupAllocFunction
84  * @see dMutexGroupMutexLockFunction
85  * @see dMutexGroupMutexUnlockFunction
86  */
87 typedef void dMutexGroupFreeFunction (dThreadingImplementationID impl, dMutexGroupID mutex_group);
88
89 /**
90  * @brief Locks a mutex in a group of muteces.
91  *
92  * The function is to block execution until requested mutex can be locked.
93  *
94  * Note: Mutex provided may not support recursive locking. Calling this function
95  * while mutex is already locked by current thread will result in unpredictable behavior.
96  *
97  * @param impl Threading implementation ID
98  * @param mutex_group Mutex group to use for locking
99  * @param mutex_index The index of mutex to be locked (0..Mutex_count - 1)
100  *
101  * @ingroup threading
102  * @see dMutexGroupAllocFunction
103  * @see dMutexGroupFreeFunction
104  * @see dMutexGroupMutexUnlockFunction
105  */
106 typedef void dMutexGroupMutexLockFunction (dThreadingImplementationID impl, dMutexGroupID mutex_group, dmutexindex_t mutex_index);
107
108 /**
109  * @brief Attempts to lock a mutex in a group of muteces.
110  *
111  * The function is to lock the requested mutex if it is unoccupied or 
112  * immediately return failure if mutex is already locked by other thread.
113  *
114  * Note: Mutex provided may not support recursive locking. Calling this function
115  * while mutex is already locked by current thread will result in unpredictable behavior.
116  *
117  * @param impl Threading implementation ID
118  * @param mutex_group Mutex group to use for locking
119  * @param mutex_index The index of mutex to be locked (0..Mutex_count - 1)
120  * @returns 1 for success (mutex is locked) and 0 for failure (mutex is not locked)
121  *
122  * @ingroup threading
123  * @see dMutexGroupAllocFunction
124  * @see dMutexGroupFreeFunction
125  * @see dMutexGroupMutexLockFunction
126  * @see dMutexGroupMutexUnlockFunction
127  */
128 /* typedef int dMutexGroupMutexTryLockFunction (dThreadingImplementationID impl, dMutexGroupID mutex_group, dmutexindex_t mutex_index);*/
129
130 /**
131  * @brief Unlocks a mutex in a group of muteces.
132  *
133  * The function is to unlock the given mutex provided it had been locked before.
134  *
135  * @param impl Threading implementation ID
136  * @param mutex_group Mutex group to use for unlocking
137  * @param mutex_index The index of mutex to be unlocked (0..Mutex_count - 1)
138  *
139  * @ingroup threading
140  * @see dMutexGroupAllocFunction
141  * @see dMutexGroupFreeFunction
142  * @see dMutexGroupMutexLockFunction
143  */
144 typedef void dMutexGroupMutexUnlockFunction (dThreadingImplementationID impl, dMutexGroupID mutex_group, dmutexindex_t mutex_index);
145
146
147 struct dxCallReleasee;
148 typedef struct dxCallReleasee *dCallReleaseeID;
149
150 struct dxCallWait;
151 typedef struct dxCallWait *dCallWaitID;
152
153 typedef dsizeint ddependencycount_t;
154 typedef ddiffint ddependencychange_t;
155 typedef dsizeint dcallindex_t;
156 typedef int dThreadedCallFunction(void *call_context, dcallindex_t instance_index, 
157   dCallReleaseeID this_releasee);
158
159 typedef struct dxThreadedWaitTime
160 {
161   time_t          wait_sec;
162   unsigned long   wait_nsec;
163
164 } dThreadedWaitTime;
165
166
167 /**
168  * @brief Allocates a Wait ID that can be used to wait for a call.
169  *
170  * @param impl Threading implementation ID
171  * @returns Wait ID or NULL if error occurred
172  *
173  * @ingroup threading
174  * @see dThreadedCallWaitResetFunction
175  * @see dThreadedCallWaitFreeFunction
176  * @see dThreadedCallPostFunction
177  * @see dThreadedCallWaitFunction
178  */
179 typedef dCallWaitID dThreadedCallWaitAllocFunction(dThreadingImplementationID impl);
180
181 /**
182  * @brief Resets a Wait ID so that it could be used to wait for another call.
183  *
184  * @param impl Threading implementation ID
185  * @param call_wait Wait ID to reset
186  *
187  * @ingroup threading
188  * @see dThreadedCallWaitAllocFunction
189  * @see dThreadedCallWaitFreeFunction
190  * @see dThreadedCallPostFunction
191  * @see dThreadedCallWaitFunction
192  */
193 typedef void dThreadedCallWaitResetFunction(dThreadingImplementationID impl, dCallWaitID call_wait);
194
195 /**
196  * @brief Frees a Wait ID.
197  *
198  * @param impl Threading implementation ID
199  * @param call_wait Wait ID to delete
200  *
201  * @ingroup threading
202  * @see dThreadedCallWaitAllocFunction
203  * @see dThreadedCallPostFunction
204  * @see dThreadedCallWaitFunction
205  */
206 typedef void dThreadedCallWaitFreeFunction(dThreadingImplementationID impl, dCallWaitID call_wait);
207
208
209 /**
210  * @brief Post a function to be called in another thread.
211  *
212  * A call is scheduled to be executed asynchronously.
213  *
214  * A @a out_summary_fault variable can be provided for call to accumulate any
215  * possible faults from its execution and execution of any possible sub-calls.
216  * This variable gets result that @a call_func returns. Also, if dependent calls 
217  * are executed after the call already exits, the variable is also going to be 
218  * updated with results of all those calls before control is released to master.
219  *
220  * @a out_post_releasee parameter receives a value of @c dCallReleaseeID that can 
221  * later be used for @a dependent_releasee while scheduling sub-calls to make 
222  * current call depend on them. The value is only returned if @a dependencies_count 
223  * is not zero (i.e. if any dependencies are expected at all). The call is not going 
224  * to start until all its dependencies complete.
225  *
226  * In case if number of dependencies is unknown in advance 1 can be passed on call
227  * scheduling. Then @c dThreadedCallDependenciesCountAlterFunction can be used to
228  * add one more extra dependencies before scheduling each subcall. And then, after
229  * all sub-calls had been scheduled, @c dThreadedCallDependenciesCountAlterFunction
230  * can be used again to subtract initial extra dependency from total number.
231  * Adding one dependency in advance is necessary to obtain releasee ID and to make 
232  * sure the call will not start and will not terminate before all sub-calls are scheduled.
233  *
234  * Extra dependencies can also be added from the call itself after it has already 
235  * been started (with parameter received in @c dThreadedCallFunction). 
236  * In that case those dependencies will start immediately or after call returns 
237  * but the call's master will not be released/notified until all additional
238  * dependencies complete. This can be used to schedule sub-calls from a call and 
239  * then pass own job to another sub-call dependent on those initial sub-calls.
240  *
241  * By using @ call_wait it is possible to assign a Wait ID that can later 
242  * be passed into @c dThreadedCallWaitFunction to wait for call completion.
243  *
244  * If @a call_name is available (and it should!) the string must remain valid until
245  * after call completion. In most cases this should be a static string literal.
246  * 
247  * Since the function is an analogue of normal method call it is not supposed to fail.
248  * Any complications with resource allocation on call scheduling should be 
249  * anticipated, avoided and worked around by implementation.
250  *
251  * @param impl Threading implementation ID
252  * @param out_summary_fault Optional pointer to variable to be set to 1 if function 
253  *        call (or any sub-call) fails internally, or 0 if all calls return success
254  * @param out_post_releasee Optional pointer to variable to receive releasee ID 
255  *        associated with the call
256  * @param dependencies_count Number of dependencies that are going to reference
257  *        this call as dependent releasee
258  * @param dependent_releasee Optional releasee ID to reference with this call
259  * @param call_wait Optional Wait ID that can later be used to wait for the call
260  * @param call_func Pointer to function to be called
261  * @param call_context Context parameter to be passed into the call
262  * @param instance_index Index parameter to be passed into the call
263  * @param call_name Optional name to be associated with the call (for debugging and state tracking)
264  *
265  * @ingroup threading
266  * @see dThreadedCallWaitFunction
267  * @see dThreadedCallDependenciesCountAlterFunction
268  * @see dThreadingImplResourcesForCallsPreallocateFunction
269  */
270 typedef void dThreadedCallPostFunction(dThreadingImplementationID impl, int *out_summary_fault/*=NULL*/, 
271   dCallReleaseeID *out_post_releasee/*=NULL*/, ddependencycount_t dependencies_count, dCallReleaseeID dependent_releasee/*=NULL*/, 
272   dCallWaitID call_wait/*=NULL*/, 
273   dThreadedCallFunction *call_func, void *call_context, dcallindex_t instance_index, 
274   const char *call_name/*=NULL*/);
275
276 /**
277  * @brief Add or remove extra dependencies from call that has been scheduled
278  * or is in process of execution.
279  *
280  * Extra dependencies can be added to a call if exact number of sub-calls is
281  * not known in advance at the moment the call is scheduled. Also, some dependencies
282  * can be removed if sub-calls were planned but then dropped. 
283  *
284  * In case if total dependency count of a call reaches zero by result of invoking 
285  * this function, the call is free to start executing immediately.
286  *
287  * After the call execution had been started, any additional dependencies can only
288  * be added from the call function itself!
289  *
290  * @param impl Threading implementation ID
291  * @param target_releasee ID of releasee to apply dependencies count change to
292  * @param dependencies_count_change Number of dependencies to add or remove
293  *
294  * @ingroup threading
295  * @see dThreadedCallPostFunction
296  */
297 typedef void dThreadedCallDependenciesCountAlterFunction(dThreadingImplementationID impl, dCallReleaseeID target_releasee, 
298   ddependencychange_t dependencies_count_change);
299
300 /**
301  * @brief Wait for a posted call to complete.
302  *
303  * Function blocks until a call identified by @a call_wait completes or
304  * timeout elapses.
305  *
306  * IT IS ILLEGAL TO INVOKE THIS FUNCTION FROM WITHIN A THREADED CALL!
307  * This is because doing so will block a physical thread and will require 
308  * increasing worker thread count to avoid starvation. Use call dependencies 
309  * if it is necessary make sure sub-calls have been completed instead!
310  *
311  * If @a timeout_time_ptr is NULL, the function waits without time limit. If @a timeout_time_ptr
312  * points to zero value, the function only checks status and does not block.
313  *
314  * If @a wait_name is available (and it should!) the string must remain valid for
315  * the duration of wait. In most cases this should be a static string literal.
316  * 
317  * Function is not expected to return failures caused by system call faults as 
318  * those are hardly ever possible to be handled in this case anyway. In event of 
319  * system call fault the function is supposed to terminate application.
320  *
321  * @param impl Threading implementation ID
322  * @param out_wait_status Optional pointer to variable to receive 1 if waiting succeeded
323  *        or 0 in case of timeout
324  * @param call_wait Wait ID that had been passed to scheduling a call that needs to be waited for
325  * @param timeout_time_ptr Optional pointer to time specification the wait must not
326  *        last longer than (pass NULL for infinite timeout)
327  * @param wait_name Optional name to be associated with the wait (for debugging and state tracking)
328  *
329  * @ingroup threading
330  * @see dThreadedCallPostFunction
331  */
332 typedef void dThreadedCallWaitFunction(dThreadingImplementationID impl, int *out_wait_status/*=NULL*/, 
333   dCallWaitID call_wait, const dThreadedWaitTime *timeout_time_ptr/*=NULL*/, 
334   const char *wait_name/*=NULL*/);
335
336 /**
337  * @brief Retrieve number of active threads that serve the implementation.
338  *
339  * @param impl Threading implementation ID
340  * @returns Number of active threads
341  *
342  * @ingroup threading
343  */
344 typedef unsigned dThreadingImplThreadCountRetrieveFunction(dThreadingImplementationID impl);
345
346 /**
347  * @brief Preallocate resources to handle posted calls.
348  *
349  * The function is intended to make sure enough resources is preallocated for the
350  * implementation to be able to handle posted calls. Then @c max_simultaneous_calls_estimate
351  * is an estimate of how many posted calls can potentially be active or scheduled 
352  * at the same time. The value is usually derived from the way the calls are posted 
353  * in library code and dependencies between them.
354  * 
355  * @warning While working on an implementation be prepared that the estimate provided 
356  * yet rarely but theoretically can be exceeded due to unpredictability of thread execution.
357  *
358  * This function is normally going to be invoked by library each time it is entered
359  * from outside to do the job but before any threaded calls are going to be posted.
360  *
361  * @param impl Threading implementation ID
362  * @param max_simultaneous_calls_estimate An estimated number of calls that can be posted simultaneously
363  * @returns 1 or 0 to indicate success or failure
364  *
365  * @ingroup threading
366  * @see dThreadedCallPostFunction
367  */
368 typedef int dThreadingImplResourcesForCallsPreallocateFunction(dThreadingImplementationID impl, 
369   ddependencycount_t max_simultaneous_calls_estimate);
370
371
372 /**
373  * @brief An interface structure with function pointers to be provided by threading implementation.
374  */
375 typedef struct dxThreadingFunctionsInfo
376 {
377   unsigned struct_size;
378   
379   dMutexGroupAllocFunction *alloc_mutex_group;
380   dMutexGroupFreeFunction *free_mutex_group;
381   dMutexGroupMutexLockFunction *lock_group_mutex;
382   dMutexGroupMutexUnlockFunction *unlock_group_mutex;
383
384   dThreadedCallWaitAllocFunction *alloc_call_wait;
385   dThreadedCallWaitResetFunction *reset_call_wait;
386   dThreadedCallWaitFreeFunction *free_call_wait;
387
388   dThreadedCallPostFunction *post_call;
389   dThreadedCallDependenciesCountAlterFunction *alter_call_dependencies_count;
390   dThreadedCallWaitFunction *wait_call;
391
392   dThreadingImplThreadCountRetrieveFunction *retrieve_thread_count;
393   dThreadingImplResourcesForCallsPreallocateFunction *preallocate_resources_for_calls; 
394
395   /* 
396    * Beware of Jon Watte's anger if you dare to uncomment this!
397    * May cryptic text below be you a warning!
398    * Стародавні легенди розказують, що кожного сміливця, хто наважиться порушити табу 
399    * і відкрити заборонений код, спіткає страшне прокляття і він відразу почне робити 
400    * одні лиш помилки.
401    *
402    * dMutexGroupMutexTryLockFunction *trylock_group_mutex;
403    */
404
405 } dThreadingFunctionsInfo;
406
407
408 #ifdef __cplusplus
409 }
410 #endif
411
412 #endif /* #ifndef _ODE_THREADING_H_ */