Threads.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. /*
  2. ** Command & Conquer Generals Zero Hour(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:: 5 $*
  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. ///////////////////////////////////////////////////////////////////////////////////////////
  37. // Static member initialization
  38. ///////////////////////////////////////////////////////////////////////////////////////////
  39. WWAudioThreadsClass::DELAYED_RELEASE_INFO * WWAudioThreadsClass::m_ReleaseListHead = NULL;
  40. CriticalSectionClass WWAudioThreadsClass::m_ListMutex;
  41. HANDLE WWAudioThreadsClass::m_hDelayedReleaseThread = (HANDLE)-1;
  42. HANDLE WWAudioThreadsClass::m_hDelayedReleaseEvent = (HANDLE)-1;
  43. CriticalSectionClass WWAudioThreadsClass::m_CriticalSection;
  44. bool WWAudioThreadsClass::m_IsShuttingDown = false;
  45. ///////////////////////////////////////////////////////////////////////////////////////////
  46. //
  47. // WWAudioThreadsClass
  48. //
  49. ///////////////////////////////////////////////////////////////////////////////////////////
  50. WWAudioThreadsClass::WWAudioThreadsClass (void)
  51. {
  52. return ;
  53. }
  54. ///////////////////////////////////////////////////////////////////////////////////////////
  55. //
  56. // ~WWAudioThreadsClass
  57. //
  58. ///////////////////////////////////////////////////////////////////////////////////////////
  59. WWAudioThreadsClass::~WWAudioThreadsClass (void)
  60. {
  61. return ;
  62. }
  63. ///////////////////////////////////////////////////////////////////////////////////////////
  64. //
  65. // Create_Delayed_Release_Thread
  66. //
  67. ///////////////////////////////////////////////////////////////////////////////////////////
  68. HANDLE
  69. WWAudioThreadsClass::Create_Delayed_Release_Thread (LPVOID param)
  70. {
  71. //
  72. // If the thread isn't already running, then
  73. //
  74. if (m_hDelayedReleaseThread == (HANDLE)-1) {
  75. m_hDelayedReleaseEvent = ::CreateEvent (NULL, FALSE, FALSE, NULL);
  76. m_hDelayedReleaseThread = (HANDLE)::_beginthread (Delayed_Release_Thread_Proc, 0, param);
  77. }
  78. return m_hDelayedReleaseThread;
  79. }
  80. ///////////////////////////////////////////////////////////////////////////////////////////
  81. //
  82. // End_Delayed_Release_Thread
  83. //
  84. ///////////////////////////////////////////////////////////////////////////////////////////
  85. void
  86. WWAudioThreadsClass::End_Delayed_Release_Thread (DWORD timeout)
  87. {
  88. m_IsShuttingDown = true;
  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_IsShuttingDown) {
  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 = W3DNEW DELAYED_RELEASE_INFO;
  133. info->object = object;
  134. info->time = ::GetTickCount () + delay;
  135. info->next = m_ReleaseListHead;
  136. m_ReleaseListHead = info;
  137. }
  138. }
  139. return ;
  140. }
  141. ///////////////////////////////////////////////////////////////////////////////////////////
  142. //
  143. // Flush_Delayed_Release_Objects
  144. //
  145. ///////////////////////////////////////////////////////////////////////////////////////////
  146. void
  147. WWAudioThreadsClass::Flush_Delayed_Release_Objects (void)
  148. {
  149. CriticalSectionClass::LockClass lock(m_CriticalSection);
  150. //
  151. // Loop through all the objects in our delay list, and
  152. // free them now.
  153. //
  154. DELAYED_RELEASE_INFO *info = NULL;
  155. DELAYED_RELEASE_INFO *next = NULL;
  156. for (info = m_ReleaseListHead; info != NULL; info = next) {
  157. next = info->next;
  158. //
  159. // Free the object
  160. //
  161. REF_PTR_RELEASE (info->object);
  162. SAFE_DELETE (info);
  163. }
  164. m_ReleaseListHead = NULL;
  165. return ;
  166. }
  167. ///////////////////////////////////////////////////////////////////////////////////////////
  168. //
  169. // Delayed_Release_Thread_Proc
  170. //
  171. ///////////////////////////////////////////////////////////////////////////////////////////
  172. void __cdecl
  173. WWAudioThreadsClass::Delayed_Release_Thread_Proc (LPVOID /*param*/)
  174. {
  175. const DWORD base_timeout = 2000;
  176. DWORD timeout = base_timeout + rand () % 1000;
  177. //
  178. // Keep looping forever until we are singalled to quit (or an error occurs)
  179. //
  180. while (::WaitForSingleObject (m_hDelayedReleaseEvent, timeout) == WAIT_TIMEOUT) {
  181. {
  182. CriticalSectionClass::LockClass lock(m_ListMutex);
  183. //
  184. // Loop through all the objects in our delay list, and
  185. // free any that have expired.
  186. //
  187. DWORD current_time = ::GetTickCount ();
  188. DELAYED_RELEASE_INFO *curr = NULL;
  189. DELAYED_RELEASE_INFO *prev = NULL;
  190. DELAYED_RELEASE_INFO *next = NULL;
  191. for (curr = m_ReleaseListHead; curr != NULL; curr = next) {
  192. next = curr->next;
  193. //
  194. // If the time has expired, free the object
  195. //
  196. if (current_time >= curr->time) {
  197. //
  198. // Unlink the object
  199. //
  200. if (prev == NULL) {
  201. m_ReleaseListHead = next;
  202. } else {
  203. prev->next = next;
  204. }
  205. //
  206. // Free the object
  207. //
  208. REF_PTR_RELEASE (curr->object);
  209. SAFE_DELETE (curr);
  210. } else {
  211. prev = curr;
  212. }
  213. }
  214. }
  215. //
  216. // To avoid 'periodic' releases, randomize our timeout
  217. //
  218. timeout = base_timeout + rand () % 1000;
  219. }
  220. Flush_Delayed_Release_Objects ();
  221. return ;
  222. }
  223. /*
  224. ///////////////////////////////////////////////////////////////////////////////////////////
  225. //
  226. // Begin_Modify_List
  227. //
  228. ///////////////////////////////////////////////////////////////////////////////////////////
  229. bool
  230. WWAudioThreadsClass::Begin_Modify_List (void)
  231. {
  232. bool retval = false;
  233. //
  234. // Wait for up to one second to modify the list object
  235. //
  236. if (m_ListMutex != NULL) {
  237. retval = (::WaitForSingleObject (m_ListMutex, 1000) == WAIT_OBJECT_0);
  238. WWASSERT (retval);
  239. }
  240. return retval;
  241. }
  242. ///////////////////////////////////////////////////////////////////////////////////////////
  243. //
  244. // End_Modify_List
  245. //
  246. ///////////////////////////////////////////////////////////////////////////////////////////
  247. void
  248. WWAudioThreadsClass::End_Modify_List (void)
  249. {
  250. //
  251. // Release this thread's hold on the mutex object.
  252. //
  253. if (m_ListMutex != NULL) {
  254. ::ReleaseMutex (m_ListMutex);
  255. }
  256. return ;
  257. }
  258. */