Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

265 lines
6.8 KiB

  1. /*******************************Module*Header*********************************\
  2. * Module Name: support.c
  3. *
  4. * MultiMedia Systems MCIWAVE DLL
  5. *
  6. * Created: 27-Feb-1992
  7. * Author: ROBINSP
  8. *
  9. * History:
  10. *
  11. * Copyright (c) 1985-1996 Microsoft Corporation
  12. *
  13. \******************************************************************************/
  14. #define UNICODE
  15. #include <windows.h>
  16. #include <mciwave.h>
  17. STATICDT CRITICAL_SECTION CritSec;
  18. #if DBG
  19. STATICDT UINT cCritSec = 0;
  20. DWORD dwCritSecOwner = 0;
  21. #endif
  22. /*************************************************************************
  23. *
  24. * Cut-down critical section stuff
  25. *
  26. * This critical section is used to simulate windows tasking
  27. * The owner of the critical section runs exclusively in this
  28. * DLL.
  29. *
  30. * At the front of each function request the critical section is
  31. * grabbed and only release on mmYield or TaskBlock.
  32. *
  33. * Extra 'tasks' (threads) per device hold the critical section when
  34. * they are working.
  35. *
  36. * This method has been used to simplify porting the code from
  37. * windows. A rewrite would use a different mechanism.
  38. *
  39. ************************************************************************/
  40. VOID InitCrit(VOID)
  41. {
  42. InitializeCriticalSection(&CritSec);
  43. }
  44. VOID DeleteCrit(VOID)
  45. {
  46. DeleteCriticalSection(&CritSec);
  47. }
  48. #if DBG
  49. VOID DbgEnterCrit(UINT ln, LPCSTR lpszFile)
  50. {
  51. BOOL fPossibleWait;
  52. if (dwCritSecOwner) {
  53. dprintf3(("Critical section owned by thread %x", dwCritSecOwner));
  54. fPossibleWait = TRUE;
  55. } else {
  56. fPossibleWait = FALSE;
  57. }
  58. EnterCriticalSection(&CritSec);
  59. if (fPossibleWait) {
  60. dprintf2(("...entered critical section after possible wait"));
  61. }
  62. if (!cCritSec++) {
  63. // This is the first time into the critcal section
  64. dwCritSecOwner = GetCurrentThreadId();
  65. dprintf3(("...entered critical section (%d) at line %d in file %s", cCritSec, ln, lpszFile));
  66. } else {
  67. dprintf1(("Reentering critical section, count = %d", cCritSec));
  68. WinAssert(0);
  69. // Note: if the memory allocation stuff starts to be synchronised
  70. // then this assertion becomes invalid.
  71. }
  72. }
  73. #else
  74. VOID EnterCrit(VOID)
  75. {
  76. EnterCriticalSection(&CritSec);
  77. }
  78. #endif
  79. VOID LeaveCrit(VOID)
  80. {
  81. #if DBG
  82. if (!--cCritSec) {
  83. // Relinquishing control of the critcal section
  84. dwCritSecOwner = 0;
  85. dprintf2(("...relinquished critical section (%d)",cCritSec));
  86. } else {
  87. dprintf3(("Leaving critical section, count = %d", cCritSec));
  88. }
  89. #endif
  90. LeaveCriticalSection(&CritSec);
  91. }
  92. /*************************************************************************
  93. *
  94. * @doc MCIWAVE
  95. *
  96. * @func UINT | TaskBlock | This function blocks the current
  97. * task context if its event count is 0.
  98. *
  99. * @rdesc Returns the message value of the signal sent.
  100. *
  101. ************************************************************************/
  102. UINT TaskBlock(VOID)
  103. {
  104. MSG msg;
  105. dprintf3(("Thread %x blocking", GetCurrentThreadId()));
  106. LeaveCrit();
  107. /*
  108. * Loop until we get the message we want
  109. */
  110. for (;;) {
  111. /*
  112. * Retrieve any message for task
  113. */
  114. GetMessage(&msg, NULL, 0, 0);
  115. /*
  116. * If the message is for a window dispatch it
  117. */
  118. if (msg.hwnd != NULL) {
  119. DispatchMessage(&msg);
  120. } else {
  121. if (msg.message != WM_USER &&
  122. msg.message != WTM_STATECHANGE) {
  123. dprintf1(("Got thread message %8X", msg.message));
  124. }
  125. //
  126. // Because MCIWAVE background task can't cope with getting
  127. // random(?) messages like MM_WIM_DATA because it thinks that
  128. // WM_USER IS its MM_WIM_DATA. Let the expected WM_USER
  129. // messages go through, but trap the MM_WIM_DATA so that
  130. // MCIWAVE's buffers don't get all messed up.
  131. //
  132. if (msg.message != MM_WIM_DATA)
  133. break;
  134. }
  135. }
  136. dprintf3(("TaskBlock returning with message 0x%x", msg.message));
  137. EnterCrit();
  138. return msg.message;
  139. }
  140. /*************************************************************************
  141. *
  142. * @doc MCIWAVE
  143. *
  144. * @func BOOL | TaskSignal | This function signals the specified
  145. * task, incrementing its event count and unblocking
  146. * it.
  147. *
  148. * @parm HANDLE | h | Task handle. For predictable results, get the
  149. * task handle from <f mmGetCurrentTask>.
  150. *
  151. * @parm UINT | Msg | Signal message to send.
  152. *
  153. * @rdesc Returns TRUE if the signal was sent, else FALSE if the message
  154. * queue was full.
  155. *
  156. * @xref mmTaskBlock mmTaskCreate
  157. *
  158. * @comm For predictable results, must only be called from a task
  159. * created with <f mmTaskCreate>.
  160. *
  161. ************************************************************************/
  162. BOOL TaskSignal(DWORD h, UINT Msg)
  163. {
  164. #ifdef DBG
  165. BOOL fErr;
  166. dprintf2(("Signalling Thread %x", (ULONG)h));
  167. fErr = PostThreadMessage(h, Msg, 0, 0);
  168. if (!fErr) {
  169. dprintf1(("Error %d signalling Thread %x", GetLastError(), (ULONG)h));
  170. }
  171. return(fErr);
  172. #else
  173. return PostThreadMessage(h, Msg, 0, 0);
  174. #endif
  175. }
  176. /*************************************************************************
  177. *
  178. * @doc MCIWAVE
  179. *
  180. * @func VOID | TaskWaitComplete | This function waits for the
  181. * specified task to terminate.
  182. *
  183. * @parm HANDLE | h | Task handle. For predictable results, get the
  184. * task handle from <f mmGetCurrentTask>.
  185. *
  186. * @rdesc No return code
  187. *
  188. ************************************************************************/
  189. VOID TaskWaitComplete(HANDLE h)
  190. {
  191. UINT Rc;
  192. LeaveCrit();
  193. /* Wait (no timeout) for thread to complete */
  194. Rc = WaitForSingleObject(h, INFINITE);
  195. if (Rc != 0) {
  196. dprintf(("Error terminating thread - WaitForSingleObject returned non-zero !!!"));
  197. }
  198. /* Note that the handle must be freed by us */
  199. CloseHandle(h);
  200. EnterCrit();
  201. }
  202. #if DBG
  203. /*************************************************************************
  204. *
  205. * @doc MCIWAVE
  206. *
  207. * @func VOID | mmYield | This function checks that we are in the
  208. * critical section before Yielding. If we are then the
  209. * critical section is reentered after yielding.
  210. *
  211. * @parm <t>PWAVEDESC<d> | pwd |
  212. * Pointer to the wave device descriptor.
  213. *
  214. * @rdesc No return code
  215. *
  216. ************************************************************************/
  217. VOID mmDbgYield(
  218. PWAVEDESC pwd,
  219. UINT ln,
  220. LPCSTR lpszFile)
  221. {
  222. if (GetCurrentThreadId() != dwCritSecOwner) {
  223. dprintf1(("mmYield called while not in the critical section from line %d in file %s", ln, lpszFile));
  224. }
  225. CheckIn();
  226. LeaveCrit();
  227. CheckOut();
  228. Sleep(10);
  229. EnterCrit();
  230. }
  231. #endif