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.

324 lines
8.1 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 "denpre.h"
  11. #pragma hdrstop
  12. #include "MTAcb.h"
  13. #include "memchk.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. Assert(m_pMTACallback);
  36. m_hrResult = (*m_pMTACallback)(m_pvContext, m_pvContext2);
  37. }
  38. // The thread function
  39. static void __cdecl Thread(void *pvArg)
  40. {
  41. HRESULT hr;
  42. 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. Assert(FALSE);
  54. return;
  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. }
  84. public:
  85. // Constructor
  86. CMTACallbackThread()
  87. : m_fInited(FALSE), m_fCSInited(FALSE), m_fShutdown(FALSE),
  88. m_hDoItEvent(NULL), m_hDoneEvent(NULL), m_hThread(NULL),
  89. m_pMTACallback(NULL)
  90. {
  91. }
  92. // Destructor
  93. ~CMTACallbackThread()
  94. {
  95. // Real cleanup is in UnInit()
  96. // This is to cleanup after a bad Init()
  97. if (m_fCSInited)
  98. DeleteCriticalSection(&m_csLock);
  99. if (m_hDoItEvent)
  100. CloseHandle(m_hDoItEvent);
  101. if (m_hDoneEvent)
  102. CloseHandle(m_hDoneEvent);
  103. }
  104. // Init (real constructor)
  105. HRESULT Init()
  106. {
  107. HRESULT hr = S_OK;
  108. if (SUCCEEDED(hr))
  109. {
  110. ErrInitCriticalSection(&m_csLock, hr);
  111. m_fCSInited = SUCCEEDED(hr);
  112. }
  113. if (SUCCEEDED(hr))
  114. {
  115. m_hDoItEvent = IIS_CREATE_EVENT(
  116. "CMTACallbackThread::m_hDoItEvent",
  117. this,
  118. FALSE,
  119. FALSE
  120. );
  121. if (!m_hDoItEvent)
  122. hr = E_OUTOFMEMORY;
  123. }
  124. if (SUCCEEDED(hr))
  125. {
  126. m_hDoneEvent = IIS_CREATE_EVENT(
  127. "CMTACallbackThread::m_hDoneEvent",
  128. this,
  129. FALSE,
  130. FALSE
  131. );
  132. if (!m_hDoneEvent)
  133. hr = E_OUTOFMEMORY;
  134. }
  135. // Launch the MTA thread
  136. uintptr_t ulThread = _beginthread(CMTACallbackThread::Thread, 0, this);
  137. if (ulThread == 0xffffffff || ulThread == 0)
  138. hr = E_OUTOFMEMORY;
  139. else
  140. m_hThread = (HANDLE)ulThread;
  141. if (SUCCEEDED(hr))
  142. m_fInited = TRUE;
  143. return hr;
  144. }
  145. // UnInit (real destructor)
  146. HRESULT UnInit()
  147. {
  148. Assert(m_fInited);
  149. if (m_hThread)
  150. {
  151. // Kill the MTA thread
  152. m_fShutdown = TRUE;
  153. SetEvent(m_hDoItEvent);
  154. WaitForSingleObject(m_hThread, INFINITE);
  155. m_hThread = NULL;
  156. }
  157. if (m_fCSInited)
  158. {
  159. DeleteCriticalSection(&m_csLock);
  160. m_fCSInited = FALSE;
  161. }
  162. if (m_hDoItEvent)
  163. {
  164. CloseHandle(m_hDoItEvent);
  165. m_hDoItEvent = NULL;
  166. }
  167. if (m_hDoneEvent)
  168. {
  169. CloseHandle(m_hDoneEvent);
  170. m_hDoneEvent = NULL;
  171. }
  172. m_fInited = FALSE;
  173. return S_OK;
  174. }
  175. // Execute callback
  176. HRESULT CallCallback
  177. (
  178. PMTACALLBACK pMTACallback,
  179. void *pvContext,
  180. void *pvContext2
  181. )
  182. {
  183. if (m_fShutdown)
  184. return E_FAIL;
  185. Assert(m_fInited);
  186. Assert(pMTACallback);
  187. HRESULT hr = E_FAIL;
  188. DWORD eventSignaled;
  189. EnterCriticalSection(&m_csLock);
  190. Assert(m_pMTACallback == NULL);
  191. m_pMTACallback = pMTACallback;
  192. m_pvContext = pvContext;
  193. m_pvContext2 = pvContext2;
  194. m_hrResult = E_FAIL;
  195. // Tell MTA thread to call back
  196. SetEvent(m_hDoItEvent);
  197. // Wait till done
  198. CoWaitForMultipleHandles(0,
  199. INFINITE,
  200. 1,
  201. &m_hDoneEvent,
  202. &eventSignaled);
  203. // remember HRESULT
  204. hr = m_hrResult;
  205. // to make sure we never do it twice
  206. m_pMTACallback = NULL;
  207. LeaveCriticalSection(&m_csLock);
  208. return hr;
  209. }
  210. };
  211. // Sole instance of the above
  212. static CMTACallbackThread g_MTACallbackThread;
  213. /*===================================================================
  214. E x t e r n a l A P I
  215. ===================================================================*/
  216. /*===================================================================
  217. InitMTACallbacks
  218. To be called from DllInit()
  219. Inits the MTA callback processing
  220. Launches the MTA thread
  221. Parameters
  222. Returns:
  223. HRESULT
  224. ===================================================================*/
  225. HRESULT InitMTACallbacks()
  226. {
  227. return g_MTACallbackThread.Init();
  228. }
  229. /*===================================================================
  230. UnInitMTACallbacks
  231. To be called from DllUnInit()
  232. Stops the MTA callback processing
  233. Kills the MTA thread
  234. Parameters
  235. Returns:
  236. HRESULT
  237. ===================================================================*/
  238. HRESULT UnInitMTACallbacks()
  239. {
  240. return g_MTACallbackThread.UnInit();
  241. }
  242. /*===================================================================
  243. CallMTACallback
  244. Calls the hack.
  245. Parameters
  246. PMTACALLBACK pMTACallback call this function
  247. void *pvContext pass this to it
  248. void *pvContext2 extra arg
  249. Returns:
  250. HRESULT
  251. ===================================================================*/
  252. HRESULT CallMTACallback
  253. (
  254. PMTACALLBACK pMTACallback,
  255. void *pvContext,
  256. void *pvContext2
  257. )
  258. {
  259. return g_MTACallbackThread.CallCallback
  260. (
  261. pMTACallback,
  262. pvContext,
  263. pvContext2
  264. );
  265. }