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.

341 lines
8.6 KiB

  1. /*===================================================================
  2. Microsoft Denali
  3. Microsoft Confidential.
  4. Copyright 1997 Microsoft Corporation. All Rights Reserved.
  5. Component: MTA Callback
  6. File: mtacb.cpp
  7. Owner: DmitryR
  8. This file contains the implementation of MTA callbacks
  9. ===================================================================*/
  10. #include <w3p.hxx>
  11. #include <process.h>
  12. #pragma hdrstop
  13. #include "MTAcb.h"
  14. /*===================================================================
  15. MTA Callback Thread
  16. Worker thread that implements the MTA callback functionality
  17. ===================================================================*/
  18. class CMTACallbackThread
  19. {
  20. private:
  21. DWORD m_fInited : 1; // inited?
  22. DWORD m_fCSInited : 1; // critical section inited?
  23. DWORD m_fShutdown : 1; // shutdown?
  24. CRITICAL_SECTION m_csLock; // callback critical section
  25. HANDLE m_hDoItEvent; // callback requested event
  26. HANDLE m_hDoneEvent; // callback done event
  27. HANDLE m_hThread; // thread handle
  28. PMTACALLBACK m_pMTACallback; // callback function ptr
  29. void *m_pvContext; // arg1
  30. void *m_pvContext2; // arg2
  31. HRESULT m_hrResult; // return code
  32. // The call callback from MTA thread
  33. void DoCallback()
  34. {
  35. DBG_ASSERT(m_pMTACallback);
  36. m_hrResult = (*m_pMTACallback)(m_pvContext, m_pvContext2);
  37. }
  38. // The thread function
  39. static unsigned Thread(void *pvArg)
  40. {
  41. HRESULT hr;
  42. DBG_ASSERT(pvArg);
  43. CMTACallbackThread *pThread = (CMTACallbackThread *)pvArg;
  44. hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); // MTA
  45. if (FAILED(hr))
  46. {
  47. // Bug 87857: Handle failure from CoInitialize
  48. if (hr == E_INVALIDARG)
  49. {
  50. CoUninitialize();
  51. }
  52. // This shouldnt actually fail. Not entirely clear what to do if it does
  53. DBG_ASSERT(FALSE);
  54. return hr;
  55. }
  56. while (!pThread->m_fShutdown)
  57. {
  58. DWORD dwRet = MsgWaitForMultipleObjects
  59. (
  60. 1,
  61. &(pThread->m_hDoItEvent),
  62. FALSE,
  63. INFINITE,
  64. QS_ALLINPUT
  65. );
  66. if (pThread->m_fShutdown)
  67. break;
  68. if (dwRet == WAIT_OBJECT_0)
  69. {
  70. // Event -> do the callback
  71. pThread->DoCallback();
  72. SetEvent(pThread->m_hDoneEvent);
  73. }
  74. else
  75. {
  76. // Do messages
  77. MSG msg;
  78. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  79. DispatchMessage(&msg);
  80. }
  81. }
  82. CoUninitialize();
  83. return 0;
  84. }
  85. public:
  86. // Constructor
  87. CMTACallbackThread()
  88. : m_fInited(FALSE), m_fCSInited(FALSE), m_fShutdown(FALSE),
  89. m_hDoItEvent(NULL), m_hDoneEvent(NULL), m_hThread(NULL),
  90. m_pMTACallback(NULL)
  91. {
  92. }
  93. // Destructor
  94. ~CMTACallbackThread()
  95. {
  96. // Real cleanup is in UnInit()
  97. // This is to cleanup after a bad Init()
  98. if (m_fCSInited)
  99. DeleteCriticalSection(&m_csLock);
  100. if (m_hDoItEvent)
  101. CloseHandle(m_hDoItEvent);
  102. if (m_hDoneEvent)
  103. CloseHandle(m_hDoneEvent);
  104. }
  105. // Init (real constructor)
  106. HRESULT Init()
  107. {
  108. HRESULT hr = NOERROR;
  109. if (SUCCEEDED(hr))
  110. {
  111. INITIALIZE_CRITICAL_SECTION(&m_csLock);
  112. m_fCSInited = TRUE;
  113. }
  114. if (SUCCEEDED(hr))
  115. {
  116. m_hDoItEvent = IIS_CREATE_EVENT(
  117. "CMTACallbackThread::m_hDoItEvent",
  118. this,
  119. FALSE,
  120. FALSE
  121. );
  122. if (!m_hDoItEvent)
  123. hr = E_OUTOFMEMORY;
  124. }
  125. if (SUCCEEDED(hr))
  126. {
  127. m_hDoneEvent = IIS_CREATE_EVENT(
  128. "CMTACallbackThread::m_hDoneEvent",
  129. this,
  130. FALSE,
  131. FALSE
  132. );
  133. if (!m_hDoneEvent)
  134. hr = E_OUTOFMEMORY;
  135. }
  136. // Launch the MTA thread
  137. unsigned threadId;
  138. uintptr_t ulThread = _beginthreadex(NULL,
  139. 0,
  140. CMTACallbackThread::Thread,
  141. this,
  142. 0,
  143. &threadId);
  144. if (ulThread == 0xffffffff || ulThread == 0)
  145. hr = E_OUTOFMEMORY;
  146. else
  147. m_hThread = (HANDLE)ulThread;
  148. if (SUCCEEDED(hr))
  149. m_fInited = TRUE;
  150. return hr;
  151. }
  152. // UnInit (real destructor)
  153. HRESULT UnInit()
  154. {
  155. DBG_ASSERT(m_fInited);
  156. if (m_hThread)
  157. {
  158. // Kill the MTA thread
  159. m_fShutdown = TRUE;
  160. SetEvent(m_hDoItEvent);
  161. WaitForSingleObject(m_hThread, INFINITE);
  162. CloseHandle(m_hThread);
  163. m_hThread = NULL;
  164. }
  165. if (m_fCSInited)
  166. {
  167. DeleteCriticalSection(&m_csLock);
  168. m_fCSInited = FALSE;
  169. }
  170. if (m_hDoItEvent)
  171. {
  172. CloseHandle(m_hDoItEvent);
  173. m_hDoItEvent = NULL;
  174. }
  175. if (m_hDoneEvent)
  176. {
  177. CloseHandle(m_hDoneEvent);
  178. m_hDoneEvent = NULL;
  179. }
  180. m_fInited = FALSE;
  181. return NOERROR;
  182. }
  183. // Execute callback
  184. HRESULT CallCallback
  185. (
  186. PMTACALLBACK pMTACallback,
  187. void *pvContext,
  188. void *pvContext2
  189. )
  190. {
  191. if (m_fShutdown)
  192. return E_FAIL;
  193. DBG_ASSERT(m_fInited);
  194. DBG_ASSERT(pMTACallback);
  195. HRESULT hr = E_FAIL;
  196. EnterCriticalSection(&m_csLock);
  197. DBG_ASSERT(m_pMTACallback == NULL);
  198. m_pMTACallback = pMTACallback;
  199. m_pvContext = pvContext;
  200. m_pvContext2 = pvContext2;
  201. m_hrResult = E_FAIL;
  202. // Tell MTA thread to call back
  203. SetEvent(m_hDoItEvent);
  204. // Wait till done
  205. WaitForSingleObject(m_hDoneEvent, INFINITE);
  206. // remember HRESULT
  207. hr = m_hrResult;
  208. // to make sure we never do it twice
  209. m_pMTACallback = NULL;
  210. LeaveCriticalSection(&m_csLock);
  211. return hr;
  212. }
  213. };
  214. // Sole instance of the above
  215. static CMTACallbackThread *g_pMTACallbackThread = NULL;
  216. /*===================================================================
  217. E x t e r n a l A P I
  218. ===================================================================*/
  219. /*===================================================================
  220. InitMTACallbacks
  221. To be called from DllInit()
  222. Inits the MTA callback processing
  223. Launches the MTA thread
  224. Parameters
  225. Returns:
  226. HRESULT
  227. ===================================================================*/
  228. HRESULT InitMTACallbacks()
  229. {
  230. g_pMTACallbackThread = new CMTACallbackThread;
  231. if (g_pMTACallbackThread == NULL)
  232. {
  233. return E_OUTOFMEMORY;
  234. }
  235. return g_pMTACallbackThread->Init();
  236. }
  237. /*===================================================================
  238. UnInitMTACallbacks
  239. To be called from DllUnInit()
  240. Stops the MTA callback processing
  241. Kills the MTA thread
  242. Parameters
  243. Returns:
  244. HRESULT
  245. ===================================================================*/
  246. HRESULT UnInitMTACallbacks()
  247. {
  248. HRESULT hr = E_FAIL;
  249. if (g_pMTACallbackThread != NULL)
  250. {
  251. hr = g_pMTACallbackThread->UnInit();
  252. delete g_pMTACallbackThread;
  253. g_pMTACallbackThread = NULL;
  254. }
  255. return hr;
  256. }
  257. /*===================================================================
  258. CallMTACallback
  259. Calls the hack.
  260. Parameters
  261. PMTACALLBACK pMTACallback call this function
  262. void *pvContext pass this to it
  263. void *pvContext2 extra arg
  264. Returns:
  265. HRESULT
  266. ===================================================================*/
  267. HRESULT CallMTACallback
  268. (
  269. PMTACALLBACK pMTACallback,
  270. void *pvContext,
  271. void *pvContext2
  272. )
  273. {
  274. return g_pMTACallbackThread->CallCallback
  275. (
  276. pMTACallback,
  277. pvContext,
  278. pvContext2
  279. );
  280. }