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.

300 lines
7.2 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. sleep.c
  5. Abstract:
  6. This handles sleep requests on the part of the interpreter
  7. Author:
  8. Stephane Plante (splante)
  9. Environment:
  10. NT Kernel Mode Driver only
  11. NB: Win9x can run this code also, but they will choose not do so.
  12. --*/
  13. #include "pch.h"
  14. VOID
  15. SleepQueueDpc(
  16. PKDPC Dpc,
  17. PVOID Context,
  18. PVOID Argument1,
  19. PVOID Argument2
  20. )
  21. /*++
  22. Routine Description:
  23. This routine is fired when a timer event occurs
  24. Arguments:
  25. Dpc - The DPC that was fired
  26. Context - Not used
  27. Argument1 - Time.LowPart -- Not used
  28. Argument2 - Time.HighPart -- Not used
  29. Return Value:
  30. VOID
  31. --*/
  32. {
  33. LARGE_INTEGER currentTime;
  34. LARGE_INTEGER dueTime;
  35. LIST_ENTRY localList;
  36. PLIST_ENTRY listEntry;
  37. PSLEEP sleepItem;
  38. UNREFERENCED_PARAMETER( Dpc );
  39. UNREFERENCED_PARAMETER( Context );
  40. UNREFERENCED_PARAMETER( Argument1 );
  41. UNREFERENCED_PARAMETER( Argument2 );
  42. //
  43. // Initialize the local list. Contrary to what the docs say, this code
  44. // can be called from any IRQL (as long as the mem is resident)
  45. //
  46. InitializeListHead(&localList);
  47. //
  48. // Acquire the lock, since we must remove the things from the list
  49. // under some kind of protection.
  50. //
  51. AcquireMutex(&gmutSleep);
  52. //
  53. // Find the correct time. This *must* be done after we are acquire the
  54. // lock because there might be a long delay between trying to acquire
  55. // the lock and actually getting it
  56. //
  57. currentTime.QuadPart = KeQueryInterruptTime();
  58. //
  59. // Loop until we are done
  60. //
  61. while (!IsListEmpty(&SleepQueue)) {
  62. //
  63. // Obtain the first element in the global list again
  64. //
  65. sleepItem = CONTAINING_RECORD(SleepQueue.Flink, SLEEP, ListEntry);
  66. //
  67. // Should the current item be removed?
  68. //
  69. if (sleepItem->SleepTime.QuadPart > currentTime.QuadPart) {
  70. //
  71. // No, so we need to set the timer to take care of this request
  72. //
  73. dueTime.QuadPart = currentTime.QuadPart -
  74. sleepItem->SleepTime.QuadPart;
  75. KeSetTimer(
  76. &SleepTimer,
  77. dueTime,
  78. &SleepDpc
  79. );
  80. break;
  81. }
  82. //
  83. // Yes, so remove it
  84. //
  85. listEntry = RemoveHeadList(&SleepQueue);
  86. //
  87. // Now, add the entry to the next queue
  88. //
  89. InsertTailList(&localList, listEntry);
  90. }
  91. //
  92. // Done with lock. This may cause another DPC to process more elements
  93. //
  94. ReleaseMutex(&gmutSleep);
  95. //
  96. // At this point, we are free to remove items from the local list and
  97. // try to do work on them.
  98. //
  99. while (!IsListEmpty(&localList)) {
  100. //
  101. // Remove the first element from the local list
  102. //
  103. listEntry = RemoveHeadList(&localList);
  104. sleepItem = CONTAINING_RECORD(listEntry, SLEEP, ListEntry);
  105. //
  106. // Force the interpreter to run
  107. //
  108. RestartContext(sleepItem->Context,
  109. (BOOLEAN)((sleepItem->Context->dwfCtxt & CTXTF_ASYNC_EVAL)
  110. == 0));
  111. }
  112. }
  113. #ifdef LOCKABLE_PRAGMA
  114. #pragma ACPI_LOCKABLE_DATA
  115. #pragma ACPI_LOCKABLE_CODE
  116. #endif
  117. NTSTATUS
  118. LOCAL
  119. SleepQueueRequest(
  120. IN PCTXT Context,
  121. IN ULONG SleepTime
  122. )
  123. /*++
  124. Routine Description:
  125. This routine is responsible for adding the sleep request to the
  126. system queue for pending sleep requests
  127. Arguments:
  128. Context - The current execution context
  129. SleepTime - The amount of sleep time, in MilliSeconds
  130. Rreturn Value:
  131. NTSTATUS
  132. --*/
  133. {
  134. TRACENAME("SLEEPQUEUEREQUEST")
  135. BOOLEAN timerSet = FALSE;
  136. NTSTATUS status;
  137. PLIST_ENTRY listEntry;
  138. PSLEEP currentSleep;
  139. PSLEEP listSleep;
  140. ULONGLONG currentTime;
  141. LARGE_INTEGER dueTime;
  142. ENTER(2, ("SleepQueueRequest(Context=%x,SleepTime=%d)\n",
  143. Context, SleepTime) );
  144. status = PushFrame(Context,
  145. SIG_SLEEP,
  146. sizeof(SLEEP),
  147. ProcessSleep,
  148. &currentSleep);
  149. if (NT_SUCCESS(status)) {
  150. //
  151. // The first step is acquire the timer lock, since we must protect it
  152. //
  153. AcquireMutex(&gmutSleep);
  154. //
  155. // Next step is to determine time at which we should wake up this
  156. // context
  157. //
  158. currentTime = KeQueryInterruptTime();
  159. currentSleep->SleepTime.QuadPart = currentTime +
  160. ((ULONGLONG)SleepTime*10000);
  161. currentSleep->Context = Context;
  162. //
  163. // At this point, it becomes easier to walk the list backwards
  164. //
  165. listEntry = &SleepQueue;
  166. while (listEntry->Blink != &SleepQueue) {
  167. listSleep = CONTAINING_RECORD(listEntry->Blink, SLEEP, ListEntry);
  168. //
  169. // Do we have to add the new element after the current one?
  170. //
  171. if (currentSleep->SleepTime.QuadPart >=
  172. listSleep->SleepTime.QuadPart) {
  173. //
  174. // Yes
  175. //
  176. InsertHeadList(
  177. &(listSleep->ListEntry),
  178. &(currentSleep->ListEntry)
  179. );
  180. break;
  181. }
  182. //
  183. // Next entry
  184. //
  185. listEntry = listEntry->Blink;
  186. }
  187. //
  188. // Look to see if we got to the head
  189. //
  190. if (listEntry->Blink == &SleepQueue) {
  191. //
  192. // If we get to this point, it is because we have
  193. // gone all the around the list. If we add to the
  194. // front of the list, we must set the timer
  195. //
  196. InsertHeadList(&SleepQueue, &currentSleep->ListEntry);
  197. dueTime.QuadPart = currentTime - currentSleep->SleepTime.QuadPart;
  198. timerSet = KeSetTimer(
  199. &SleepTimer,
  200. dueTime,
  201. &SleepDpc
  202. );
  203. }
  204. //
  205. // Done with the lock
  206. //
  207. ReleaseMutex(&gmutSleep);
  208. }
  209. EXIT(2, ("SleepQueueReqest=%x (currentSleep=%x timerSet=%x)\n",
  210. status, currentSleep, timerSet) );
  211. return status;
  212. }
  213. /***LP ProcessSleep - post processing of sleep
  214. *
  215. * ENTRY
  216. * pctxt -> CTXT
  217. * psleep -> SLEEP
  218. * rc - status code
  219. *
  220. * EXIT-SUCCESS
  221. * returns STATUS_SUCCESS
  222. * EXIT-FAILURE
  223. * returns AMLIERR_ code
  224. */
  225. NTSTATUS LOCAL ProcessSleep(PCTXT pctxt, PSLEEP psleep, NTSTATUS rc)
  226. {
  227. TRACENAME("PROCESSSLEEP")
  228. ENTER(2, ("ProcessSleep(pctxt=%x,pbOp=%x,psleep=%x,rc=%x)\n",
  229. pctxt, pctxt->pbOp, psleep, rc));
  230. ASSERT(psleep->FrameHdr.dwSig == SIG_SLEEP);
  231. PopFrame(pctxt);
  232. EXIT(2, ("ProcessSleep=%x\n", rc));
  233. return rc;
  234. } //ProcessSleep