threading_impl_templates.h 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265
  1. /*************************************************************************
  2. * *
  3. * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. *
  4. * All rights reserved. Email: [email protected] Web: www.q12.org *
  5. * *
  6. * Threading implementation templates file. *
  7. * Copyright (C) 2011-2012 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. * Job list and Mutex group implementation templates for built-in threading
  28. * support provider.
  29. */
  30. #ifndef _ODE_THREADING_IMPL_TEMPLATES_H_
  31. #define _ODE_THREADING_IMPL_TEMPLATES_H_
  32. #include <ode/common.h>
  33. #include <ode/memory.h>
  34. #include <ode/threading.h>
  35. #include "objects.h"
  36. #include <new>
  37. #define dMAKE_JOBINSTANCE_RELEASEE(job_instance) ((dCallReleaseeID)(job_instance))
  38. #define dMAKE_RELEASEE_JOBINSTANCE(releasee) ((dxThreadedJobInfo *)(releasee))
  39. template <class tThreadMutex>
  40. class dxtemplateMutexGroup
  41. {
  42. private:
  43. dxtemplateMutexGroup() {}
  44. ~dxtemplateMutexGroup() {}
  45. public:
  46. static dxtemplateMutexGroup<tThreadMutex> *AllocateInstance(dmutexindex_t Mutex_count);
  47. static void FreeInstance(dxtemplateMutexGroup<tThreadMutex> *mutex_group);
  48. private:
  49. bool InitializeMutexArray(dmutexindex_t Mutex_count);
  50. void FinalizeMutexArray(dmutexindex_t Mutex_count);
  51. public:
  52. void LockMutex(dmutexindex_t mutex_index) { dIASSERT(mutex_index < m_un.m_mutex_count); m_Mutex_array[mutex_index].LockMutex(); }
  53. bool TryLockMutex(dmutexindex_t mutex_index) { dIASSERT(mutex_index < m_un.m_mutex_count); return m_Mutex_array[mutex_index].TryLockMutex(); }
  54. void UnlockMutex(dmutexindex_t mutex_index) { dIASSERT(mutex_index < m_un.m_mutex_count); m_Mutex_array[mutex_index].UnlockMutex(); }
  55. private:
  56. union
  57. {
  58. dmutexindex_t m_mutex_count;
  59. unsigned long m_reserved_for_allignment[2];
  60. } m_un;
  61. tThreadMutex m_Mutex_array[1];
  62. };
  63. template<class tThreadWakeup>
  64. class dxtemplateCallWait:
  65. public dBase
  66. {
  67. public:
  68. dxtemplateCallWait() {}
  69. ~dxtemplateCallWait() { DoFinalizeObject(); }
  70. bool InitializeObject() { return DoInitializeObject(); }
  71. private:
  72. bool DoInitializeObject() { return m_wait_wakeup.InitializeObject(); }
  73. void DoFinalizeObject() { /* Do nothing */ }
  74. public:
  75. typedef dxtemplateCallWait<tThreadWakeup> dxCallWait;
  76. public:
  77. void ResetTheWait() { m_wait_wakeup.ResetWakeup(); }
  78. void SignalTheWait() { m_wait_wakeup.WakeupAllThreads(); }
  79. bool PerformWaiting(const dThreadedWaitTime *timeout_time_ptr/*=NULL*/) { return m_wait_wakeup.WaitWakeup(timeout_time_ptr); }
  80. public:
  81. static void AbstractSignalTheWait(void *wait_wakeup_ptr) { ((dxCallWait *)wait_wakeup_ptr)->SignalTheWait(); }
  82. private:
  83. tThreadWakeup m_wait_wakeup;
  84. };
  85. #if dBUILTIN_THREADING_IMPL_ENABLED
  86. template<class tThreadWakeup, class tAtomicsProvider, const bool tatomic_test_required>
  87. class dxtemplateThreadedLull
  88. {
  89. public:
  90. dxtemplateThreadedLull(): m_registrant_count(0), m_alarm_wakeup() {}
  91. ~dxtemplateThreadedLull() { dIASSERT(m_registrant_count == 0); DoFinalizeObject(); }
  92. bool InitializeObject() { return DoInitializeObject(); }
  93. private:
  94. bool DoInitializeObject() { return m_alarm_wakeup.InitializeObject(); }
  95. void DoFinalizeObject() { /* Do nothing */ }
  96. private:
  97. typedef typename tAtomicsProvider::atomicord_t atomicord_t;
  98. public:
  99. void RegisterToLull() { tAtomicsProvider::IncrementTargetNoRet(&m_registrant_count); }
  100. void WaitForLullAlarm() { dIASSERT(m_registrant_count != 0); m_alarm_wakeup.WaitWakeup(NULL); }
  101. void UnregisterFromLull() { tAtomicsProvider::DecrementTargetNoRet(&m_registrant_count); }
  102. void SignalLullAlarmIfAnyRegistrants()
  103. {
  104. if (tatomic_test_required ? (tAtomicsProvider::QueryTargetValue(&m_registrant_count) != 0) : (m_registrant_count != 0))
  105. {
  106. m_alarm_wakeup.WakeupAThread();
  107. }
  108. }
  109. private:
  110. atomicord_t m_registrant_count;
  111. tThreadWakeup m_alarm_wakeup;
  112. };
  113. #endif // #if dBUILTIN_THREADING_IMPL_ENABLED
  114. struct dxThreadedJobInfo:
  115. public dBase
  116. {
  117. dxThreadedJobInfo() {}
  118. explicit dxThreadedJobInfo(void *): m_next_job(NULL) {}
  119. void AssignJobData(ddependencycount_t dependencies_count, dxThreadedJobInfo *dependent_job, void *call_wait,
  120. int *fault_accumulator_ptr, dThreadedCallFunction *call_function, void *call_context, dcallindex_t call_index)
  121. {
  122. m_dependencies_count = dependencies_count;
  123. m_dependent_job = dependent_job;
  124. m_call_wait = call_wait;
  125. m_fault_accumulator_ptr = fault_accumulator_ptr;
  126. m_call_fault = 0;
  127. m_call_function = call_function;
  128. m_call_context = call_context;
  129. m_call_index = call_index;
  130. }
  131. bool InvokeCallFunction()
  132. {
  133. int call_result = m_call_function(m_call_context, m_call_index, dMAKE_JOBINSTANCE_RELEASEE(this));
  134. return call_result != 0;
  135. }
  136. dxThreadedJobInfo *m_next_job;
  137. dxThreadedJobInfo **m_prev_job_next_ptr;
  138. ddependencycount_t m_dependencies_count;
  139. dxThreadedJobInfo *m_dependent_job;
  140. void *m_call_wait;
  141. int *m_fault_accumulator_ptr;
  142. int m_call_fault;
  143. dThreadedCallFunction *m_call_function;
  144. void *m_call_context;
  145. dcallindex_t m_call_index;
  146. };
  147. template<class tThreadMutex>
  148. class dxtemplateThreadingLockHelper
  149. {
  150. public:
  151. dxtemplateThreadingLockHelper(tThreadMutex &mutex_instance): m_mutex_instance(mutex_instance), m_lock_indicator_flag(false) { LockMutex(); }
  152. ~dxtemplateThreadingLockHelper() { if (m_lock_indicator_flag) { UnlockMutex(); } }
  153. void LockMutex() { dIASSERT(!m_lock_indicator_flag); m_mutex_instance.LockMutex(); m_lock_indicator_flag = true; }
  154. void UnlockMutex() { dIASSERT(m_lock_indicator_flag); m_mutex_instance.UnlockMutex(); m_lock_indicator_flag = false; }
  155. private:
  156. tThreadMutex &m_mutex_instance;
  157. bool m_lock_indicator_flag;
  158. };
  159. template<class tThreadLull, class tThreadMutex, class tAtomicsProvider>
  160. class dxtemplateJobListContainer
  161. {
  162. public:
  163. dxtemplateJobListContainer():
  164. m_job_list(NULL),
  165. m_info_pool((atomicptr_t)NULL),
  166. m_pool_access_lock(),
  167. m_list_access_lock(),
  168. m_info_wait_lull(),
  169. m_info_count_known_to_be_preallocated(0)
  170. {
  171. }
  172. ~dxtemplateJobListContainer()
  173. {
  174. dIASSERT(m_job_list == NULL); // Would not it be nice to wait for jobs to complete before deleting the list?
  175. FreeJobInfoPoolInfos();
  176. DoFinalizeObject();
  177. }
  178. bool InitializeObject() { return DoInitializeObject(); }
  179. private:
  180. bool DoInitializeObject() { return m_pool_access_lock.InitializeObject() && m_list_access_lock.InitializeObject() && m_info_wait_lull.InitializeObject(); }
  181. void DoFinalizeObject() { /* Do nothing */ }
  182. public:
  183. typedef tAtomicsProvider dxAtomicsProvider;
  184. typedef typename tAtomicsProvider::atomicord_t atomicord_t;
  185. typedef typename tAtomicsProvider::atomicptr_t atomicptr_t;
  186. typedef tThreadMutex dxThreadMutex;
  187. typedef dxtemplateThreadingLockHelper<tThreadMutex> dxMutexLockHelper;
  188. typedef void dWaitSignallingFunction(void *job_call_wait);
  189. public:
  190. dxThreadedJobInfo *ReleaseAJobAndPickNextPendingOne(
  191. dxThreadedJobInfo *job_to_release, bool job_result, dWaitSignallingFunction *wait_signal_proc_ptr,
  192. bool &out_last_job_flag);
  193. private:
  194. dxThreadedJobInfo *PickNextPendingJob(bool &out_last_job_flag);
  195. void ReleaseAJob(dxThreadedJobInfo *job_instance, bool job_result, dWaitSignallingFunction *wait_signal_proc_ptr);
  196. public:
  197. inline dxThreadedJobInfo *AllocateJobInfoFromPool();
  198. void QueueJobForProcessing(dxThreadedJobInfo *job_instance);
  199. void AlterJobProcessingDependencies(dxThreadedJobInfo *job_instance, ddependencychange_t dependencies_count_change,
  200. bool &out_job_has_become_ready);
  201. private:
  202. inline ddependencycount_t SmartAddJobDependenciesCount(dxThreadedJobInfo *job_instance, ddependencychange_t dependencies_count_change);
  203. inline void InsertJobInfoIntoListHead(dxThreadedJobInfo *job_instance);
  204. inline void RemoveJobInfoFromList(dxThreadedJobInfo *job_instance);
  205. dxThreadedJobInfo *ExtractJobInfoFromPoolOrAllocate();
  206. inline void ReleaseJobInfoIntoPool(dxThreadedJobInfo *job_instance);
  207. private:
  208. void FreeJobInfoPoolInfos();
  209. public:
  210. bool EnsureNumberOfJobInfosIsPreallocated(ddependencycount_t required_info_count);
  211. private:
  212. bool DoPreallocateJobInfos(ddependencycount_t required_info_count);
  213. public:
  214. bool IsJobListReadyForShutdown() const { return m_job_list == NULL; }
  215. private:
  216. dxThreadedJobInfo *m_job_list;
  217. volatile atomicptr_t m_info_pool; // dxThreadedJobInfo *
  218. tThreadMutex m_pool_access_lock;
  219. tThreadMutex m_list_access_lock;
  220. tThreadLull m_info_wait_lull;
  221. ddependencycount_t m_info_count_known_to_be_preallocated;
  222. };
  223. typedef void (dxThreadReadyToServeCallback)(void *callback_context);
  224. #if dBUILTIN_THREADING_IMPL_ENABLED
  225. template<class tThreadWakeup, class tJobListContainer>
  226. class dxtemplateJobListThreadedHandler
  227. {
  228. public:
  229. dxtemplateJobListThreadedHandler(tJobListContainer *list_container_ptr):
  230. m_job_list_ptr(list_container_ptr),
  231. m_processing_wakeup(),
  232. m_active_thread_count(0),
  233. m_shutdown_requested(0)
  234. {
  235. }
  236. ~dxtemplateJobListThreadedHandler()
  237. {
  238. dIASSERT(m_active_thread_count == 0);
  239. DoFinalizeObject();
  240. }
  241. bool InitializeObject() { return DoInitializeObject(); }
  242. private:
  243. bool DoInitializeObject() { return m_processing_wakeup.InitializeObject(); }
  244. void DoFinalizeObject() { /* Do nothing */ }
  245. public:
  246. typedef dxtemplateCallWait<tThreadWakeup> dxCallWait;
  247. public:
  248. inline void ProcessActiveJobAddition();
  249. inline void PrepareForWaitingAJobCompletion();
  250. public:
  251. inline unsigned RetrieveActiveThreadsCount();
  252. inline void StickToJobsProcessing(dxThreadReadyToServeCallback *readiness_callback/*=NULL*/, void *callback_context/*=NULL*/);
  253. private:
  254. void PerformJobProcessingUntilShutdown();
  255. void PerformJobProcessingSession();
  256. void BlockAsIdleThread();
  257. void ActivateAnIdleThread();
  258. public:
  259. inline void ShutdownProcessing();
  260. inline void CleanupForRestart();
  261. private:
  262. bool IsShutdownRequested() const { return m_shutdown_requested != 0; }
  263. private:
  264. typedef typename tJobListContainer::dxAtomicsProvider dxAtomicsProvider;
  265. typedef typename tJobListContainer::atomicord_t atomicord_t;
  266. atomicord_t GetActiveThreadsCount() const { return m_active_thread_count; }
  267. void RegisterAsActiveThread() { dxAtomicsProvider::template AddValueToTarget<sizeof(atomicord_t)>((volatile void *)&m_active_thread_count, 1); }
  268. void UnregisterAsActiveThread() { dxAtomicsProvider::template AddValueToTarget<sizeof(atomicord_t)>((volatile void *)&m_active_thread_count, -1); }
  269. private:
  270. tJobListContainer *m_job_list_ptr;
  271. tThreadWakeup m_processing_wakeup;
  272. volatile atomicord_t m_active_thread_count;
  273. int m_shutdown_requested;
  274. };
  275. #endif // #if dBUILTIN_THREADING_IMPL_ENABLED
  276. template<class tThreadWakeup, class tJobListContainer>
  277. class dxtemplateJobListSelfHandler
  278. {
  279. public:
  280. dxtemplateJobListSelfHandler(tJobListContainer *list_container_ptr):
  281. m_job_list_ptr(list_container_ptr)
  282. {
  283. }
  284. ~dxtemplateJobListSelfHandler()
  285. {
  286. // Do nothing
  287. }
  288. bool InitializeObject() { return true; }
  289. public:
  290. typedef dxtemplateCallWait<tThreadWakeup> dxCallWait;
  291. public:
  292. inline void ProcessActiveJobAddition();
  293. inline void PrepareForWaitingAJobCompletion();
  294. public:
  295. inline unsigned RetrieveActiveThreadsCount();
  296. inline void StickToJobsProcessing(dxThreadReadyToServeCallback *readiness_callback/*=NULL*/, void *callback_context/*=NULL*/);
  297. private:
  298. void PerformJobProcessingUntilExhaustion();
  299. void PerformJobProcessingSession();
  300. public:
  301. inline void ShutdownProcessing();
  302. inline void CleanupForRestart();
  303. private:
  304. tJobListContainer *m_job_list_ptr;
  305. };
  306. struct dIMutexGroup;
  307. struct dxICallWait;
  308. class dxIThreadingImplementation
  309. {
  310. public:
  311. virtual void FreeInstance() = 0;
  312. public:
  313. virtual dIMutexGroup *AllocMutexGroup(dmutexindex_t Mutex_count) = 0;
  314. virtual void FreeMutexGroup(dIMutexGroup *mutex_group) = 0;
  315. virtual void LockMutexGroupMutex(dIMutexGroup *mutex_group, dmutexindex_t mutex_index) = 0;
  316. // virtual bool TryLockMutexGroupMutex(dIMutexGroup *mutex_group, dmutexindex_t mutex_index) = 0;
  317. virtual void UnlockMutexGroupMutex(dIMutexGroup *mutex_group, dmutexindex_t mutex_index) = 0;
  318. public:
  319. virtual dxICallWait *AllocACallWait() = 0;
  320. virtual void ResetACallWait(dxICallWait *call_wait) = 0;
  321. virtual void FreeACallWait(dxICallWait *call_wait) = 0;
  322. public:
  323. virtual bool PreallocateJobInfos(ddependencycount_t max_simultaneous_calls_estimate) = 0;
  324. virtual void ScheduleNewJob(int *fault_accumulator_ptr/*=NULL*/,
  325. dCallReleaseeID *out_post_releasee_ptr/*=NULL*/, ddependencycount_t dependencies_count, dCallReleaseeID dependent_releasee/*=NULL*/,
  326. dxICallWait *call_wait/*=NULL*/,
  327. dThreadedCallFunction *call_func, void *call_context, dcallindex_t instance_index) = 0;
  328. virtual void AlterJobDependenciesCount(dCallReleaseeID target_releasee, ddependencychange_t dependencies_count_change) = 0;
  329. virtual void WaitJobCompletion(int *out_wait_status_ptr/*=NULL*/,
  330. dxICallWait *call_wait, const dThreadedWaitTime *timeout_time_ptr/*=NULL*/) = 0;
  331. public:
  332. virtual unsigned RetrieveActiveThreadsCount() = 0;
  333. virtual void StickToJobsProcessing(dxThreadReadyToServeCallback *readiness_callback/*=NULL*/, void *callback_context/*=NULL*/) = 0;
  334. virtual void ShutdownProcessing() = 0;
  335. virtual void CleanupForRestart() = 0;
  336. };
  337. template<class tJobListContainer, class tJobListHandler>
  338. class dxtemplateThreadingImplementation:
  339. public dBase,
  340. public dxIThreadingImplementation
  341. {
  342. public:
  343. dxtemplateThreadingImplementation():
  344. dBase(),
  345. m_list_container(),
  346. m_list_handler(&m_list_container)
  347. {
  348. }
  349. virtual ~dxtemplateThreadingImplementation()
  350. {
  351. DoFinalizeObject();
  352. }
  353. bool InitializeObject() { return DoInitializeObject(); }
  354. private:
  355. bool DoInitializeObject() { return m_list_container.InitializeObject() && m_list_handler.InitializeObject(); }
  356. void DoFinalizeObject() { /* Do nothing */ }
  357. protected:
  358. virtual void FreeInstance();
  359. private:
  360. typedef dxtemplateMutexGroup<typename tJobListContainer::dxThreadMutex> dxMutexGroup;
  361. typedef typename tJobListHandler::dxCallWait dxCallWait;
  362. protected:
  363. virtual dIMutexGroup *AllocMutexGroup(dmutexindex_t Mutex_count);
  364. virtual void FreeMutexGroup(dIMutexGroup *mutex_group);
  365. virtual void LockMutexGroupMutex(dIMutexGroup *mutex_group, dmutexindex_t mutex_index);
  366. // virtual bool TryLockMutexGroupMutex(dIMutexGroup *mutex_group, dmutexindex_t mutex_index);
  367. virtual void UnlockMutexGroupMutex(dIMutexGroup *mutex_group, dmutexindex_t mutex_index);
  368. protected:
  369. virtual dxICallWait *AllocACallWait();
  370. virtual void ResetACallWait(dxICallWait *call_wait);
  371. virtual void FreeACallWait(dxICallWait *call_wait);
  372. protected:
  373. virtual bool PreallocateJobInfos(ddependencycount_t max_simultaneous_calls_estimate);
  374. virtual void ScheduleNewJob(int *fault_accumulator_ptr/*=NULL*/,
  375. dCallReleaseeID *out_post_releasee_ptr/*=NULL*/, ddependencycount_t dependencies_count, dCallReleaseeID dependent_releasee/*=NULL*/,
  376. dxICallWait *call_wait/*=NULL*/,
  377. dThreadedCallFunction *call_func, void *call_context, dcallindex_t instance_index);
  378. virtual void AlterJobDependenciesCount(dCallReleaseeID target_releasee, ddependencychange_t dependencies_count_change);
  379. virtual void WaitJobCompletion(int *out_wait_status_ptr/*=NULL*/,
  380. dxICallWait *call_wait, const dThreadedWaitTime *timeout_time_ptr/*=NULL*/);
  381. protected:
  382. virtual unsigned RetrieveActiveThreadsCount();
  383. virtual void StickToJobsProcessing(dxThreadReadyToServeCallback *readiness_callback/*=NULL*/, void *callback_context/*=NULL*/);
  384. virtual void ShutdownProcessing();
  385. virtual void CleanupForRestart();
  386. private:
  387. tJobListContainer m_list_container;
  388. tJobListHandler m_list_handler;
  389. };
  390. /************************************************************************/
  391. /* Implementation of dxtemplateMutexGroup */
  392. /************************************************************************/
  393. template<class tThreadMutex>
  394. /*static */dxtemplateMutexGroup<tThreadMutex> *dxtemplateMutexGroup<tThreadMutex>::AllocateInstance(dmutexindex_t Mutex_count)
  395. {
  396. dAASSERT(Mutex_count != 0);
  397. const dxtemplateMutexGroup<tThreadMutex> *const dummy_group = (dxtemplateMutexGroup<tThreadMutex> *)(size_t)8;
  398. const size_t size_requited = ((size_t)(&dummy_group->m_Mutex_array) - (size_t)dummy_group) + Mutex_count * sizeof(tThreadMutex);
  399. dxtemplateMutexGroup<tThreadMutex> *mutex_group = (dxtemplateMutexGroup<tThreadMutex> *)dAlloc(size_requited);
  400. if (mutex_group != NULL)
  401. {
  402. mutex_group->m_un.m_mutex_count = Mutex_count;
  403. if (!mutex_group->InitializeMutexArray(Mutex_count))
  404. {
  405. dFree((void *)mutex_group, size_requited);
  406. mutex_group = NULL;
  407. }
  408. }
  409. return mutex_group;
  410. }
  411. template<class tThreadMutex>
  412. /*static */void dxtemplateMutexGroup<tThreadMutex>::FreeInstance(dxtemplateMutexGroup<tThreadMutex> *mutex_group)
  413. {
  414. if (mutex_group != NULL)
  415. {
  416. dmutexindex_t Mutex_count = mutex_group->m_un.m_mutex_count;
  417. mutex_group->FinalizeMutexArray(Mutex_count);
  418. const size_t anyting_not_zero = 2 * sizeof(size_t);
  419. const dxtemplateMutexGroup<tThreadMutex> *const dummy_group = (dxtemplateMutexGroup<tThreadMutex> *)anyting_not_zero;
  420. const size_t size_requited = ((size_t)(&dummy_group->m_Mutex_array) - (size_t)dummy_group) + Mutex_count * sizeof(tThreadMutex);
  421. dFree((void *)mutex_group, size_requited);
  422. }
  423. }
  424. template<class tThreadMutex>
  425. bool dxtemplateMutexGroup<tThreadMutex>::InitializeMutexArray(dmutexindex_t Mutex_count)
  426. {
  427. bool any_fault = false;
  428. dmutexindex_t mutex_index = 0;
  429. for (; mutex_index != Mutex_count; ++mutex_index)
  430. {
  431. tThreadMutex *mutex_storage = m_Mutex_array + mutex_index;
  432. new(mutex_storage) tThreadMutex;
  433. if (!mutex_storage->InitializeObject())
  434. {
  435. mutex_storage->tThreadMutex::~tThreadMutex();
  436. any_fault = true;
  437. break;
  438. }
  439. }
  440. if (any_fault)
  441. {
  442. FinalizeMutexArray(mutex_index);
  443. }
  444. bool init_result = !any_fault;
  445. return init_result;
  446. }
  447. template<class tThreadMutex>
  448. void dxtemplateMutexGroup<tThreadMutex>::FinalizeMutexArray(dmutexindex_t Mutex_count)
  449. {
  450. for (dmutexindex_t mutex_index = 0; mutex_index != Mutex_count; ++mutex_index)
  451. {
  452. tThreadMutex *mutex_storage = m_Mutex_array + mutex_index;
  453. mutex_storage->tThreadMutex::~tThreadMutex();
  454. }
  455. }
  456. /************************************************************************/
  457. /* Implementation of dxtemplateJobListContainer */
  458. /************************************************************************/
  459. template<class tThreadLull, class tThreadMutex, class tAtomicsProvider>
  460. dxThreadedJobInfo *dxtemplateJobListContainer<tThreadLull, tThreadMutex, tAtomicsProvider>::ReleaseAJobAndPickNextPendingOne(
  461. dxThreadedJobInfo *job_to_release, bool job_result, dWaitSignallingFunction *wait_signal_proc_ptr, bool &out_last_job_flag)
  462. {
  463. if (job_to_release != NULL)
  464. {
  465. ReleaseAJob(job_to_release, job_result, wait_signal_proc_ptr);
  466. }
  467. dxMutexLockHelper list_access(m_list_access_lock);
  468. dxThreadedJobInfo *picked_job = PickNextPendingJob(out_last_job_flag);
  469. return picked_job;
  470. }
  471. template<class tThreadLull, class tThreadMutex, class tAtomicsProvider>
  472. dxThreadedJobInfo *dxtemplateJobListContainer<tThreadLull, tThreadMutex, tAtomicsProvider>::PickNextPendingJob(
  473. bool &out_last_job_flag)
  474. {
  475. dxThreadedJobInfo *current_job = m_job_list;
  476. bool last_job_flag = false;
  477. while (current_job != NULL)
  478. {
  479. if (current_job->m_dependencies_count == 0)
  480. {
  481. // It is OK to assign in unsafe manner - dependencies count should not be changed
  482. // after the job has become ready for execution
  483. current_job->m_dependencies_count = 1;
  484. last_job_flag = current_job->m_next_job == NULL;
  485. RemoveJobInfoFromList(current_job);
  486. break;
  487. }
  488. current_job = current_job->m_next_job;
  489. }
  490. out_last_job_flag = last_job_flag;
  491. return current_job;
  492. }
  493. template<class tThreadLull, class tThreadMutex, class tAtomicsProvider>
  494. void dxtemplateJobListContainer<tThreadLull, tThreadMutex, tAtomicsProvider>::ReleaseAJob(
  495. dxThreadedJobInfo *job_instance, bool job_result, dWaitSignallingFunction *wait_signal_proc_ptr)
  496. {
  497. dxThreadedJobInfo *current_job = job_instance;
  498. if (!job_result)
  499. {
  500. // Accumulate call fault (be careful to not reset it!!!)
  501. current_job->m_call_fault = 1;
  502. }
  503. bool job_dequeued = true;
  504. dIASSERT(current_job->m_prev_job_next_ptr == NULL);
  505. while (true)
  506. {
  507. dIASSERT(current_job->m_dependencies_count != 0);
  508. ddependencycount_t new_dependencies_count = SmartAddJobDependenciesCount(current_job, -1);
  509. if (new_dependencies_count != 0 || !job_dequeued)
  510. {
  511. break;
  512. }
  513. void *job_call_wait = current_job->m_call_wait;
  514. if (job_call_wait != NULL)
  515. {
  516. wait_signal_proc_ptr(job_call_wait);
  517. }
  518. int call_fault = current_job->m_call_fault;
  519. if (current_job->m_fault_accumulator_ptr)
  520. {
  521. *current_job->m_fault_accumulator_ptr = call_fault;
  522. }
  523. dxThreadedJobInfo *dependent_job = current_job->m_dependent_job;
  524. ReleaseJobInfoIntoPool(current_job);
  525. if (dependent_job == NULL)
  526. {
  527. break;
  528. }
  529. if (call_fault)
  530. {
  531. // Accumulate call fault (be careful to not reset it!!!)
  532. dependent_job->m_call_fault = 1;
  533. }
  534. current_job = dependent_job;
  535. job_dequeued = dependent_job->m_prev_job_next_ptr == NULL;
  536. }
  537. }
  538. template<class tThreadLull, class tThreadMutex, class tAtomicsProvider>
  539. dxThreadedJobInfo *dxtemplateJobListContainer<tThreadLull, tThreadMutex, tAtomicsProvider>::AllocateJobInfoFromPool()
  540. {
  541. // No locking is necessary
  542. dxThreadedJobInfo *job_instance = ExtractJobInfoFromPoolOrAllocate();
  543. return job_instance;
  544. }
  545. template<class tThreadLull, class tThreadMutex, class tAtomicsProvider>
  546. void dxtemplateJobListContainer<tThreadLull, tThreadMutex, tAtomicsProvider>::QueueJobForProcessing(dxThreadedJobInfo *job_instance)
  547. {
  548. dxMutexLockHelper list_access(m_list_access_lock);
  549. InsertJobInfoIntoListHead(job_instance);
  550. }
  551. template<class tThreadLull, class tThreadMutex, class tAtomicsProvider>
  552. void dxtemplateJobListContainer<tThreadLull, tThreadMutex, tAtomicsProvider>::AlterJobProcessingDependencies(dxThreadedJobInfo *job_instance, ddependencychange_t dependencies_count_change,
  553. bool &out_job_has_become_ready)
  554. {
  555. // Dependencies should not be changed when job has already become ready for execution
  556. dIASSERT(job_instance->m_dependencies_count != 0);
  557. // It's OK that access is not atomic - that is to be handled by external logic
  558. dIASSERT(dependencies_count_change < 0 ? (job_instance->m_dependencies_count >= (ddependencycount_t)(-dependencies_count_change)) : ((ddependencycount_t)(-(ddependencychange_t)job_instance->m_dependencies_count) > (ddependencycount_t)dependencies_count_change));
  559. ddependencycount_t new_dependencies_count = SmartAddJobDependenciesCount(job_instance, dependencies_count_change);
  560. out_job_has_become_ready = new_dependencies_count == 0;
  561. }
  562. template<class tThreadLull, class tThreadMutex, class tAtomicsProvider>
  563. ddependencycount_t dxtemplateJobListContainer<tThreadLull, tThreadMutex, tAtomicsProvider>::SmartAddJobDependenciesCount(
  564. dxThreadedJobInfo *job_instance, ddependencychange_t dependencies_count_change)
  565. {
  566. ddependencycount_t new_dependencies_count = tAtomicsProvider::template AddValueToTarget<sizeof(ddependencycount_t)>((volatile void *)&job_instance->m_dependencies_count, dependencies_count_change) + dependencies_count_change;
  567. return new_dependencies_count;
  568. }
  569. template<class tThreadLull, class tThreadMutex, class tAtomicsProvider>
  570. void dxtemplateJobListContainer<tThreadLull, tThreadMutex, tAtomicsProvider>::InsertJobInfoIntoListHead(
  571. dxThreadedJobInfo *job_instance)
  572. {
  573. dxThreadedJobInfo *job_list_head = m_job_list;
  574. job_instance->m_next_job = job_list_head;
  575. if (job_list_head != NULL)
  576. {
  577. job_list_head->m_prev_job_next_ptr = &job_instance->m_next_job;
  578. }
  579. job_instance->m_prev_job_next_ptr = &m_job_list;
  580. m_job_list = job_instance;
  581. }
  582. template<class tThreadLull, class tThreadMutex, class tAtomicsProvider>
  583. void dxtemplateJobListContainer<tThreadLull, tThreadMutex, tAtomicsProvider>::RemoveJobInfoFromList(
  584. dxThreadedJobInfo *job_instance)
  585. {
  586. if (job_instance->m_next_job)
  587. {
  588. job_instance->m_next_job->m_prev_job_next_ptr = job_instance->m_prev_job_next_ptr;
  589. }
  590. *job_instance->m_prev_job_next_ptr = job_instance->m_next_job;
  591. // Assign NULL to m_prev_job_next_ptr as an indicator that instance has been dequeued
  592. job_instance->m_prev_job_next_ptr = NULL;
  593. }
  594. template<class tThreadLull, class tThreadMutex, class tAtomicsProvider>
  595. dxThreadedJobInfo *dxtemplateJobListContainer<tThreadLull, tThreadMutex, tAtomicsProvider>::ExtractJobInfoFromPoolOrAllocate()
  596. {
  597. dxThreadedJobInfo *result_info;
  598. bool waited_lull = false;
  599. m_info_wait_lull.RegisterToLull();
  600. while (true)
  601. {
  602. dxThreadedJobInfo *raw_head_info = (dxThreadedJobInfo *)m_info_pool;
  603. if (raw_head_info == NULL)
  604. {
  605. result_info = new dxThreadedJobInfo();
  606. if (result_info != NULL)
  607. {
  608. break;
  609. }
  610. m_info_wait_lull.WaitForLullAlarm();
  611. waited_lull = true;
  612. }
  613. // Extraction must be locked so that other thread does not "steal" head info,
  614. // use it and then reinsert back with a different "next"
  615. dxMutexLockHelper pool_access(m_pool_access_lock);
  616. dxThreadedJobInfo *head_info = (dxThreadedJobInfo *)m_info_pool; // Head info must be re-read after mutex had been locked
  617. if (head_info != NULL)
  618. {
  619. dxThreadedJobInfo *next_info = head_info->m_next_job;
  620. if (tAtomicsProvider::CompareExchangeTargetPtr(&m_info_pool, (atomicptr_t)head_info, (atomicptr_t)next_info))
  621. {
  622. result_info = head_info;
  623. break;
  624. }
  625. }
  626. }
  627. m_info_wait_lull.UnregisterFromLull();
  628. if (waited_lull)
  629. {
  630. // It is necessary to re-signal lull alarm if current thread was waiting as
  631. // there might be other threads waiting which might have not received alarm signal.
  632. m_info_wait_lull.SignalLullAlarmIfAnyRegistrants();
  633. }
  634. return result_info;
  635. }
  636. template<class tThreadLull, class tThreadMutex, class tAtomicsProvider>
  637. void dxtemplateJobListContainer<tThreadLull, tThreadMutex, tAtomicsProvider>::ReleaseJobInfoIntoPool(
  638. dxThreadedJobInfo *job_instance)
  639. {
  640. while (true)
  641. {
  642. dxThreadedJobInfo *next_info = (dxThreadedJobInfo *)m_info_pool;
  643. job_instance->m_next_job = next_info;
  644. if (tAtomicsProvider::CompareExchangeTargetPtr(&m_info_pool, (atomicptr_t)next_info, (atomicptr_t)job_instance))
  645. {
  646. break;
  647. }
  648. }
  649. m_info_wait_lull.SignalLullAlarmIfAnyRegistrants();
  650. }
  651. template<class tThreadLull, class tThreadMutex, class tAtomicsProvider>
  652. void dxtemplateJobListContainer<tThreadLull, tThreadMutex, tAtomicsProvider>::FreeJobInfoPoolInfos()
  653. {
  654. dxThreadedJobInfo *current_info = (dxThreadedJobInfo *)m_info_pool;
  655. while (current_info != NULL)
  656. {
  657. dxThreadedJobInfo *info_save = current_info;
  658. current_info = current_info->m_next_job;
  659. delete info_save;
  660. }
  661. m_info_pool = (atomicptr_t)NULL;
  662. }
  663. template<class tThreadLull, class tThreadMutex, class tAtomicsProvider>
  664. bool dxtemplateJobListContainer<tThreadLull, tThreadMutex, tAtomicsProvider>::EnsureNumberOfJobInfosIsPreallocated(ddependencycount_t required_info_count)
  665. {
  666. bool result = required_info_count <= m_info_count_known_to_be_preallocated
  667. || DoPreallocateJobInfos(required_info_count);
  668. return result;
  669. }
  670. template<class tThreadLull, class tThreadMutex, class tAtomicsProvider>
  671. bool dxtemplateJobListContainer<tThreadLull, tThreadMutex, tAtomicsProvider>::DoPreallocateJobInfos(ddependencycount_t required_info_count)
  672. {
  673. dIASSERT(required_info_count > m_info_count_known_to_be_preallocated); // Also ensures required_info_count > 0
  674. bool allocation_failure = false;
  675. dxThreadedJobInfo *info_pool = (dxThreadedJobInfo *)m_info_pool;
  676. ddependencycount_t info_index = 0;
  677. for (dxThreadedJobInfo **current_info_ptr = &info_pool; ; )
  678. {
  679. dxThreadedJobInfo *current_info = *current_info_ptr;
  680. if (current_info == NULL)
  681. {
  682. current_info = new dxThreadedJobInfo(NULL);
  683. if (current_info == NULL)
  684. {
  685. allocation_failure = true;
  686. break;
  687. }
  688. *current_info_ptr = current_info;
  689. }
  690. if (++info_index == required_info_count)
  691. {
  692. m_info_count_known_to_be_preallocated = info_index;
  693. break;
  694. }
  695. current_info_ptr = &current_info->m_next_job;
  696. }
  697. // Make sure m_info_pool was not changed
  698. dIASSERT(m_info_pool == NULL || m_info_pool == (atomicptr_t)info_pool);
  699. m_info_pool = (atomicptr_t)info_pool;
  700. bool result = !allocation_failure;
  701. return result;
  702. }
  703. #if dBUILTIN_THREADING_IMPL_ENABLED
  704. /************************************************************************/
  705. /* Implementation of dxtemplateJobListThreadedHandler */
  706. /************************************************************************/
  707. template<class tThreadWakeup, class tJobListContainer>
  708. void dxtemplateJobListThreadedHandler<tThreadWakeup, tJobListContainer>::ProcessActiveJobAddition()
  709. {
  710. ActivateAnIdleThread();
  711. }
  712. template<class tThreadWakeup, class tJobListContainer>
  713. void dxtemplateJobListThreadedHandler<tThreadWakeup, tJobListContainer>::PrepareForWaitingAJobCompletion()
  714. {
  715. // Do nothing
  716. }
  717. template<class tThreadWakeup, class tJobListContainer>
  718. unsigned dxtemplateJobListThreadedHandler<tThreadWakeup, tJobListContainer>::RetrieveActiveThreadsCount()
  719. {
  720. return GetActiveThreadsCount();
  721. }
  722. template<class tThreadWakeup, class tJobListContainer>
  723. void dxtemplateJobListThreadedHandler<tThreadWakeup, tJobListContainer>::StickToJobsProcessing(dxThreadReadyToServeCallback *readiness_callback/*=NULL*/, void *callback_context/*=NULL*/)
  724. {
  725. RegisterAsActiveThread();
  726. if (readiness_callback != NULL)
  727. {
  728. (*readiness_callback)(callback_context);
  729. }
  730. PerformJobProcessingUntilShutdown();
  731. UnregisterAsActiveThread();
  732. }
  733. template<class tThreadWakeup, class tJobListContainer>
  734. void dxtemplateJobListThreadedHandler<tThreadWakeup, tJobListContainer>::PerformJobProcessingUntilShutdown()
  735. {
  736. while (true)
  737. {
  738. // It is expected that new jobs will not be queued any longer after shutdown had been requested
  739. if (IsShutdownRequested() && m_job_list_ptr->IsJobListReadyForShutdown())
  740. {
  741. break;
  742. }
  743. PerformJobProcessingSession();
  744. // It is expected that new jobs will not be queued any longer after shutdown had been requested
  745. if (IsShutdownRequested() && m_job_list_ptr->IsJobListReadyForShutdown())
  746. {
  747. break;
  748. }
  749. BlockAsIdleThread();
  750. }
  751. }
  752. template<class tThreadWakeup, class tJobListContainer>
  753. void dxtemplateJobListThreadedHandler<tThreadWakeup, tJobListContainer>::PerformJobProcessingSession()
  754. {
  755. dxThreadedJobInfo *current_job = NULL;
  756. bool job_result = false;
  757. while (true)
  758. {
  759. bool last_job_flag;
  760. current_job = m_job_list_ptr->ReleaseAJobAndPickNextPendingOne(current_job, job_result, &dxCallWait::AbstractSignalTheWait, last_job_flag);
  761. if (!current_job)
  762. {
  763. break;
  764. }
  765. if (!last_job_flag)
  766. {
  767. ActivateAnIdleThread();
  768. }
  769. job_result = current_job->InvokeCallFunction();
  770. }
  771. }
  772. template<class tThreadWakeup, class tJobListContainer>
  773. void dxtemplateJobListThreadedHandler<tThreadWakeup, tJobListContainer>::BlockAsIdleThread()
  774. {
  775. m_processing_wakeup.WaitWakeup(NULL);
  776. }
  777. template<class tThreadWakeup, class tJobListContainer>
  778. void dxtemplateJobListThreadedHandler<tThreadWakeup, tJobListContainer>::ActivateAnIdleThread()
  779. {
  780. m_processing_wakeup.WakeupAThread();
  781. }
  782. template<class tThreadWakeup, class tJobListContainer>
  783. void dxtemplateJobListThreadedHandler<tThreadWakeup, tJobListContainer>::ShutdownProcessing()
  784. {
  785. m_shutdown_requested = true;
  786. m_processing_wakeup.WakeupAllThreads();
  787. }
  788. template<class tThreadWakeup, class tJobListContainer>
  789. void dxtemplateJobListThreadedHandler<tThreadWakeup, tJobListContainer>::CleanupForRestart()
  790. {
  791. m_shutdown_requested = false;
  792. m_processing_wakeup.ResetWakeup();
  793. }
  794. #endif // #if dBUILTIN_THREADING_IMPL_ENABLED
  795. /************************************************************************/
  796. /* Implementation of dxtemplateJobListSelfHandler */
  797. /************************************************************************/
  798. template<class tThreadWakeup, class tJobListContainer>
  799. void dxtemplateJobListSelfHandler<tThreadWakeup, tJobListContainer>::ProcessActiveJobAddition()
  800. {
  801. // Do nothing
  802. }
  803. template<class tThreadWakeup, class tJobListContainer>
  804. void dxtemplateJobListSelfHandler<tThreadWakeup, tJobListContainer>::PrepareForWaitingAJobCompletion()
  805. {
  806. PerformJobProcessingUntilExhaustion();
  807. }
  808. template<class tThreadWakeup, class tJobListContainer>
  809. unsigned dxtemplateJobListSelfHandler<tThreadWakeup, tJobListContainer>::RetrieveActiveThreadsCount()
  810. {
  811. return 1U; // Self-Handling is always performed by a single thread
  812. }
  813. template<class tThreadWakeup, class tJobListContainer>
  814. void dxtemplateJobListSelfHandler<tThreadWakeup, tJobListContainer>::StickToJobsProcessing(dxThreadReadyToServeCallback *readiness_callback/*=NULL*/, void *callback_context/*=NULL*/)
  815. {
  816. (void)readiness_callback; // unused
  817. (void)callback_context; // unused
  818. dIASSERT(false); // This method is not expected to be called for Self-Handler
  819. }
  820. template<class tThreadWakeup, class tJobListContainer>
  821. void dxtemplateJobListSelfHandler<tThreadWakeup, tJobListContainer>::PerformJobProcessingUntilExhaustion()
  822. {
  823. PerformJobProcessingSession();
  824. }
  825. template<class tThreadWakeup, class tJobListContainer>
  826. void dxtemplateJobListSelfHandler<tThreadWakeup, tJobListContainer>::PerformJobProcessingSession()
  827. {
  828. dxThreadedJobInfo *current_job = NULL;
  829. bool job_result = false;
  830. while (true)
  831. {
  832. bool dummy_last_job_flag;
  833. current_job = m_job_list_ptr->ReleaseAJobAndPickNextPendingOne(current_job, job_result, &dxCallWait::AbstractSignalTheWait, dummy_last_job_flag);
  834. if (!current_job)
  835. {
  836. break;
  837. }
  838. job_result = current_job->InvokeCallFunction();
  839. }
  840. }
  841. template<class tThreadWakeup, class tJobListContainer>
  842. void dxtemplateJobListSelfHandler<tThreadWakeup, tJobListContainer>::ShutdownProcessing()
  843. {
  844. // Do nothing
  845. }
  846. template<class tThreadWakeup, class tJobListContainer>
  847. void dxtemplateJobListSelfHandler<tThreadWakeup, tJobListContainer>::CleanupForRestart()
  848. {
  849. // Do nothing
  850. }
  851. /************************************************************************/
  852. /* Implementation of dxtemplateThreadingImplementation */
  853. /************************************************************************/
  854. template<class tJobListContainer, class tJobListHandler>
  855. void dxtemplateThreadingImplementation<tJobListContainer, tJobListHandler>::FreeInstance()
  856. {
  857. delete this;
  858. }
  859. template<class tJobListContainer, class tJobListHandler>
  860. dIMutexGroup *dxtemplateThreadingImplementation<tJobListContainer, tJobListHandler>::AllocMutexGroup(dmutexindex_t Mutex_count)
  861. {
  862. dxMutexGroup *mutex_group = dxMutexGroup::AllocateInstance(Mutex_count);
  863. return (dIMutexGroup *)mutex_group;
  864. }
  865. template<class tJobListContainer, class tJobListHandler>
  866. void dxtemplateThreadingImplementation<tJobListContainer, tJobListHandler>::FreeMutexGroup(dIMutexGroup *mutex_group)
  867. {
  868. dxMutexGroup::FreeInstance((dxMutexGroup *)mutex_group);
  869. }
  870. template<class tJobListContainer, class tJobListHandler>
  871. void dxtemplateThreadingImplementation<tJobListContainer, tJobListHandler>::LockMutexGroupMutex(dIMutexGroup *mutex_group, dmutexindex_t mutex_index)
  872. {
  873. ((dxMutexGroup *)mutex_group)->LockMutex(mutex_index);
  874. }
  875. // template<class tJobListContainer, class tJobListHandler>
  876. // bool dxtemplateThreadingImplementation<tJobListContainer, tJobListHandler>::TryLockMutexGroupMutex(dIMutexGroup *mutex_group, dmutexindex_t mutex_index)
  877. // {
  878. // return ((dxMutexGroup *)mutex_group)->TryLockMutex(mutex_index);
  879. // }
  880. template<class tJobListContainer, class tJobListHandler>
  881. void dxtemplateThreadingImplementation<tJobListContainer, tJobListHandler>::UnlockMutexGroupMutex(dIMutexGroup *mutex_group, dmutexindex_t mutex_index)
  882. {
  883. ((dxMutexGroup *)mutex_group)->UnlockMutex(mutex_index);
  884. }
  885. template<class tJobListContainer, class tJobListHandler>
  886. dxICallWait *dxtemplateThreadingImplementation<tJobListContainer, tJobListHandler>::AllocACallWait()
  887. {
  888. dxCallWait *call_wait = new dxCallWait();
  889. if (call_wait != NULL && !call_wait->InitializeObject())
  890. {
  891. delete call_wait;
  892. call_wait = NULL;
  893. }
  894. return (dxICallWait *)call_wait;
  895. }
  896. template<class tJobListContainer, class tJobListHandler>
  897. void dxtemplateThreadingImplementation<tJobListContainer, tJobListHandler>::ResetACallWait(dxICallWait *call_wait)
  898. {
  899. ((dxCallWait *)call_wait)->ResetTheWait();
  900. }
  901. template<class tJobListContainer, class tJobListHandler>
  902. void dxtemplateThreadingImplementation<tJobListContainer, tJobListHandler>::FreeACallWait(dxICallWait *call_wait)
  903. {
  904. delete ((dxCallWait *)call_wait);
  905. }
  906. template<class tJobListContainer, class tJobListHandler>
  907. bool dxtemplateThreadingImplementation<tJobListContainer, tJobListHandler>::PreallocateJobInfos(ddependencycount_t max_simultaneous_calls_estimate)
  908. {
  909. // No multithreading protection here!
  910. // Resources are to be preallocated before jobs start to be scheduled
  911. // as otherwise there is no way to implement the preallocation.
  912. bool result = m_list_container.EnsureNumberOfJobInfosIsPreallocated(max_simultaneous_calls_estimate);
  913. return result;
  914. }
  915. template<class tJobListContainer, class tJobListHandler>
  916. void dxtemplateThreadingImplementation<tJobListContainer, tJobListHandler>::ScheduleNewJob(
  917. int *fault_accumulator_ptr/*=NULL*/,
  918. dCallReleaseeID *out_post_releasee_ptr/*=NULL*/, ddependencycount_t dependencies_count, dCallReleaseeID dependent_releasee/*=NULL*/,
  919. dxICallWait *call_wait/*=NULL*/,
  920. dThreadedCallFunction *call_func, void *call_context, dcallindex_t instance_index)
  921. {
  922. dxThreadedJobInfo *new_job = m_list_container.AllocateJobInfoFromPool();
  923. dIASSERT(new_job != NULL);
  924. new_job->AssignJobData(dependencies_count, dMAKE_RELEASEE_JOBINSTANCE(dependent_releasee), (dxCallWait *)call_wait, fault_accumulator_ptr, call_func, call_context, instance_index);
  925. if (out_post_releasee_ptr != NULL)
  926. {
  927. *out_post_releasee_ptr = dMAKE_JOBINSTANCE_RELEASEE(new_job);
  928. }
  929. m_list_container.QueueJobForProcessing(new_job);
  930. if (dependencies_count == 0)
  931. {
  932. m_list_handler.ProcessActiveJobAddition();
  933. }
  934. }
  935. template<class tJobListContainer, class tJobListHandler>
  936. void dxtemplateThreadingImplementation<tJobListContainer, tJobListHandler>::AlterJobDependenciesCount(
  937. dCallReleaseeID target_releasee, ddependencychange_t dependencies_count_change)
  938. {
  939. dIASSERT(dependencies_count_change != 0);
  940. dxThreadedJobInfo *job_instance = dMAKE_RELEASEE_JOBINSTANCE(target_releasee);
  941. bool job_has_become_ready;
  942. m_list_container.AlterJobProcessingDependencies(job_instance, dependencies_count_change, job_has_become_ready);
  943. if (job_has_become_ready)
  944. {
  945. m_list_handler.ProcessActiveJobAddition();
  946. }
  947. }
  948. template<class tJobListContainer, class tJobListHandler>
  949. void dxtemplateThreadingImplementation<tJobListContainer, tJobListHandler>::WaitJobCompletion(
  950. int *out_wait_status_ptr/*=NULL*/,
  951. dxICallWait *call_wait, const dThreadedWaitTime *timeout_time_ptr/*=NULL*/)
  952. {
  953. dIASSERT(call_wait != NULL);
  954. m_list_handler.PrepareForWaitingAJobCompletion();
  955. bool wait_status = ((dxCallWait *)call_wait)->PerformWaiting(timeout_time_ptr);
  956. dIASSERT(timeout_time_ptr != NULL || wait_status);
  957. if (out_wait_status_ptr)
  958. {
  959. *out_wait_status_ptr = wait_status;
  960. }
  961. }
  962. template<class tJobListContainer, class tJobListHandler>
  963. unsigned dxtemplateThreadingImplementation<tJobListContainer, tJobListHandler>::RetrieveActiveThreadsCount()
  964. {
  965. return m_list_handler.RetrieveActiveThreadsCount();
  966. }
  967. template<class tJobListContainer, class tJobListHandler>
  968. void dxtemplateThreadingImplementation<tJobListContainer, tJobListHandler>::StickToJobsProcessing(dxThreadReadyToServeCallback *readiness_callback/*=NULL*/, void *callback_context/*=NULL*/)
  969. {
  970. m_list_handler.StickToJobsProcessing(readiness_callback, callback_context);
  971. }
  972. template<class tJobListContainer, class tJobListHandler>
  973. void dxtemplateThreadingImplementation<tJobListContainer, tJobListHandler>::ShutdownProcessing()
  974. {
  975. m_list_handler.ShutdownProcessing();
  976. }
  977. template<class tJobListContainer, class tJobListHandler>
  978. void dxtemplateThreadingImplementation<tJobListContainer, tJobListHandler>::CleanupForRestart()
  979. {
  980. m_list_handler.CleanupForRestart();
  981. }
  982. #endif // #ifndef _ODE_THREADING_IMPL_TEMPLATES_H_