threading.h 17 KB

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