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.

246 lines
5.5 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. waitsup.c
  5. Abstract:
  6. This module contains the support routines necessary to support the
  7. generic kernel wait functions. Functions are provided to test if a
  8. wait can be satisfied, to satisfy a wait, and to unwwait a thread.
  9. Author:
  10. David N. Cutler (davec) 24-Mar-1989
  11. Environment:
  12. Kernel mode only.
  13. Revision History:
  14. --*/
  15. #include "ki.h"
  16. VOID
  17. FASTCALL
  18. KiExitDispatcher (
  19. IN KIRQL OldIrql
  20. )
  21. /*++
  22. Routine Description:
  23. This function processes the deferred ready list, possibly switches to
  24. a new thread, and lowers IRQL to its previous value.
  25. Arguments:
  26. OldIrql - Supplies the previous IRQL value.
  27. Return Value:
  28. None.
  29. --*/
  30. {
  31. PKTHREAD CurrentThread;
  32. PKTHREAD NewThread;
  33. BOOLEAN Pending;
  34. PKPRCB Prcb;
  35. ASSERT(KeGetCurrentIrql() == SYNCH_LEVEL);
  36. //
  37. // Process the deferred ready list if the list is not empty.
  38. //
  39. Prcb = KeGetCurrentPrcb();
  40. #if !defined(NT_UP)
  41. if (Prcb->DeferredReadyListHead.Next != NULL) {
  42. KiProcessDeferredReadyList(Prcb);
  43. }
  44. #endif
  45. //
  46. // If the old IRQL is less than dispatch level, then a new thread can
  47. // be dispatcher immediately.
  48. //
  49. if (OldIrql < DISPATCH_LEVEL) {
  50. //
  51. // If there is a new thread selected for execution, then switch
  52. // context to the new thread.
  53. //
  54. if (Prcb->NextThread != NULL) {
  55. KiAcquirePrcbLock(Prcb);
  56. NewThread = Prcb->NextThread;
  57. CurrentThread = Prcb->CurrentThread;
  58. KiSetContextSwapBusy(CurrentThread);
  59. Prcb->NextThread = NULL;
  60. Prcb->CurrentThread = NewThread;
  61. NewThread->State = Running;
  62. KxQueueReadyThread(CurrentThread, Prcb);
  63. CurrentThread->WaitIrql = OldIrql;
  64. Pending = KiSwapContext(CurrentThread, NewThread);
  65. if (Pending != FALSE) {
  66. KeLowerIrql(APC_LEVEL);
  67. KiDeliverApc(KernelMode, NULL, NULL);
  68. ASSERT(OldIrql == 0);
  69. }
  70. }
  71. } else if ((Prcb->NextThread != NULL) &&
  72. (Prcb->DpcRoutineActive == FALSE)) {
  73. KiRequestSoftwareInterrupt(DISPATCH_LEVEL);
  74. }
  75. //
  76. // Lower IRQL to its previous level.
  77. //
  78. KeLowerIrql(OldIrql);
  79. return;
  80. }
  81. VOID
  82. FASTCALL
  83. KiUnwaitThread (
  84. IN PRKTHREAD Thread,
  85. IN LONG_PTR WaitStatus,
  86. IN KPRIORITY Increment
  87. )
  88. /*++
  89. Routine Description:
  90. This function unwaits a thread, sets the thread's wait completion status,
  91. calculates the thread's new priority, and either readies the thread for
  92. execution or adds the thread to a list of threads to be readied later.
  93. Arguments:
  94. Thread - Supplies a pointer to a dispatcher object of type thread.
  95. WaitStatus - Supplies the wait completion status.
  96. Increment - Supplies the priority increment that is to be applied to
  97. the thread's priority.
  98. Return Value:
  99. None.
  100. --*/
  101. {
  102. //
  103. // Unlink thread from the appropriate wait queues and set the wait
  104. // completion status.
  105. //
  106. KiUnlinkThread(Thread, WaitStatus);
  107. //
  108. // Set unwait priority adjustment parameters.
  109. //
  110. ASSERT(Increment >= 0);
  111. Thread->AdjustIncrement = (SCHAR)Increment;
  112. Thread->AdjustReason = (UCHAR)AdjustUnwait;
  113. //
  114. // Ready the thread for execution.
  115. //
  116. KiReadyThread(Thread);
  117. return;
  118. }
  119. VOID
  120. FASTCALL
  121. KiWaitTest (
  122. IN PVOID Object,
  123. IN KPRIORITY Increment
  124. )
  125. /*++
  126. Routine Description:
  127. This function tests if a wait can be satisfied when an object attains
  128. a state of signaled. If a wait can be satisfied, then the subject thread
  129. is unwaited with a completion status that is the WaitKey of the wait
  130. block from the object wait list. As many waits as possible are satisfied.
  131. Arguments:
  132. Object - Supplies a pointer to a dispatcher object.
  133. Return Value:
  134. None.
  135. --*/
  136. {
  137. PKEVENT Event;
  138. PLIST_ENTRY ListHead;
  139. PRKTHREAD Thread;
  140. PRKWAIT_BLOCK WaitBlock;
  141. PLIST_ENTRY WaitEntry;
  142. NTSTATUS WaitStatus;
  143. //
  144. // As long as the signal state of the specified object is Signaled and
  145. // there are waiters in the object wait list, then try to satisfy a wait.
  146. //
  147. Event = (PKEVENT)Object;
  148. ListHead = &Event->Header.WaitListHead;
  149. WaitEntry = ListHead->Flink;
  150. while ((Event->Header.SignalState > 0) &&
  151. (WaitEntry != ListHead)) {
  152. WaitBlock = CONTAINING_RECORD(WaitEntry, KWAIT_BLOCK, WaitListEntry);
  153. Thread = WaitBlock->Thread;
  154. WaitStatus = STATUS_KERNEL_APC;
  155. //
  156. // N.B. The below code only satisfies the wait for wait any types.
  157. // Wait all types are satisfied in the wait code itself. This
  158. // is done with a eye to the future when the dispatcher lock is
  159. // split into a lock per waitable object type and a scheduling
  160. // state lock. For now, a kernel APC is simulated for wait all
  161. // types.
  162. //
  163. if (WaitBlock->WaitType == WaitAny) {
  164. WaitStatus = (NTSTATUS)WaitBlock->WaitKey;
  165. KiWaitSatisfyAny((PKMUTANT)Event, Thread);
  166. }
  167. KiUnwaitThread(Thread, WaitStatus, Increment);
  168. WaitEntry = ListHead->Flink;
  169. }
  170. return;
  171. }