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.

521 lines
10 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. tpstimer.h
  5. Abstract:
  6. Timer classes. Moved out of tpsclass.h
  7. Contents:
  8. CTimer
  9. CTimerQueueEntry
  10. CTimerQueueList
  11. CTimerQueue
  12. CTimerRequest
  13. CTimerQueueDeleteRequest
  14. CTimerAddRequest
  15. CTimerChangeRequest
  16. CTimerCancelRequest
  17. Author:
  18. Richard L Firth (rfirth) 08-Aug-1998
  19. Revision History:
  20. 08-Aug-1998 rfirth
  21. Created
  22. --*/
  23. //
  24. // manifests
  25. //
  26. #define TPS_TIMER_IN_USE 0x80000000
  27. #define TPS_TIMER_CANCELLED 0x40000000
  28. //
  29. // external data
  30. //
  31. extern LONG g_UID;
  32. //
  33. // classes
  34. //
  35. //
  36. // CTimer
  37. //
  38. class CTimer {
  39. private:
  40. HANDLE m_hQueue; // address of owning queue
  41. HANDLE m_hTimer; // timer ordinal
  42. WAITORTIMERCALLBACKFUNC m_pfnCallback;
  43. LPVOID m_pContext;
  44. DWORD m_dwPeriod;
  45. DWORD m_dwFlags;
  46. public:
  47. CTimer(HANDLE hQueue,
  48. WAITORTIMERCALLBACKFUNC pfnCallback,
  49. LPVOID pContext,
  50. DWORD dwPeriod,
  51. DWORD dwFlags
  52. )
  53. {
  54. m_hQueue = hQueue;
  55. //
  56. // FEATURE - (prevent this scenario) not industrial-strength: can have 2 timers with same ID
  57. //
  58. m_hTimer = IntToPtr(InterlockedIncrement(&g_UID));
  59. m_pfnCallback = pfnCallback;
  60. m_pContext = pContext;
  61. m_dwPeriod = dwPeriod;
  62. m_dwFlags = dwFlags;
  63. }
  64. HANDLE GetHandle(VOID) const {
  65. return m_hTimer;
  66. }
  67. HANDLE GetQueue(VOID) const {
  68. return m_hQueue;
  69. }
  70. VOID Execute(VOID) {
  71. if (m_dwFlags & TPS_EXECUTEIO) {
  72. //
  73. // NT code does nothing with this flag. We should queue
  74. // request to I/O worker thread
  75. //
  76. ASSERT(!(m_dwFlags & TPS_EXECUTEIO));
  77. }
  78. m_pfnCallback(m_pContext, TRUE);
  79. }
  80. VOID SetPeriod(DWORD dwPeriod) {
  81. m_dwPeriod = dwPeriod;
  82. }
  83. DWORD GetPeriod(VOID) const {
  84. return m_dwPeriod;
  85. }
  86. BOOL IsOneShot(VOID) {
  87. return GetPeriod() == 0;
  88. }
  89. VOID SetInUse(VOID) {
  90. m_dwFlags |= TPS_TIMER_IN_USE;
  91. }
  92. VOID ResetInUse(VOID) {
  93. m_dwFlags &= ~TPS_TIMER_IN_USE;
  94. }
  95. BOOL IsInUse(VOID) {
  96. return (m_dwFlags & TPS_TIMER_IN_USE) ? TRUE : FALSE;
  97. }
  98. VOID SetCancelled(VOID) {
  99. m_dwFlags |= TPS_TIMER_CANCELLED;
  100. }
  101. BOOL IsCancelled(VOID) {
  102. return (m_dwFlags & TPS_TIMER_CANCELLED) ? TRUE : FALSE;
  103. }
  104. };
  105. //
  106. // CTimerQueueEntry
  107. //
  108. class CTimerQueueEntry : public CTimedListEntry, public CTimer {
  109. private:
  110. public:
  111. CDoubleLinkedList m_TimerList;
  112. CTimerQueueEntry(HANDLE hQueue,
  113. WAITORTIMERCALLBACKFUNC pfnCallback,
  114. LPVOID pContext,
  115. DWORD dwDueTime,
  116. DWORD dwPeriod,
  117. DWORD dwFlags
  118. ) :
  119. CTimedListEntry(dwDueTime),
  120. CTimer(hQueue,
  121. pfnCallback,
  122. pContext,
  123. dwPeriod,
  124. dwFlags
  125. )
  126. {
  127. CDoubleLinkedListEntry::Init();
  128. m_TimerList.Init();
  129. }
  130. ~CTimerQueueEntry() {
  131. m_TimerList.Remove();
  132. }
  133. VOID SetPeriodicTime(VOID) {
  134. SetTimeStamp(ExpiryTime());
  135. SetWaitTime(GetPeriod());
  136. }
  137. CDoubleLinkedList * TimerListHead(VOID) {
  138. return m_TimerList.Head();
  139. }
  140. };
  141. //
  142. // CTimerQueueList
  143. //
  144. class CTimerQueueList {
  145. private:
  146. CDoubleLinkedList m_QueueList;
  147. CDoubleLinkedList m_TimerList;
  148. public:
  149. VOID Init(VOID) {
  150. m_QueueList.Init();
  151. m_TimerList.Init();
  152. }
  153. CDoubleLinkedList * QueueListHead(VOID) {
  154. return m_QueueList.Head();
  155. }
  156. CDoubleLinkedList * TimerListHead(VOID) {
  157. return m_TimerList.Head();
  158. }
  159. CDoubleLinkedListEntry * FindQueue(CDoubleLinkedListEntry * pEntry) {
  160. return m_QueueList.FindEntry(pEntry);
  161. }
  162. BOOL Wait(VOID) {
  163. DWORD dwWaitTime = INFINITE;
  164. CTimedListEntry * pTimer = (CTimedListEntry * )m_TimerList.Next();
  165. ASSERT(pTimer != NULL);
  166. if (pTimer != (CTimedListEntry * )m_TimerList.Head()) {
  167. dwWaitTime = pTimer->TimeToWait();
  168. }
  169. //
  170. // HACKHACK (tnoonan): Can't just check for 0 since
  171. // Win95 will always return WAIT_TIMEOUT (despite what
  172. // the docs say).
  173. //
  174. DWORD dwResult = SleepEx(dwWaitTime, TRUE);
  175. return (dwResult == 0) || (dwResult == WAIT_TIMEOUT);
  176. }
  177. VOID ProcessCompletions(VOID) {
  178. //
  179. // run down list of all timers; for each expired timer, execute its
  180. // completion handler. If one-shot timer, delete it, else reset the
  181. // timer and re-insert it in the list
  182. //
  183. // If a timer is re-inserted further down the list, we may visit it
  184. // again before we have completed the traversal. This is OK: either it
  185. // has already expired, in which case we execute again, or it hasn't
  186. // expired, in which case we terminate the traversal
  187. //
  188. CTimerQueueEntry * pTimer;
  189. CTimerQueueEntry * pNext = (CTimerQueueEntry *)m_TimerList.Next();
  190. do {
  191. pTimer = pNext;
  192. if ((pTimer == (CTimerQueueEntry *)m_TimerList.Head())
  193. || !pTimer->IsTimedOut()) {
  194. break;
  195. }
  196. pNext = (CTimerQueueEntry * )pTimer->Next();
  197. pTimer->Remove();
  198. pTimer->SetInUse();
  199. pTimer->Execute();
  200. if (pTimer->IsOneShot() || pTimer->IsCancelled()) {
  201. delete pTimer;
  202. } else {
  203. pTimer->SetPeriodicTime();
  204. pTimer->ResetInUse();
  205. pTimer->InsertBack(m_TimerList.Head());
  206. }
  207. } while (TRUE);
  208. }
  209. };
  210. //
  211. // CTimerQueue
  212. //
  213. class CTimerQueue : public CDoubleLinkedList {
  214. private:
  215. CDoubleLinkedList m_TimerList;
  216. public:
  217. CTimerQueue(CTimerQueueList * pList) {
  218. CDoubleLinkedList::Init();
  219. m_TimerList.Init();
  220. InsertTail(pList->QueueListHead());
  221. }
  222. ~CTimerQueue() {
  223. Remove();
  224. }
  225. CDoubleLinkedList * TimerListHead(VOID) {
  226. return m_TimerList.Head();
  227. }
  228. CTimerQueueEntry * FindTimer(HANDLE hTimer) {
  229. CDoubleLinkedListEntry * pEntry;
  230. for (pEntry = m_TimerList.Next();
  231. pEntry != m_TimerList.Head();
  232. pEntry = pEntry->Next()) {
  233. CTimerQueueEntry * pTimer;
  234. pTimer = CONTAINING_RECORD(pEntry, CTimerQueueEntry, m_TimerList);
  235. if (pTimer->GetHandle() == hTimer) {
  236. return pTimer;
  237. }
  238. }
  239. return NULL;
  240. }
  241. VOID DeleteTimers(VOID) {
  242. CDoubleLinkedListEntry * pEntry;
  243. for (pEntry = m_TimerList.Next();
  244. pEntry != m_TimerList.Head();
  245. pEntry = m_TimerList.Next()) {
  246. CTimerQueueEntry * pTimer;
  247. pTimer = CONTAINING_RECORD(pEntry, CTimerQueueEntry, m_TimerList);
  248. //
  249. // remove timer from global timer list (linked on CDoubleLinkedList)
  250. //
  251. pTimer->Remove();
  252. //
  253. // timer will be removed from m_TimerList by its destructor
  254. //
  255. delete pTimer;
  256. }
  257. }
  258. };
  259. //
  260. // CTimerRequest
  261. //
  262. class CTimerRequest {
  263. private:
  264. BOOL m_bCompleted;
  265. DWORD m_dwStatus;
  266. public:
  267. CTimerRequest() {
  268. m_bCompleted = FALSE;
  269. m_dwStatus = ERROR_SUCCESS;
  270. }
  271. VOID SetComplete(VOID) {
  272. m_bCompleted = TRUE;
  273. }
  274. VOID WaitForCompletion(VOID) {
  275. while (!m_bCompleted) {
  276. SleepEx(0, TRUE);
  277. }
  278. }
  279. VOID SetStatus(DWORD dwStatus) {
  280. m_dwStatus = dwStatus;
  281. }
  282. VOID SetCompletionStatus(DWORD dwStatus) {
  283. SetStatus(dwStatus);
  284. SetComplete();
  285. }
  286. BOOL SetThreadStatus(VOID) {
  287. if (m_dwStatus == ERROR_SUCCESS) {
  288. return TRUE;
  289. }
  290. SetLastError(m_dwStatus);
  291. return FALSE;
  292. }
  293. };
  294. //
  295. // CTimerQueueDeleteRequest
  296. //
  297. class CTimerQueueDeleteRequest : public CTimerRequest {
  298. private:
  299. HANDLE m_hQueue;
  300. public:
  301. CTimerQueueDeleteRequest(HANDLE hQueue) : CTimerRequest() {
  302. m_hQueue = hQueue;
  303. }
  304. HANDLE GetQueue(VOID) const {
  305. return m_hQueue;
  306. }
  307. };
  308. //
  309. // CTimerAddRequest
  310. //
  311. class CTimerAddRequest : public CTimerQueueEntry, public CTimerRequest {
  312. public:
  313. CTimerAddRequest(HANDLE hQueue,
  314. WAITORTIMERCALLBACKFUNC pfnCallback,
  315. LPVOID pContext,
  316. DWORD dwDueTime,
  317. DWORD dwPeriod,
  318. DWORD dwFlags
  319. ) :
  320. CTimerQueueEntry(hQueue,
  321. pfnCallback,
  322. pContext,
  323. dwDueTime,
  324. dwPeriod,
  325. dwFlags
  326. ),
  327. CTimerRequest()
  328. {
  329. }
  330. HANDLE GetHandle(VOID) const {
  331. return CTimer::GetHandle();
  332. }
  333. CTimerQueue * GetQueue(VOID) const {
  334. return (CTimerQueue *)CTimer::GetQueue();
  335. }
  336. };
  337. //
  338. // CTimerChangeRequest
  339. //
  340. class CTimerChangeRequest : public CTimerRequest {
  341. private:
  342. HANDLE m_hQueue;
  343. HANDLE m_hTimer;
  344. DWORD m_dwDueTime;
  345. DWORD m_dwPeriod;
  346. public:
  347. CTimerChangeRequest(HANDLE hQueue,
  348. HANDLE hTimer,
  349. DWORD dwDueTime,
  350. DWORD dwPeriod
  351. ) :
  352. CTimerRequest()
  353. {
  354. m_hQueue = hQueue;
  355. m_hTimer = hTimer;
  356. m_dwDueTime = dwDueTime;
  357. m_dwPeriod = dwPeriod;
  358. }
  359. HANDLE GetQueue(VOID) const {
  360. return m_hQueue;
  361. }
  362. HANDLE GetTimer(VOID) const {
  363. return m_hTimer;
  364. }
  365. DWORD GetDueTime(VOID) const {
  366. return m_dwDueTime;
  367. }
  368. DWORD GetPeriod(VOID) const {
  369. return m_dwPeriod;
  370. }
  371. };
  372. //
  373. // CTimerCancelRequest
  374. //
  375. class CTimerCancelRequest : public CTimerRequest {
  376. private:
  377. HANDLE m_hQueue;
  378. HANDLE m_hTimer;
  379. public:
  380. CTimerCancelRequest(HANDLE hQueue, HANDLE hTimer) : CTimerRequest() {
  381. m_hQueue = hQueue;
  382. m_hTimer = hTimer;
  383. }
  384. HANDLE GetQueue(VOID) const {
  385. return m_hQueue;
  386. }
  387. HANDLE GetTimer(VOID) const {
  388. return m_hTimer;
  389. }
  390. };