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.

310 lines
7.2 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.HighPart >= 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. InTimer - 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. #if DBG
  152. ULONG SearchCount;
  153. #endif
  154. //
  155. // Compute the timer table index and set the timer expiration time.
  156. //
  157. Index = KiComputeTimerTableIndex(Interval, CurrentTime, Timer);
  158. //
  159. // If the timer is due before the first entry in the computed list
  160. // or the computed list is empty, then insert the timer at the front
  161. // of the list and check if the timer has already expired. Otherwise,
  162. // insert then timer in the sorted order of the list searching from
  163. // the back of the list forward.
  164. //
  165. // N.B. The sequence of operations below is critical to avoid the race
  166. // condition that exists between this code and the clock interrupt
  167. // code that examines the timer table lists to detemine when timers
  168. // expire.
  169. //
  170. ListHead = &KiTimerTableListHead[Index];
  171. NextEntry = ListHead->Blink;
  172. #if DBG
  173. SearchCount = 0;
  174. #endif
  175. while (NextEntry != ListHead) {
  176. //
  177. // Compute the maximum search count.
  178. //
  179. #if DBG
  180. SearchCount += 1;
  181. if (SearchCount > KiMaximumSearchCount) {
  182. KiMaximumSearchCount = SearchCount;
  183. }
  184. #endif
  185. NextTimer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry);
  186. if (Timer->DueTime.QuadPart >= NextTimer->DueTime.QuadPart) {
  187. break;
  188. }
  189. NextEntry = NextEntry->Blink;
  190. }
  191. InsertHeadList(NextEntry, &Timer->TimerListEntry);
  192. if (NextEntry == ListHead) {
  193. //
  194. // The computed list is empty or the timer is due to expire before
  195. // the first entry in the list.
  196. //
  197. //
  198. // Make sure the writes for the insert into the list are done before
  199. // reading the interrupt time. KeUpdateSystemTime update will write
  200. // the time and then check the list for expired timers.
  201. //
  202. KeMemoryBarrier();
  203. KiQueryInterruptTime(&CurrentTime);
  204. if (Timer->DueTime.QuadPart <= (ULONG64)CurrentTime.QuadPart) {
  205. //
  206. // The timer is due to expire before the current time. Remove the
  207. // timer from the computed list, set its status to Signaled, and
  208. // set its inserted state to FALSE.
  209. //
  210. KiRemoveTreeTimer(Timer);
  211. Timer->Header.SignalState = TRUE;
  212. Timer->Header.Inserted = FALSE;
  213. }
  214. }
  215. return Timer->Header.Inserted;
  216. }