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.

338 lines
7.0 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 2000.
  5. //
  6. // File: T I M E R . C P P
  7. //
  8. // Contents: Timer queue helper class
  9. //
  10. // Notes:
  11. //
  12. // Author: mbend 3 Nov 2000
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "pch.h"
  16. #pragma hdrstop
  17. #include "timer.h"
  18. #include "ncdefine.h"
  19. #include "ncbase.h"
  20. CTimerQueue CTimerQueue::s_instance;
  21. CTimerQueue::CTimerQueue() : m_hTimerQueue(NULL), m_nRefCount(0)
  22. {
  23. }
  24. CTimerQueue::~CTimerQueue()
  25. {
  26. if (!m_hTimerQueue)
  27. {
  28. TraceError("CTimerQueue::~CTimerQueue", E_FAIL);
  29. }
  30. }
  31. CTimerQueue & CTimerQueue::Instance()
  32. {
  33. return s_instance;
  34. }
  35. HRESULT CTimerQueue::HrInitialize()
  36. {
  37. CLock lock(m_critSec);
  38. ++m_nRefCount;
  39. if(m_nRefCount > 1)
  40. {
  41. return S_OK;
  42. }
  43. HRESULT hr = S_OK;
  44. m_hTimerQueue = CreateTimerQueue();
  45. if(!m_hTimerQueue)
  46. {
  47. hr = HrFromLastWin32Error();
  48. }
  49. TraceHr(ttidSsdpTimer, FAL, hr, FALSE, "CTimerQueue::HrInitialize");
  50. return hr;
  51. }
  52. HRESULT CTimerQueue::HrShutdown(HANDLE hCompletionEvent)
  53. {
  54. HRESULT hr = S_OK;
  55. HANDLE hTimerQueue = NULL;
  56. {
  57. CLock lock(m_critSec);
  58. if(!m_nRefCount)
  59. {
  60. hr = E_UNEXPECTED;
  61. TraceHr(ttidSsdpTimer, FAL, hr, FALSE, "CTimerQueue::HrShutdown - Can't call SsdpCleanup without calling SsdpStartup");
  62. }
  63. if(SUCCEEDED(hr))
  64. {
  65. --m_nRefCount;
  66. if(!m_nRefCount)
  67. {
  68. Assert(m_hTimerQueue);
  69. hTimerQueue = m_hTimerQueue;
  70. m_hTimerQueue = NULL;
  71. }
  72. }
  73. }
  74. if(SUCCEEDED(hr) && hTimerQueue)
  75. {
  76. if(!DeleteTimerQueueEx(hTimerQueue, hCompletionEvent))
  77. {
  78. hr = HrFromLastWin32Error();
  79. }
  80. }
  81. TraceHr(ttidSsdpTimer, FAL, hr, FALSE, "CTimerQueue::HrShutdown");
  82. return hr;
  83. }
  84. HRESULT CTimerQueue::HrGetHandle(HANDLE * phTimerQueue)
  85. {
  86. CLock lock(m_critSec);
  87. HRESULT hr = S_OK;
  88. if(phTimerQueue)
  89. {
  90. *phTimerQueue = m_hTimerQueue;
  91. }
  92. else
  93. {
  94. hr = E_POINTER;
  95. }
  96. TraceHr(ttidSsdpTimer, FAL, hr, FALSE, "CTimerQueue::HrGetHandle");
  97. return hr;
  98. }
  99. #ifdef DBG
  100. long CTimerBase::s_nCallbackEnter = 0;
  101. long CTimerBase::s_nCallbackExit = 0;
  102. #endif // DBG
  103. CTimerBase::CTimerBase() : m_bShutdown(FALSE), m_hTimerQueueTimer(NULL)
  104. {
  105. #ifdef DBG
  106. m_nSetTimer = 0;
  107. m_nSetTimerSuccess = 0;
  108. m_nDeleteTimer = 0;
  109. m_nDeleteTimerActual = 0;
  110. m_nTimerFiredEnter = 0;
  111. m_nTimerFiredExit = 0;
  112. m_nCallbackEnter = 0;
  113. #endif // DBG
  114. }
  115. CTimerBase::~CTimerBase()
  116. {
  117. HRESULT hr = S_OK;
  118. if(m_hTimerQueueTimer)
  119. {
  120. HANDLE hTimerQueue = NULL;
  121. hr = CTimerQueue::Instance().HrGetHandle(&hTimerQueue);
  122. if(SUCCEEDED(hr))
  123. {
  124. if(!DeleteTimerQueueTimer(hTimerQueue, m_hTimerQueueTimer, NULL))
  125. {
  126. hr = HrFromLastWin32Error();
  127. }
  128. else
  129. {
  130. m_hTimerQueueTimer = NULL;
  131. }
  132. }
  133. }
  134. }
  135. HRESULT CTimerBase::HrSetTimer(
  136. DWORD dwIntervalInMillis)
  137. {
  138. HRESULT hr = E_FAIL;
  139. CLock lock(m_critSec);
  140. Assert(!m_hTimerQueueTimer);
  141. #ifdef DBG
  142. InterlockedIncrement(&m_nSetTimer);
  143. #endif // DBG
  144. // Check for shutdown
  145. if(!m_bShutdown)
  146. {
  147. HANDLE hTimerQueue = NULL;
  148. hr = CTimerQueue::Instance().HrGetHandle(&hTimerQueue);
  149. if(SUCCEEDED(hr))
  150. {
  151. if(!CreateTimerQueueTimer(&m_hTimerQueueTimer, hTimerQueue, &CTimerBase::Callback, this, dwIntervalInMillis, 0, 0))
  152. {
  153. hr = HrFromLastWin32Error();
  154. }
  155. }
  156. }
  157. #ifdef DBG
  158. if(SUCCEEDED(hr))
  159. {
  160. InterlockedIncrement(&m_nSetTimerSuccess);
  161. }
  162. #endif // DBG
  163. TraceHr(ttidSsdpTimer, FAL, hr, FALSE, "CTimerBase::HrSetTimer");
  164. return hr;
  165. }
  166. HRESULT CTimerBase::HrSetTimerInFired(
  167. DWORD dwIntervalInMillis)
  168. {
  169. HRESULT hr = E_FAIL;
  170. CLock lock(m_critSec);
  171. if(!m_bShutdown)
  172. {
  173. if(m_hTimerQueueTimer)
  174. {
  175. HrDelete(NULL);
  176. m_bShutdown = FALSE;
  177. }
  178. hr = HrSetTimer(dwIntervalInMillis);
  179. }
  180. TraceHr(ttidSsdpTimer, FAL, hr, FALSE, "CTimerBase::HrSetTimerInFired");
  181. return hr;
  182. }
  183. HRESULT CTimerBase::HrDelete(HANDLE hCompletionEvent)
  184. {
  185. HRESULT hr = S_OK;
  186. #ifdef DBG
  187. InterlockedIncrement(&m_nDeleteTimer);
  188. #endif // DBG
  189. HANDLE hTimerQueueTimer = NULL;
  190. {
  191. CLock lock(m_critSec);
  192. m_bShutdown = TRUE;
  193. hTimerQueueTimer = m_hTimerQueueTimer;
  194. m_hTimerQueueTimer = NULL;
  195. }
  196. if(hTimerQueueTimer)
  197. {
  198. HANDLE hTimerQueue = NULL;
  199. hr = CTimerQueue::Instance().HrGetHandle(&hTimerQueue);
  200. if(SUCCEEDED(hr))
  201. {
  202. if(!DeleteTimerQueueTimer(hTimerQueue, hTimerQueueTimer, hCompletionEvent))
  203. {
  204. hr = HrFromLastWin32Error();
  205. if (HRESULT_FROM_WIN32(ERROR_IO_PENDING) == hr)
  206. {
  207. hr = S_OK;
  208. }
  209. }
  210. #ifdef DBG
  211. if(SUCCEEDED(hr))
  212. {
  213. InterlockedIncrement(&m_nDeleteTimerActual);
  214. }
  215. #endif // DBG
  216. }
  217. }
  218. else
  219. {
  220. if(hCompletionEvent != NULL && hCompletionEvent != INVALID_HANDLE_VALUE)
  221. {
  222. SetEvent(hCompletionEvent);
  223. }
  224. }
  225. TraceHr(ttidSsdpTimer, FAL, hr, FALSE, "CTimerBase::HrDelete");
  226. return hr;
  227. }
  228. HRESULT CTimerBase::HrResetTimer(
  229. DWORD dwIntervalInMillis)
  230. {
  231. HRESULT hr = S_OK;
  232. // Can't hold lock during whole operation or this can deadlock waiting for timer to exit
  233. HrDelete(INVALID_HANDLE_VALUE);
  234. m_bShutdown = FALSE;
  235. hr = HrSetTimer(dwIntervalInMillis);
  236. TraceHr(ttidSsdpTimer, FAL, hr, FALSE, "CTimerBase::HrResetTimer");
  237. return hr;
  238. }
  239. void CALLBACK CTimerBase::Callback(void * pvParam, BOOLEAN)
  240. {
  241. CTimerBase * pTimer = reinterpret_cast<CTimerBase*>(pvParam);
  242. #ifdef DBG
  243. InterlockedIncrement(&s_nCallbackEnter);
  244. InterlockedIncrement(&pTimer->m_nCallbackEnter);
  245. #endif // DBG
  246. while(true)
  247. {
  248. CLock lock(pTimer->m_critSec);
  249. if(pTimer->m_bShutdown)
  250. {
  251. break;
  252. }
  253. if(pTimer->OnTryToLock())
  254. {
  255. pTimer->OnExecute();
  256. pTimer->OnUnlock();
  257. break;
  258. }
  259. Sleep(1);
  260. }
  261. #ifdef DBG
  262. InterlockedIncrement(&s_nCallbackExit);
  263. #endif // DBG
  264. }
  265. VOID FileTimeToString(FILETIME FileTime, CHAR *szBuf, INT BufSize)
  266. {
  267. SYSTEMTIME SystemTime;
  268. INT Size;
  269. FileTimeToLocalFileTime(&FileTime, &FileTime);
  270. FileTimeToSystemTime(&FileTime,&SystemTime);
  271. Size = GetDateFormatA(LOCALE_SYSTEM_DEFAULT, 0, &SystemTime, NULL,
  272. szBuf, BufSize-1 );
  273. if (Size > 0)
  274. {
  275. szBuf[Size-1] = ' ';
  276. }
  277. GetTimeFormatA(LOCALE_SYSTEM_DEFAULT, 0, &SystemTime, NULL,
  278. szBuf+Size, BufSize-Size);
  279. }