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.

297 lines
6.6 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. timersup.c
  5. Abstract:
  6. This module contains the support routines for the timer object. It
  7. contains functions to insert and remove from the timer queue.
  8. Author:
  9. David N. Cutler (davec) 13-Mar-1989
  10. Environment:
  11. Kernel mode only.
  12. Revision History:
  13. --*/
  14. #include "ki.h"
  15. //
  16. // Define forward referenced function prototypes.
  17. //
  18. LOGICAL
  19. FASTCALL
  20. KiInsertTimerTable (
  21. LARGE_INTEGER Interval,
  22. LARGE_INTEGER CurrentTime,
  23. IN PKTIMER Timer
  24. );
  25. LOGICAL
  26. FASTCALL
  27. KiInsertTreeTimer (
  28. IN PKTIMER Timer,
  29. IN LARGE_INTEGER Interval
  30. )
  31. /*++
  32. Routine Description:
  33. This function inserts a timer object in the timer queue.
  34. N.B. This routine assumes that the dispatcher data lock has been acquired.
  35. Arguments:
  36. Timer - Supplies a pointer to a dispatcher object of type timer.
  37. Interval - Supplies the absolute or relative time at which the time
  38. is to expire.
  39. Return Value:
  40. If the timer is inserted in the timer tree, than a value of TRUE is
  41. returned. Otherwise, a value of FALSE is returned.
  42. --*/
  43. {
  44. LARGE_INTEGER CurrentTime;
  45. LARGE_INTEGER SystemTime;
  46. LARGE_INTEGER TimeDifference;
  47. //
  48. // Clear the signal state of timer if the timer period is zero and set
  49. // the inserted state to TRUE.
  50. //
  51. Timer->Header.Inserted = TRUE;
  52. Timer->Header.Absolute = FALSE;
  53. if (Timer->Period == 0) {
  54. Timer->Header.SignalState = FALSE;
  55. }
  56. //
  57. // If the specified interval is not a relative time (i.e., is an absolute
  58. // time), then convert it to relative time.
  59. //
  60. if (Interval.HighPart >= 0) {
  61. KiQuerySystemTime(&SystemTime);
  62. TimeDifference.QuadPart = SystemTime.QuadPart - Interval.QuadPart;
  63. //
  64. // If the resultant relative time is greater than or equal to zero,
  65. // then the timer has already expired.
  66. //
  67. if (TimeDifference.HighPart >= 0) {
  68. Timer->Header.SignalState = TRUE;
  69. Timer->Header.Inserted = FALSE;
  70. return FALSE;
  71. }
  72. Interval = TimeDifference;
  73. Timer->Header.Absolute = TRUE;
  74. }
  75. //
  76. // Get the current interrupt time, insert the timer in the timer table,
  77. // and return the inserted state.
  78. //
  79. KiQueryInterruptTime(&CurrentTime);
  80. return KiInsertTimerTable(Interval, CurrentTime, Timer);
  81. }
  82. LOGICAL
  83. FASTCALL
  84. KiReinsertTreeTimer (
  85. IN PKTIMER Timer,
  86. IN ULARGE_INTEGER DueTime
  87. )
  88. /*++
  89. Routine Description:
  90. This function reinserts a timer object in the timer queue.
  91. N.B. This routine assumes that the dispatcher data lock has been acquired.
  92. Arguments:
  93. Timer - Supplies a pointer to a dispatcher object of type timer.
  94. DueTime - Supplies the absolute time the timer is to expire.
  95. Return Value:
  96. If the timer is inserted in the timer tree, than a value of TRUE is
  97. returned. Otherwise, a value of FALSE is returned.
  98. --*/
  99. {
  100. LARGE_INTEGER CurrentTime;
  101. LARGE_INTEGER Interval;
  102. //
  103. // Clear the signal state of timer if the timer period is zero and set
  104. // the inserted state to TRUE.
  105. //
  106. Timer->Header.Inserted = TRUE;
  107. if (Timer->Period == 0) {
  108. Timer->Header.SignalState = FALSE;
  109. }
  110. //
  111. // Compute the interval between the current time and the due time.
  112. // If the resultant relative time is greater than or equal to zero,
  113. // then the timer has already expired.
  114. //
  115. KiQueryInterruptTime(&CurrentTime);
  116. Interval.QuadPart = CurrentTime.QuadPart - DueTime.QuadPart;
  117. if (Interval.QuadPart >= 0) {
  118. Timer->Header.SignalState = TRUE;
  119. Timer->Header.Inserted = FALSE;
  120. return FALSE;
  121. }
  122. //
  123. // Insert the timer in the timer table and return the inserted state.
  124. //
  125. return KiInsertTimerTable(Interval, CurrentTime, Timer);
  126. }
  127. LOGICAL
  128. FASTCALL
  129. KiInsertTimerTable (
  130. LARGE_INTEGER Interval,
  131. LARGE_INTEGER CurrentTime,
  132. IN PKTIMER Timer
  133. )
  134. /*++
  135. Routine Description:
  136. This function inserts a timer object in the timer table.
  137. N.B. This routine assumes that the dispatcher data lock has been acquired.
  138. Arguments:
  139. Interval - Supplies the relative timer before the timer is to expire.
  140. CurrentTime - supplies the current interrupt time.
  141. Timer - Supplies a pointer to a dispatcher object of type timer.
  142. Return Value:
  143. If the timer is inserted in the timer tree, than a value of TRUE is
  144. returned. Otherwise, a value of FALSE is returned.
  145. --*/
  146. {
  147. ULONG Index;
  148. PLIST_ENTRY ListHead;
  149. PLIST_ENTRY NextEntry;
  150. PKTIMER NextTimer;
  151. ULONG SearchCount;
  152. //
  153. // Compute the timer table index and set the timer expiration time.
  154. //
  155. Index = KiComputeTimerTableIndex(Interval, CurrentTime, Timer);
  156. //
  157. // If the timer is due before the first entry in the computed list
  158. // or the computed list is empty, then insert the timer at the front
  159. // of the list and check if the timer has already expired. Otherwise,
  160. // insert then timer in the sorted order of the list searching from
  161. // the back of the list forward.
  162. //
  163. // N.B. The sequence of operations below is critical to avoid the race
  164. // condition that exists between this code and the clock interrupt
  165. // code that examines the timer table lists to detemine when timers
  166. // expire.
  167. //
  168. ListHead = &KiTimerTableListHead[Index];
  169. NextEntry = ListHead->Blink;
  170. #if DBG
  171. SearchCount = 0;
  172. #endif
  173. while (NextEntry != ListHead) {
  174. //
  175. // Compute the maximum search count.
  176. //
  177. #if DBG
  178. SearchCount += 1;
  179. if (SearchCount > KiMaximumSearchCount) {
  180. KiMaximumSearchCount = SearchCount;
  181. }
  182. #endif
  183. NextTimer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry);
  184. if (Timer->DueTime.QuadPart >= NextTimer->DueTime.QuadPart) {
  185. break;
  186. }
  187. NextEntry = NextEntry->Blink;
  188. }
  189. InsertHeadList(NextEntry, &Timer->TimerListEntry);
  190. if (NextEntry == ListHead) {
  191. //
  192. // The computed list is empty or the timer is due to expire before
  193. // the first entry in the list.
  194. //
  195. KiQueryInterruptTime(&CurrentTime);
  196. if (Timer->DueTime.QuadPart <= (ULONG64)CurrentTime.QuadPart) {
  197. //
  198. // The timer is due to expire before the current time. Remove the
  199. // timer from the computed list, set its status to Signaled, and
  200. // set its inserted state to FALSE.
  201. //
  202. KiRemoveTreeTimer(Timer);
  203. Timer->Header.SignalState = TRUE;
  204. Timer->Header.Inserted = FALSE;
  205. }
  206. }
  207. return Timer->Header.Inserted;
  208. }