Leaked source code of windows server 2003
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.

332 lines
8.7 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 unsigned 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 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 = S_OK;
  109. if (SUCCEEDED(hr))
  110. {
  111. ErrInitCriticalSection(&m_csLock, hr);
  112. m_fCSInited = SUCCEEDED(hr);
  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. 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 S_OK;
  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. Assert(m_fInited);
  194. Assert(pMTACallback);
  195. HRESULT hr = E_FAIL;
  196. DWORD eventSignaled;
  197. EnterCriticalSection(&m_csLock);
  198. Assert(m_pMTACallback == NULL);
  199. m_pMTACallback = pMTACallback;
  200. m_pvContext = pvContext;
  201. m_pvContext2 = pvContext2;
  202. m_hrResult = E_FAIL;
  203. // Tell MTA thread to call back
  204. SetEvent(m_hDoItEvent);
  205. // Wait till done
  206. CoWaitForMultipleHandles(0,
  207. INFINITE,
  208. 1,
  209. &m_hDoneEvent,
  210. &eventSignaled);
  211. // remember HRESULT
  212. hr = m_hrResult;
  213. // to make sure we never do it twice
  214. m_pMTACallback = NULL;
  215. LeaveCriticalSection(&m_csLock);
  216. return hr;
  217. }
  218. };
  219. // Sole instance of the above
  220. static CMTACallbackThread g_MTACallbackThread;
  221. /*===================================================================
  222. E x t e r n a l A P I
  223. ===================================================================*/
  224. /*===================================================================
  225. InitMTACallbacks
  226. To be called from DllInit()
  227. Inits the MTA callback processing
  228. Launches the MTA thread
  229. Parameters
  230. Returns:
  231. HRESULT
  232. ===================================================================*/
  233. HRESULT InitMTACallbacks()
  234. {
  235. return g_MTACallbackThread.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. return g_MTACallbackThread.UnInit();
  249. }
  250. /*===================================================================
  251. CallMTACallback
  252. Calls the hack.
  253. Parameters
  254. PMTACALLBACK pMTACallback call this function
  255. void *pvContext pass this to it
  256. void *pvContext2 extra arg
  257. Returns:
  258. HRESULT
  259. ===================================================================*/
  260. HRESULT CallMTACallback
  261. (
  262. PMTACALLBACK pMTACallback,
  263. void *pvContext,
  264. void *pvContext2
  265. )
  266. {
  267. return g_MTACallbackThread.CallCallback
  268. (
  269. pMTACallback,
  270. pvContext,
  271. pvContext2
  272. );
  273. }