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.

247 lines
8.2 KiB

  1. /*++
  2. Copyright (c) 2002 Microsoft Corporation
  3. Module Name:
  4. idsched.c
  5. Abstract:
  6. This module implement idle scheduling. Idle scheduling is performed when
  7. the current thread is entering a wait state or must be rescheduled for
  8. any other reason (e.g., affinity change), and a suitable thread cannot be
  9. found after searching a suitable subset of the processor ready queues.
  10. Author:
  11. David N. Cutler (davec) 25-Jan-2002
  12. Environment:
  13. Kernel mode only.
  14. --*/
  15. #include "ki.h"
  16. #if !defined(NT_UP)
  17. PKTHREAD
  18. FASTCALL
  19. KiIdleSchedule (
  20. PKPRCB CurrentPrcb
  21. )
  22. /*++
  23. Routine Description:
  24. This function is called when the idle schedule flag is set in the current
  25. PRCB. This flag is set when the current thread is entering a wait state
  26. or must be rescheduled for any other reason (e.g., affinity change) and
  27. a suitable thread cannot be found after searching all the processor ready
  28. queues outside the dispatcher database lock. A second pass over the ready
  29. queues is required since the processor was not idle during the first scan,
  30. and therefore, a potential candidate thread may have been missed.
  31. Arguments:
  32. CurrentPrcb - Supplies a pointer to the current processor block.
  33. Return Value:
  34. If a thread is found to run, then a pointer to the thread is returned.
  35. Otherwise, NULL is returned.
  36. N.B. If a thread is found, then IRQL is returned at SYNCH_LEVEL. If a
  37. thread is not found, then IRQL is returned at DISPATCH_LEVEL.
  38. --*/
  39. {
  40. LONG Index;
  41. LONG Limit;
  42. LONG Number;
  43. PKTHREAD NewThread;
  44. ULONG Processor;
  45. PKPRCB TargetPrcb;
  46. ASSERT (CurrentPrcb == KeGetCurrentPrcb());
  47. //
  48. // Raise IRQL to SYNCH_LEVEL, acquire the current PRCB lock, and clear
  49. // idle schedule.
  50. //
  51. KeRaiseIrqlToSynchLevel();
  52. KiAcquirePrcbLock(CurrentPrcb);
  53. CurrentPrcb->IdleSchedule = FALSE;
  54. //
  55. // If a thread has already been selected to run on the current processor,
  56. // then select that thread. Otherwise, attempt to select a thread from
  57. // the current processor dispatcher ready queues.
  58. //
  59. if ((NewThread = CurrentPrcb->NextThread) != NULL) {
  60. //
  61. // Clear the next thread address, set the current thread address, and
  62. // set the thread state to running.
  63. //
  64. CurrentPrcb->NextThread = NULL;
  65. CurrentPrcb->CurrentThread = NewThread;
  66. NewThread->State = Running;
  67. } else {
  68. //
  69. // Attempt to select a thread from the current processor dispatcher
  70. // ready queues.
  71. //
  72. NewThread = KiSelectReadyThread(0, CurrentPrcb);
  73. if (NewThread != NULL) {
  74. CurrentPrcb->NextThread = NULL;
  75. CurrentPrcb->CurrentThread = NewThread;
  76. NewThread->State = Running;
  77. } else {
  78. //
  79. // Release the current PRCB lock and attempt to select a thread
  80. // from any processor dispatcher ready queues.
  81. //
  82. // If this is a multinode system, then start with the processors
  83. // on the same node. Otherwise, start with the current processor.
  84. //
  85. KiReleasePrcbLock(CurrentPrcb);
  86. Processor = CurrentPrcb->Number;
  87. Index = Processor;
  88. if (KeNumberNodes > 1) {
  89. KeFindFirstSetLeftAffinity(CurrentPrcb->ParentNode->ProcessorMask,
  90. (PULONG)&Index);
  91. }
  92. Limit = KeNumberProcessors - 1;
  93. Number = Limit;
  94. do {
  95. TargetPrcb = KiProcessorBlock[Index];
  96. if (CurrentPrcb != TargetPrcb) {
  97. if (TargetPrcb->ReadySummary != 0) {
  98. //
  99. // Acquire both current and target PRCB locks in
  100. // address order to prevent deadlock.
  101. //
  102. if (CurrentPrcb < TargetPrcb) {
  103. KiAcquirePrcbLock(CurrentPrcb);
  104. KiAcquirePrcbLock(TargetPrcb);
  105. } else {
  106. KiAcquirePrcbLock(TargetPrcb);
  107. KiAcquirePrcbLock(CurrentPrcb);
  108. }
  109. //
  110. // If a new thread has not been selected to run on
  111. // the current processor, then attempt to select a
  112. // thread to run on the current processor.
  113. //
  114. if ((NewThread = CurrentPrcb->NextThread) == NULL) {
  115. if ((TargetPrcb->ReadySummary != 0) &&
  116. (NewThread = KiFindReadyThread(Processor,
  117. TargetPrcb)) != NULL) {
  118. //
  119. // A new thread has been found to run on the
  120. // current processor.
  121. //
  122. NewThread->State = Running;
  123. KiReleasePrcbLock(TargetPrcb);
  124. CurrentPrcb->NextThread = NULL;
  125. CurrentPrcb->CurrentThread = NewThread;
  126. //
  127. // Clear idle on the current processor
  128. // and update the idle SMT summary set to
  129. // indicate the set is not idle.
  130. //
  131. KiClearIdleSummary(AFFINITY_MASK(Processor));
  132. KiClearSMTSummary(CurrentPrcb->MultiThreadProcessorSet);
  133. goto ThreadFound;
  134. } else {
  135. KiReleasePrcbLock(CurrentPrcb);
  136. KiReleasePrcbLock(TargetPrcb);
  137. }
  138. } else {
  139. //
  140. // A thread has already been selected to run on
  141. // the current processor. It is possible that
  142. // the thread is the idle thread due to a state
  143. // change that made a scheduled runable thread
  144. // unrunable.
  145. //
  146. // N.B. If the idle thread is selected, then the
  147. // current processor is idle. Otherwise,
  148. // the current processor is not idle.
  149. //
  150. if (NewThread == CurrentPrcb->IdleThread) {
  151. CurrentPrcb->NextThread = NULL;
  152. CurrentPrcb->IdleSchedule = FALSE;
  153. KiReleasePrcbLock(CurrentPrcb);
  154. KiReleasePrcbLock(TargetPrcb);
  155. continue;
  156. } else {
  157. NewThread->State = Running;
  158. KiReleasePrcbLock(TargetPrcb);
  159. CurrentPrcb->NextThread = NULL;
  160. CurrentPrcb->CurrentThread = NewThread;
  161. goto ThreadFound;
  162. }
  163. }
  164. }
  165. }
  166. Index -= 1;
  167. if (Index < 0) {
  168. Index = Limit;
  169. }
  170. Number -= 1;
  171. } while (Number >= 0);
  172. }
  173. }
  174. //
  175. // If a new thread has been selected for execution, then release the
  176. // PRCB lock and acquire the idle thread lock. Otherwise, lower IRQL
  177. // to DISPATCH_LEVEL.
  178. //
  179. ThreadFound:;
  180. if (NewThread == NULL) {
  181. KeLowerIrql(DISPATCH_LEVEL);
  182. } else {
  183. KiSetContextSwapBusy(CurrentPrcb->IdleThread);
  184. KiReleasePrcbLock(CurrentPrcb);
  185. }
  186. return NewThread;
  187. }
  188. #endif