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.

409 lines
8.3 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. thread.cpp
  5. Abstract:
  6. This module contains implementation of MSP thread management.
  7. Author:
  8. Mu Han (muhan) 1-11-1998
  9. --*/
  10. #include "stdafx.h"
  11. #include <objbase.h>
  12. #include "rndcommc.h"
  13. #include "rndutil.h"
  14. #include "thread.h"
  15. #include "rendp.h"
  16. CRendThread g_RendThread;
  17. extern "C" DWORD WINAPI gfThreadProc(LPVOID p)
  18. {
  19. return ((CRendThread *)p)->ThreadProc();
  20. }
  21. CRendThread::~CRendThread()
  22. {
  23. // all code moved from here to CRendThread::Shutdown
  24. }
  25. //
  26. // Since this class is instantiated above as a global object, and
  27. // _Module.Term() is called in DLL_PROCESS_DETACH before this
  28. // global object is destroyed, we must release all our COM references
  29. // in DLL_PROCESS_DETACH before the _Module.Term(). This is because
  30. // the _Module.Term() deletes a critical section that must be
  31. // acquired whenever a COM object is released. Therefore we have this
  32. // shutdown method, which we call explicitly in the DLL_PROCESS_DETACH
  33. // handling code before we call _Module.Term().
  34. //
  35. void CRendThread::Shutdown(void)
  36. {
  37. CLock Lock(m_lock);
  38. if (m_hThread)
  39. {
  40. Stop();
  41. }
  42. for (DWORD i = 0; i < m_Directories.size(); i ++)
  43. {
  44. m_Directories[i]->Release();
  45. }
  46. if (m_hEvents[EVENT_TIMER])
  47. {
  48. CloseHandle(m_hEvents[EVENT_TIMER]);
  49. m_hEvents[EVENT_TIMER] = NULL;
  50. }
  51. if (m_hEvents[EVENT_STOP])
  52. {
  53. CloseHandle(m_hEvents[EVENT_STOP]);
  54. m_hEvents[EVENT_STOP] = NULL;
  55. }
  56. }
  57. HRESULT CRendThread::Start()
  58. /*++
  59. Routine Description:
  60. Create the thread.
  61. Arguments:
  62. Return Value:
  63. HRESULT.
  64. --*/
  65. {
  66. HRESULT hr = E_FAIL;
  67. while (TRUE) // break if fail, for clean up purpose.
  68. {
  69. if ((m_hEvents[EVENT_STOP] = ::CreateEvent(
  70. NULL,
  71. FALSE, // flag for manual-reset event
  72. FALSE, // initial state is not set.
  73. NULL // No name.
  74. )) == NULL)
  75. {
  76. LOG((MSP_ERROR, ("Can't create the signal event")));
  77. hr = HRESULT_FROM_ERROR_CODE(GetLastError());
  78. break;
  79. }
  80. if ((m_hEvents[EVENT_TIMER] = ::CreateWaitableTimer(
  81. NULL, // lpTimerAttributes
  82. FALSE, // bManualReset
  83. NULL // lpTimerName
  84. )) == NULL)
  85. {
  86. LOG((MSP_ERROR, ("Can't create timer. Error: %d"), GetLastError()));
  87. hr = HRESULT_FROM_ERROR_CODE(GetLastError());
  88. break;
  89. }
  90. DWORD dwThreadID;
  91. m_hThread = ::CreateThread(NULL, 0, gfThreadProc, this, 0, &dwThreadID);
  92. if (m_hThread == NULL)
  93. {
  94. LOG((MSP_ERROR, ("Can't create thread. Error: %d"), GetLastError()));
  95. hr = HRESULT_FROM_ERROR_CODE(GetLastError());
  96. break;
  97. }
  98. return S_OK;
  99. }
  100. if (m_hEvents[EVENT_TIMER])
  101. {
  102. CloseHandle(m_hEvents[EVENT_TIMER]);
  103. m_hEvents[EVENT_TIMER] = NULL;
  104. }
  105. if (m_hEvents[EVENT_STOP])
  106. {
  107. CloseHandle(m_hEvents[EVENT_STOP]);
  108. m_hEvents[EVENT_STOP] = NULL;
  109. }
  110. return hr;
  111. }
  112. HRESULT CRendThread::Stop()
  113. /*++
  114. Routine Description:
  115. Stop the thread.
  116. Arguments:
  117. Return Value:
  118. HRESULT.
  119. --*/
  120. {
  121. if (!StopThread())
  122. {
  123. LOG((MSP_ERROR, ("can't stop the thread. %d"), GetLastError()));
  124. return HRESULT_FROM_ERROR_CODE(GetLastError());
  125. }
  126. // Wait until the thread stops
  127. if (::WaitForSingleObject(m_hThread, INFINITE) != WAIT_OBJECT_0)
  128. {
  129. LOG((MSP_ERROR, ("waiting for the thread to stop, %d"), GetLastError()));
  130. return HRESULT_FROM_ERROR_CODE(GetLastError());
  131. }
  132. else
  133. {
  134. ::CloseHandle(m_hThread);
  135. m_hThread = NULL;
  136. }
  137. return S_OK;
  138. }
  139. HRESULT CRendThread::AddDirectory(ITDirectory *pITDirectory)
  140. /*++
  141. Routine Description:
  142. Add a new directory to the list. The directory will be notified to
  143. update its objects when the timer goes out.
  144. Arguments:
  145. pITDirectory - A pointer to a ITDirectory Interface.
  146. Return Value:
  147. --*/
  148. {
  149. ITDynamicDirectory * pDir;
  150. HRESULT hr = pITDirectory->QueryInterface(
  151. IID_ITDynamicDirectory,
  152. (void **)&pDir
  153. );
  154. if (FAILED(hr))
  155. {
  156. return hr;
  157. }
  158. CLock Lock(m_lock);
  159. if (m_hThread == NULL)
  160. {
  161. hr = Start();
  162. if (FAILED(hr))
  163. {
  164. pDir->Release();
  165. return hr;
  166. }
  167. }
  168. for (DWORD i = 0; i < m_Directories.size(); i ++)
  169. {
  170. if (m_Directories[i] == pDir)
  171. {
  172. //
  173. // It was already in the list, so don't keep a second reference
  174. // to it.
  175. //
  176. pDir->Release();
  177. return S_OK;
  178. }
  179. }
  180. if (!m_Directories.add(pDir))
  181. {
  182. pDir->Release();
  183. return E_OUTOFMEMORY;
  184. }
  185. //
  186. // We have successfully added the directory to the list and
  187. // kept a reference to it. It is released on Remove or on destruction of
  188. // the thread class.
  189. //
  190. return S_OK;
  191. }
  192. HRESULT CRendThread::RemoveDirectory(ITDirectory *pITDirectory)
  193. /*++
  194. Routine Description:
  195. Remove a directory from the list.
  196. Arguments:
  197. pITDirectory - A pointer to a ITDirectory Interface.
  198. Return Value:
  199. --*/
  200. {
  201. CComPtr<ITDynamicDirectory> pDir;
  202. HRESULT hr = pITDirectory->QueryInterface(
  203. IID_ITDynamicDirectory,
  204. (void **)&pDir
  205. );
  206. if (FAILED(hr))
  207. {
  208. return hr;
  209. }
  210. CLock Lock(m_lock);
  211. if (m_hThread == NULL)
  212. {
  213. hr = Start();
  214. if (FAILED(hr))
  215. {
  216. return hr;
  217. }
  218. }
  219. for (DWORD i = 0; i < m_Directories.size(); i ++)
  220. {
  221. if (m_Directories[i] == pDir)
  222. {
  223. //
  224. // We kept a reference to the directory when we added it for
  225. // autorefresh. Release it now.
  226. //
  227. m_Directories[i]->Release();
  228. //
  229. // Copy the last array element to the removed element and shrink
  230. // the array by one. Can do this because order does not matter.
  231. //
  232. m_Directories[i] = m_Directories[m_Directories.size() - 1];
  233. m_Directories.shrink();
  234. return S_OK;
  235. }
  236. }
  237. return S_OK;
  238. }
  239. VOID CRendThread::UpdateDirectories()
  240. /*++
  241. Routine Description:
  242. Notify all the directories to update the objects.
  243. Arguments:
  244. Return Value:
  245. --*/
  246. {
  247. if (m_lock.TryLock())
  248. {
  249. for (DWORD i = 0; i < m_Directories.size(); i ++)
  250. {
  251. m_Directories[i]->Update(TIMER_PERIOD);
  252. }
  253. m_lock.Unlock();
  254. }
  255. }
  256. HRESULT CRendThread::ThreadProc()
  257. /*++
  258. Routine Description:
  259. the main loop of this thread.
  260. Arguments:
  261. Return Value:
  262. HRESULT.
  263. --*/
  264. {
  265. HRESULT hr;
  266. LARGE_INTEGER liDueTime;
  267. const long UNIT_IN_SECOND = (long)1e7;
  268. // initialize update timer due time, negative mean relative.
  269. liDueTime.QuadPart = Int32x32To64(-(long)TIMER_PERIOD, UNIT_IN_SECOND);
  270. if (!SetWaitableTimer(
  271. m_hEvents[EVENT_TIMER], // hTimer
  272. &liDueTime, // DueTime in 100 nanonsecond units
  273. (long)(TIMER_PERIOD * 1e3), // miliseconds
  274. NULL, // pfnCompletionRoutine
  275. NULL, // lpArgToCompletionRoutine
  276. FALSE // fResume
  277. ))
  278. {
  279. LOG((MSP_ERROR, ("Can't enable timer. Error: %d"), GetLastError()));
  280. return HRESULT_FROM_ERROR_CODE(GetLastError());
  281. }
  282. if (FAILED(hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED)))
  283. {
  284. LOG((MSP_ERROR, ("CRendThread:ConinitialzeEx failed:%x"), hr));
  285. return hr;
  286. }
  287. LOG((MSP_TRACE, ("thread proc started")));
  288. BOOL bExitFlag = FALSE;
  289. while (!bExitFlag)
  290. {
  291. DWORD dwResult = ::WaitForMultipleObjects(
  292. NUM_EVENTS, // wait for all the events.
  293. m_hEvents,
  294. FALSE, // return if any of them is set
  295. INFINITE // wait forever.
  296. );
  297. switch (dwResult)
  298. {
  299. case WAIT_OBJECT_0 + EVENT_STOP:
  300. bExitFlag = TRUE;
  301. break;
  302. case WAIT_OBJECT_0 + EVENT_TIMER:
  303. UpdateDirectories();
  304. break;
  305. }
  306. }
  307. ::CoUninitialize();
  308. return S_OK;
  309. }