Threads.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : WWAudio *
  23. * *
  24. * $Archive:: /Commando/Code/WWAudio/Threads.cpp $Modtime:: 7/17/99 3:32p $*
  25. * *
  26. * $Revision:: 9 $*
  27. * *
  28. *---------------------------------------------------------------------------------------------*
  29. * Functions: *
  30. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  31. #include "Threads.h"
  32. #include "refcount.h"
  33. #include "Utils.h"
  34. #include <Process.h>
  35. #include "wwdebug.h"
  36. #include "systimer.h"
  37. ///////////////////////////////////////////////////////////////////////////////////////////
  38. // Static member initialization
  39. ///////////////////////////////////////////////////////////////////////////////////////////
  40. WWAudioThreadsClass::DELAYED_RELEASE_INFO * WWAudioThreadsClass::m_ReleaseListHead = NULL;
  41. CriticalSectionClass WWAudioThreadsClass::m_ListMutex;
  42. HANDLE WWAudioThreadsClass::m_hDelayedReleaseThread = (HANDLE)-1;
  43. HANDLE WWAudioThreadsClass::m_hDelayedReleaseEvent = (HANDLE)-1;
  44. CriticalSectionClass WWAudioThreadsClass::m_CriticalSection;
  45. bool WWAudioThreadsClass::m_IsFlushing = false;
  46. ///////////////////////////////////////////////////////////////////////////////////////////
  47. //
  48. // WWAudioThreadsClass
  49. //
  50. ///////////////////////////////////////////////////////////////////////////////////////////
  51. WWAudioThreadsClass::WWAudioThreadsClass (void)
  52. {
  53. return ;
  54. }
  55. ///////////////////////////////////////////////////////////////////////////////////////////
  56. //
  57. // ~WWAudioThreadsClass
  58. //
  59. ///////////////////////////////////////////////////////////////////////////////////////////
  60. WWAudioThreadsClass::~WWAudioThreadsClass (void)
  61. {
  62. return ;
  63. }
  64. ///////////////////////////////////////////////////////////////////////////////////////////
  65. //
  66. // Create_Delayed_Release_Thread
  67. //
  68. ///////////////////////////////////////////////////////////////////////////////////////////
  69. HANDLE
  70. WWAudioThreadsClass::Create_Delayed_Release_Thread (LPVOID param)
  71. {
  72. //
  73. // If the thread isn't already running, then
  74. //
  75. if (m_hDelayedReleaseThread == (HANDLE)-1) {
  76. m_hDelayedReleaseEvent = ::CreateEvent (NULL, FALSE, FALSE, NULL);
  77. m_hDelayedReleaseThread = (HANDLE)::_beginthread (Delayed_Release_Thread_Proc, 0, param);
  78. }
  79. return m_hDelayedReleaseThread;
  80. }
  81. ///////////////////////////////////////////////////////////////////////////////////////////
  82. //
  83. // End_Delayed_Release_Thread
  84. //
  85. ///////////////////////////////////////////////////////////////////////////////////////////
  86. void
  87. WWAudioThreadsClass::End_Delayed_Release_Thread (DWORD timeout)
  88. {
  89. //
  90. // If the thread is running, then wait for it to finish
  91. //
  92. if (m_hDelayedReleaseThread != (HANDLE)-1) {
  93. ::SetEvent (m_hDelayedReleaseEvent);
  94. ::WaitForSingleObject (m_hDelayedReleaseThread, timeout);
  95. m_hDelayedReleaseEvent = (HANDLE)-1;
  96. m_hDelayedReleaseThread = (HANDLE)-1;
  97. }
  98. return ;
  99. }
  100. ///////////////////////////////////////////////////////////////////////////////////////////
  101. //
  102. // Add_Delayed_Release_Object
  103. //
  104. ///////////////////////////////////////////////////////////////////////////////////////////
  105. void
  106. WWAudioThreadsClass::Add_Delayed_Release_Object
  107. (
  108. RefCountClass * object,
  109. DWORD delay
  110. )
  111. {
  112. if (m_IsFlushing) {
  113. REF_PTR_RELEASE (object);
  114. } else {
  115. //
  116. // Make sure we have a thread running that will handle
  117. // the operation for us.
  118. //
  119. if (m_hDelayedReleaseThread == (HANDLE)-1) {
  120. Create_Delayed_Release_Thread ();
  121. }
  122. //
  123. // Wait for the release thread to finish using the
  124. // list pointer
  125. //
  126. {
  127. CriticalSectionClass::LockClass lock(m_ListMutex);
  128. //
  129. // Create a new delay-information structure and
  130. // add it to our list
  131. //
  132. DELAYED_RELEASE_INFO *info = new DELAYED_RELEASE_INFO;
  133. info->object = object;
  134. info->time = TIMEGETTIME () + delay;
  135. info->next = m_ReleaseListHead;
  136. info->prev = NULL;
  137. if (info->next != NULL) {
  138. info->next->prev = info;
  139. }
  140. m_ReleaseListHead = info;
  141. }
  142. }
  143. return ;
  144. }
  145. ///////////////////////////////////////////////////////////////////////////////////////////
  146. //
  147. // Flush_Delayed_Release_Objects
  148. //
  149. ///////////////////////////////////////////////////////////////////////////////////////////
  150. void
  151. WWAudioThreadsClass::Flush_Delayed_Release_Objects (void)
  152. {
  153. CriticalSectionClass::LockClass lock(m_ListMutex);
  154. m_IsFlushing = true;
  155. //
  156. // Loop through all the objects in our delay list, and
  157. // free them now.
  158. //
  159. DELAYED_RELEASE_INFO *info = NULL;
  160. DELAYED_RELEASE_INFO *next = NULL;
  161. for (info = m_ReleaseListHead; info != NULL; info = next) {
  162. next = info->next;
  163. //
  164. // Free the object
  165. //
  166. REF_PTR_RELEASE (info->object);
  167. SAFE_DELETE (info);
  168. }
  169. m_ReleaseListHead = NULL;
  170. return ;
  171. }
  172. ///////////////////////////////////////////////////////////////////////////////////////////
  173. //
  174. // Delayed_Release_Thread_Proc
  175. //
  176. ///////////////////////////////////////////////////////////////////////////////////////////
  177. void __cdecl
  178. WWAudioThreadsClass::Delayed_Release_Thread_Proc (LPVOID /*param*/)
  179. {
  180. const DWORD base_timeout = 2000;
  181. DWORD timeout = base_timeout + rand () % 1000;
  182. //
  183. // Keep looping forever until we are singalled to quit (or an error occurs)
  184. //
  185. while (::WaitForSingleObject (m_hDelayedReleaseEvent, timeout) == WAIT_TIMEOUT) {
  186. {
  187. CriticalSectionClass::LockClass lock(m_ListMutex);
  188. //
  189. // Loop through all the objects in our delay list, and
  190. // free any that have expired.
  191. //
  192. DWORD current_time = TIMEGETTIME ();
  193. DELAYED_RELEASE_INFO *curr = NULL;
  194. DELAYED_RELEASE_INFO *prev = NULL;
  195. DELAYED_RELEASE_INFO *next = NULL;
  196. for (curr = m_ReleaseListHead; curr != NULL; curr = next) {
  197. next = curr->next;
  198. prev = curr->prev;
  199. //
  200. // If the time has expired, free the object
  201. //
  202. if (current_time >= curr->time) {
  203. //
  204. // Unlink the object
  205. //
  206. if (curr == m_ReleaseListHead) {
  207. m_ReleaseListHead = next;
  208. }
  209. if (prev != NULL) {
  210. prev->next = next;
  211. }
  212. if (next != NULL) {
  213. next->prev = prev;
  214. }
  215. //
  216. // Free the object
  217. //
  218. REF_PTR_RELEASE (curr->object);
  219. SAFE_DELETE (curr);
  220. }
  221. }
  222. }
  223. //
  224. // To avoid 'periodic' releases, randomize our timeout
  225. //
  226. timeout = base_timeout + rand () % 1000;
  227. }
  228. Flush_Delayed_Release_Objects ();
  229. return ;
  230. }
  231. /*
  232. ///////////////////////////////////////////////////////////////////////////////////////////
  233. //
  234. // Begin_Modify_List
  235. //
  236. ///////////////////////////////////////////////////////////////////////////////////////////
  237. bool
  238. WWAudioThreadsClass::Begin_Modify_List (void)
  239. {
  240. bool retval = false;
  241. //
  242. // Wait for up to one second to modify the list object
  243. //
  244. if (m_ListMutex != NULL) {
  245. retval = (::WaitForSingleObject (m_ListMutex, 1000) == WAIT_OBJECT_0);
  246. WWASSERT (retval);
  247. }
  248. return retval;
  249. }
  250. ///////////////////////////////////////////////////////////////////////////////////////////
  251. //
  252. // End_Modify_List
  253. //
  254. ///////////////////////////////////////////////////////////////////////////////////////////
  255. void
  256. WWAudioThreadsClass::End_Modify_List (void)
  257. {
  258. //
  259. // Release this thread's hold on the mutex object.
  260. //
  261. if (m_ListMutex != NULL) {
  262. ::ReleaseMutex (m_ListMutex);
  263. }
  264. return ;
  265. }
  266. */