2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ke/thrdschd.c
5 * PURPOSE: Kernel Thread Scheduler (Affinity, Priority, Scheduling)
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
15 /* GLOBALS *******************************************************************/
18 ULONG KiIdleSMTSummary
;
20 /* FUNCTIONS *****************************************************************/
24 KiQueueReadyThread(IN PKTHREAD Thread
,
27 /* Call the macro. We keep the API for compatibility with ASM code */
28 KxQueueReadyThread(Thread
, Prcb
);
33 KiDeferredReadyThread(IN PKTHREAD Thread
)
38 KPRIORITY OldPriority
;
42 ASSERT(Thread
->State
== DeferredReady
);
43 ASSERT((Thread
->Priority
>= 0) && (Thread
->Priority
<= HIGH_PRIORITY
));
45 /* Check if we have any adjusts to do */
46 if (Thread
->AdjustReason
== AdjustBoost
)
49 KiAcquireThreadLock(Thread
);
51 /* Check if the priority is low enough to qualify for boosting */
52 if ((Thread
->Priority
<= Thread
->AdjustIncrement
) &&
53 (Thread
->Priority
< (LOW_REALTIME_PRIORITY
- 3)) &&
54 !(Thread
->DisableBoost
))
56 /* Calculate the new priority based on the adjust increment */
57 OldPriority
= min(Thread
->AdjustIncrement
+ 1,
58 LOW_REALTIME_PRIORITY
- 1);
60 /* Make sure we're not decreasing outside of the priority range */
61 ASSERT((Thread
->PriorityDecrement
>= 0) &&
62 (Thread
->PriorityDecrement
<= Thread
->Priority
));
64 /* Calculate the new priority decrement based on the boost */
65 Thread
->PriorityDecrement
+= ((SCHAR
)OldPriority
- Thread
->Priority
);
67 /* Again verify that this decrement is valid */
68 ASSERT((Thread
->PriorityDecrement
>= 0) &&
69 (Thread
->PriorityDecrement
<= OldPriority
));
71 /* Set the new priority */
72 Thread
->Priority
= (SCHAR
)OldPriority
;
75 /* We need 4 quanta, make sure we have them, then decrease by one */
76 if (Thread
->Quantum
< 4) Thread
->Quantum
= 4;
79 /* Make sure the priority is still valid */
80 ASSERT((Thread
->Priority
>= 0) && (Thread
->Priority
<= HIGH_PRIORITY
));
82 /* Release the lock and clear the adjust reason */
83 KiReleaseThreadLock(Thread
);
84 Thread
->AdjustReason
= AdjustNone
;
86 else if (Thread
->AdjustReason
== AdjustUnwait
)
88 /* Acquire the thread lock and check if this is a real-time thread */
89 KiAcquireThreadLock(Thread
);
90 if (Thread
->Priority
< LOW_REALTIME_PRIORITY
)
92 /* It's not real time, but is it time critical? */
93 if (Thread
->BasePriority
>= (LOW_REALTIME_PRIORITY
- 2))
95 /* It is, so simply reset its quantum */
96 Thread
->Quantum
= Thread
->QuantumReset
;
100 /* Has the priority been adjusted previously? */
101 if (!(Thread
->PriorityDecrement
) && (Thread
->AdjustIncrement
))
103 /* Yes, reset its quantum */
104 Thread
->Quantum
= Thread
->QuantumReset
;
107 /* Wait code already handles quantum adjustment during APCs */
108 if (Thread
->WaitStatus
!= STATUS_KERNEL_APC
)
110 /* Decrease the quantum by one and check if we're out */
111 if (--Thread
->Quantum
<= 0)
113 /* We are, reset the quantum and get a new priority */
114 Thread
->Quantum
= Thread
->QuantumReset
;
115 Thread
->Priority
= KiComputeNewPriority(Thread
, 1);
120 /* Now check if we have no decrement and boosts are enabled */
121 if (!(Thread
->PriorityDecrement
) && !(Thread
->DisableBoost
))
123 /* Make sure we have an increment */
124 ASSERT(Thread
->AdjustIncrement
>= 0);
126 /* Calculate the new priority after the increment */
127 OldPriority
= Thread
->BasePriority
+ Thread
->AdjustIncrement
;
129 /* Check if this new priority is higher */
130 if (OldPriority
> Thread
->Priority
)
132 /* Make sure we don't go into the real time range */
133 if (OldPriority
>= LOW_REALTIME_PRIORITY
)
135 /* Normalize it back down one notch */
136 OldPriority
= LOW_REALTIME_PRIORITY
- 1;
139 /* Check if the priority is higher then the boosted base */
140 if (OldPriority
> (Thread
->BasePriority
+
141 Thread
->AdjustIncrement
))
143 /* Setup a priority decrement to nullify the boost */
144 Thread
->PriorityDecrement
= ((SCHAR
)OldPriority
-
145 Thread
->BasePriority
-
146 Thread
->AdjustIncrement
);
149 /* Make sure that the priority decrement is valid */
150 ASSERT((Thread
->PriorityDecrement
>= 0) &&
151 (Thread
->PriorityDecrement
<= OldPriority
));
153 /* Set this new priority */
154 Thread
->Priority
= (SCHAR
)OldPriority
;
160 /* It's a real-time thread, so just reset its quantum */
161 Thread
->Quantum
= Thread
->QuantumReset
;
164 /* Make sure the priority makes sense */
165 ASSERT((Thread
->Priority
>= 0) && (Thread
->Priority
<= HIGH_PRIORITY
));
167 /* Release the thread lock and reset the adjust reason */
168 KiReleaseThreadLock(Thread
);
169 Thread
->AdjustReason
= AdjustNone
;
172 /* Clear thread preemption status and save current values */
173 Preempted
= Thread
->Preempted
;
174 OldPriority
= Thread
->Priority
;
175 Thread
->Preempted
= FALSE
;
177 /* Queue the thread on CPU 0 and get the PRCB */
178 Thread
->NextProcessor
= 0;
179 Prcb
= KiProcessorBlock
[0];
181 /* Check if we have an idle summary */
184 /* Clear it and set this thread as the next one */
186 Thread
->State
= Standby
;
187 Prcb
->NextThread
= Thread
;
191 /* Set the CPU number */
192 Thread
->NextProcessor
= (UCHAR
)Processor
;
194 /* Get the next scheduled thread */
195 NextThread
= Prcb
->NextThread
;
199 ASSERT(NextThread
->State
== Standby
);
201 /* Check if priority changed */
202 if (OldPriority
> NextThread
->Priority
)
204 /* Preempt the thread */
205 NextThread
->Preempted
= TRUE
;
207 /* Put this one as the next one */
208 Thread
->State
= Standby
;
209 Prcb
->NextThread
= Thread
;
211 /* Set it in deferred ready mode */
212 NextThread
->State
= DeferredReady
;
213 NextThread
->DeferredProcessor
= Prcb
->Number
;
214 KiReleasePrcbLock(Prcb
);
215 KiDeferredReadyThread(NextThread
);
221 /* Set the next thread as the current thread */
222 NextThread
= Prcb
->CurrentThread
;
223 if (OldPriority
> NextThread
->Priority
)
225 /* Preempt it if it's already running */
226 if (NextThread
->State
== Running
) NextThread
->Preempted
= TRUE
;
228 /* Set the thread on standby and as the next thread */
229 Thread
->State
= Standby
;
230 Prcb
->NextThread
= Thread
;
232 /* Release the lock */
233 KiReleasePrcbLock(Prcb
);
235 /* Check if we're running on another CPU */
236 if (KeGetCurrentProcessorNumber() != Thread
->NextProcessor
)
238 /* We are, send an IPI */
239 KiIpiSendRequest(AFFINITY_MASK(Thread
->NextProcessor
), IPI_DPC
);
246 ASSERT((OldPriority
>= 0) && (OldPriority
<= HIGH_PRIORITY
));
248 /* Set this thread as ready */
249 Thread
->State
= Ready
;
250 Thread
->WaitTime
= KeTickCount
.LowPart
;
252 /* Insert this thread in the appropriate order */
253 Preempted
? InsertHeadList(&Prcb
->DispatcherReadyListHead
[OldPriority
],
254 &Thread
->WaitListEntry
) :
255 InsertTailList(&Prcb
->DispatcherReadyListHead
[OldPriority
],
256 &Thread
->WaitListEntry
);
258 /* Update the ready summary */
259 Prcb
->ReadySummary
|= PRIORITY_MASK(OldPriority
);
262 ASSERT(OldPriority
== Thread
->Priority
);
264 /* Release the lock */
265 KiReleasePrcbLock(Prcb
);
269 KiInsertIntoThreadList(KPRIORITY Priority
,
272 ASSERT(Ready
== Thread
->State
);
273 ASSERT(Thread
->Priority
== Priority
);
275 if (Priority
>= MAXIMUM_PRIORITY
|| Priority
< LOW_PRIORITY
) {
277 DPRINT1("Invalid thread priority (%d)\n", Priority
);
281 InsertTailList(&KeGetCurrentPrcb()->DispatcherReadyListHead
[Priority
], &Thread
->WaitListEntry
);
282 KeGetCurrentPrcb()->ReadySummary
|= (1 << Priority
);
286 KiRemoveFromThreadList(PKTHREAD Thread
)
288 ASSERT(Ready
== Thread
->State
);
289 RemoveEntryList(&Thread
->WaitListEntry
);
290 if (IsListEmpty(&KeGetCurrentPrcb()->DispatcherReadyListHead
[Thread
->Priority
])) {
292 KeGetCurrentPrcb()->ReadySummary
&= ~(1 << Thread
->Priority
);
297 KiScanThreadList(KPRIORITY Priority
,
303 Mask
= (1 << Priority
);
305 if (KeGetCurrentPrcb()->ReadySummary
& Mask
) {
307 LIST_FOR_EACH(current
, &KeGetCurrentPrcb()->DispatcherReadyListHead
[Priority
], KTHREAD
, WaitListEntry
) {
309 if (current
->State
!= Ready
) {
311 DPRINT1("%p/%d\n", current
, current
->State
);
314 ASSERT(current
->State
== Ready
);
316 if (current
->Affinity
& Affinity
) {
318 KiRemoveFromThreadList(current
);
329 KiDispatchThreadNoLock(ULONG NewThreadStatus
)
331 KPRIORITY CurrentPriority
;
334 PKTHREAD CurrentThread
= KeGetCurrentThread();
337 DPRINT("KiDispatchThreadNoLock() %d/%d/%d/%d\n", KeGetCurrentProcessorNumber(),
338 CurrentThread
, NewThreadStatus
, CurrentThread
->State
);
340 CurrentThread
->State
= (UCHAR
)NewThreadStatus
;
342 if (NewThreadStatus
== Ready
) {
344 KiInsertIntoThreadList(CurrentThread
->Priority
,
348 Affinity
= 1 << KeGetCurrentProcessorNumber();
350 for (CurrentPriority
= HIGH_PRIORITY
; CurrentPriority
>= LOW_PRIORITY
; CurrentPriority
--) {
352 Candidate
= KiScanThreadList(CurrentPriority
, Affinity
);
354 if (Candidate
== CurrentThread
) {
356 Candidate
->State
= Running
;
357 KiReleaseDispatcherLockFromDpcLevel();
361 if (Candidate
!= NULL
) {
366 DPRINT("Scheduling %x(%d)\n",Candidate
, CurrentPriority
);
368 Candidate
->State
= Running
;
370 OldThread
= CurrentThread
;
371 CurrentThread
= Candidate
;
372 IdleThread
= KeGetCurrentPrcb()->IdleThread
;
374 if (OldThread
== IdleThread
) {
376 KiIdleSummary
&= ~Affinity
;
378 } else if (CurrentThread
== IdleThread
) {
380 KiIdleSummary
|= Affinity
;
383 MmUpdatePageDir((PEPROCESS
)PsGetCurrentProcess(),((PETHREAD
)CurrentThread
)->ThreadsProcess
, sizeof(EPROCESS
));
385 /* Special note for Filip: This will release the Dispatcher DB Lock ;-) -- Alex */
386 DPRINT("You are : %x, swapping to: %x.\n", OldThread
, CurrentThread
);
387 KeGetCurrentPrcb()->CurrentThread
= CurrentThread
;
388 ApcState
= KiSwapContext(OldThread
, CurrentThread
);
389 DPRINT("You are : %x, swapped from: %x\n", OldThread
, CurrentThread
);
394 DPRINT1("CRITICAL: No threads are ready (CPU%d)\n", KeGetCurrentProcessorNumber());
401 KiDispatchThread(ULONG NewThreadStatus
)
405 if (KeGetCurrentPrcb()->IdleThread
== NULL
) {
409 OldIrql
= KiAcquireDispatcherLock();
410 KiDispatchThreadNoLock(NewThreadStatus
);
411 KeLowerIrql(OldIrql
);
416 KiSelectNextThread(IN PKPRCB Prcb
)
420 /* Select a ready thread */
421 Thread
= KiSelectReadyThread(0, Prcb
);
424 /* Didn't find any, get the current idle thread */
425 Thread
= Prcb
->IdleThread
;
427 /* Enable idle scheduling */
428 InterlockedOr((PLONG
) &KiIdleSummary
, Prcb
->SetMember
);
429 Prcb
->IdleSchedule
= TRUE
;
431 /* FIXME: SMT support */
434 /* Sanity checks and return the thread */
435 ASSERT(Thread
!= NULL
);
436 ASSERT((Thread
->BasePriority
== 0) || (Thread
->Priority
!= 0));
442 KiSwapThread(IN PKTHREAD CurrentThread
,
445 BOOLEAN ApcState
= FALSE
;
450 PEPROCESS HackOfDoom
= PsGetCurrentProcess();
452 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL
);
454 /* Acquire the PRCB lock */
455 KiAcquirePrcbLock(Prcb
);
457 /* Get the next thread */
458 NextThread
= Prcb
->NextThread
;
461 /* Already got a thread, set it up */
462 Prcb
->NextThread
= NULL
;
463 Prcb
->CurrentThread
= NextThread
;
464 NextThread
->State
= Running
;
469 /* Try to find a ready thread */
470 NextThread
= KiSelectReadyThread(0, Prcb
);
474 Prcb
->CurrentThread
= NextThread
;
475 NextThread
->State
= Running
;
479 /* Set the idle summary */
480 InterlockedOr((PLONG
)&KiIdleSummary
, Prcb
->SetMember
);
482 /* Schedule the idle thread */
483 NextThread
= Prcb
->IdleThread
;
484 Prcb
->CurrentThread
= NextThread
;
485 NextThread
->State
= Running
;
488 /* Find a new thread to run */
489 ApcState
= KiDispatchThreadNoLock(Waiting
);
493 /* Sanity check and release the PRCB */
494 ASSERT(CurrentThread
!= Prcb
->IdleThread
);
495 KiReleasePrcbLock(Prcb
);
497 /* Save the wait IRQL */
498 WaitIrql
= CurrentThread
->WaitIrql
;
501 /* REACTOS Mm Hack of Doom */
502 MmUpdatePageDir(HackOfDoom
,((PETHREAD
)NextThread
)->ThreadsProcess
, sizeof(EPROCESS
));
505 ApcState
= KiSwapContext(CurrentThread
, NextThread
);
508 /* Get the wait status */
509 WaitStatus
= CurrentThread
->WaitStatus
;
511 /* Check if we need to deliver APCs */
514 /* Lower to APC_LEVEL */
515 KeLowerIrql(APC_LEVEL
);
518 KiDeliverApc(KernelMode
, NULL
, NULL
);
519 ASSERT(WaitIrql
== 0);
522 /* Lower IRQL back to what it was and return the wait status */
523 KeLowerIrql(WaitIrql
);
529 KiReadyThread(IN PKTHREAD Thread
)
531 IN PKPROCESS Process
= Thread
->ApcState
.Process
;
533 /* Check if the process is paged out */
534 if (Process
->State
!= ProcessInMemory
)
536 /* We don't page out processes in ROS */
539 else if (!Thread
->KernelStackResident
)
541 /* Increase the stack count */
542 ASSERT(Process
->StackCount
!= MAXULONG_PTR
);
543 Process
->StackCount
++;
545 /* Set the thread to transition */
546 ASSERT(Thread
->State
!= Transition
);
547 Thread
->State
= Transition
;
549 /* The stack is always resident in ROS */
554 /* Insert the thread on the deferred ready list */
556 KiInsertDeferredReadyList(Thread
);
558 /* Insert the thread into the thread list */
559 Thread
->State
= Ready
;
560 KiInsertIntoThreadList(Thread
->Priority
, Thread
);
567 KiAdjustQuantumThread(IN PKTHREAD Thread
)
569 PKPRCB Prcb
= KeGetCurrentPrcb();
572 /* Acquire thread and PRCB lock */
573 KiAcquireThreadLock(Thread
);
574 KiAcquirePrcbLock(Prcb
);
576 /* Don't adjust for RT threads */
577 if ((Thread
->Priority
< LOW_REALTIME_PRIORITY
) &&
578 (Thread
->BasePriority
< (LOW_REALTIME_PRIORITY
- 2)))
580 /* Decrease Quantum by one and see if we've ran out */
581 if (--Thread
->Quantum
<= 0)
584 Thread
->Quantum
= Thread
->QuantumReset
;
586 /* Calculate new Priority */
587 Thread
->Priority
= KiComputeNewPriority(Thread
, 1);
590 /* Check if there's no next thread scheduled */
591 if (!Prcb
->NextThread
)
593 /* Select a ready thread and check if we found one */
594 NextThread
= KiSelectReadyThread(Thread
->Priority
, Prcb
);
597 /* Set it on standby and switch to it */
598 NextThread
->State
= Standby
;
599 Prcb
->NextThread
= NextThread
;
604 /* This thread can be preempted again */
605 Thread
->Preempted
= FALSE
;
608 /* We need to dispatch a new thread */
610 KiDispatchThread(Ready
);
616 KiReleasePrcbLock(Prcb
);
617 KiReleaseThreadLock(Thread
);
618 KiExitDispatcher(Thread
->WaitIrql
);
623 KiSetPriorityThread(IN PKTHREAD Thread
,
624 IN KPRIORITY Priority
)
628 BOOLEAN RequestInterrupt
= FALSE
;
629 KPRIORITY OldPriority
;
631 ASSERT((Priority
>= 0) && (Priority
<= HIGH_PRIORITY
));
633 /* Check if priority changed */
634 if (Thread
->Priority
!= Priority
)
636 /* Loop priority setting in case we need to start over */
639 /* Choose action based on thread's state */
640 if (Thread
->State
== Ready
)
642 /* Make sure we're not on the ready queue */
643 if (!Thread
->ProcessReadyQueue
)
645 /* Get the PRCB for the thread and lock it */
646 Processor
= Thread
->NextProcessor
;
647 Prcb
= KiProcessorBlock
[Processor
];
648 KiAcquirePrcbLock(Prcb
);
650 /* Make sure the thread is still ready and on this CPU */
651 if ((Thread
->State
== Ready
) &&
652 (Thread
->NextProcessor
== Prcb
->Number
))
656 ASSERT((Prcb
->ReadySummary
&
657 PRIORITY_MASK(Thread
->Priority
)));
659 /* Remove it from the current queue */
660 if (RemoveEntryList(&Thread
->WaitListEntry
))
662 /* Update the ready summary */
663 Prcb
->ReadySummary
^= PRIORITY_MASK(Thread
->
667 KiRemoveFromThreadList(Thread
);
670 /* Update priority */
671 Thread
->Priority
= (SCHAR
)Priority
;
673 /* Re-insert it at its current priority */
674 #ifndef NEW_SCHEDULER
675 KiInsertIntoThreadList(Priority
, Thread
);
676 //KiDispatchThreadNoLock(Ready);
678 KiInsertDeferredReadyList(Thread
);
681 /* Release the PRCB Lock */
682 KiReleasePrcbLock(Prcb
);
686 /* Release the lock and loop again */
687 KiReleasePrcbLock(Prcb
);
693 /* It's already on the ready queue, just update priority */
694 Thread
->Priority
= (SCHAR
)Priority
;
697 else if (Thread
->State
== Standby
)
699 /* Get the PRCB for the thread and lock it */
700 Processor
= Thread
->NextProcessor
;
701 Prcb
= KiProcessorBlock
[Processor
];
702 KiAcquirePrcbLock(Prcb
);
704 /* Check if we're still the next thread to run */
705 if (Thread
== Prcb
->NextThread
)
707 /* Get the old priority and update ours */
708 OldPriority
= Thread
->Priority
;
709 Thread
->Priority
= (SCHAR
)Priority
;
711 /* Check if there was a change */
712 if (Priority
< OldPriority
)
714 /* Find a new thread */
715 NewThread
= KiSelectReadyThread(Priority
+ 1, Prcb
);
718 /* Found a new one, set it on standby */
719 NewThread
->State
= Standby
;
720 Prcb
->NextThread
= NewThread
;
722 /* Dispatch our thread */
723 KiInsertDeferredReadyList(Thread
);
727 /* Release the PRCB lock */
728 KiReleasePrcbLock(Prcb
);
732 /* Release the lock and try again */
733 KiReleasePrcbLock(Prcb
);
737 else if (Thread
->State
== Running
)
739 /* Get the PRCB for the thread and lock it */
740 Processor
= Thread
->NextProcessor
;
741 Prcb
= KiProcessorBlock
[Processor
];
742 KiAcquirePrcbLock(Prcb
);
744 /* Check if we're still the current thread running */
745 if (Thread
== Prcb
->CurrentThread
)
747 /* Get the old priority and update ours */
748 OldPriority
= Thread
->Priority
;
749 Thread
->Priority
= (SCHAR
)Priority
;
751 /* Check if there was a change and there's no new thread */
752 if ((Priority
< OldPriority
) && !(Prcb
->NextThread
))
755 /* Find a new thread */
756 NewThread
= KiSelectReadyThread(Priority
+ 1, Prcb
);
759 /* Found a new one, set it on standby */
760 NewThread
->State
= Standby
;
761 Prcb
->NextThread
= NewThread
;
763 /* Request an interrupt */
764 RequestInterrupt
= TRUE
;
767 /* Check for threads with a higher priority */
768 if (KeGetCurrentPrcb()->ReadySummary
& ~((1 << (Priority
+ 1)) - 1))
770 /* Found a thread, is it us? */
771 if (Thread
== KeGetCurrentThread())
774 //KiDispatchThreadNoLock(Ready);
781 /* Release the lock and check if we need an interrupt */
782 KiReleasePrcbLock(Prcb
);
783 if (RequestInterrupt
)
785 /* Check if we're running on another CPU */
786 if (KeGetCurrentProcessorNumber() != Processor
)
788 /* We are, send an IPI */
789 KiIpiSendRequest(AFFINITY_MASK(Processor
), IPI_DPC
);
795 /* Thread changed, release lock and restart */
796 KiReleasePrcbLock(Prcb
);
800 else if (Thread
->State
== DeferredReady
)
803 DPRINT1("Deferred state not yet supported\n");
808 /* Any other state, just change priority */
809 Thread
->Priority
= (SCHAR
)Priority
;
812 /* If we got here, then thread state was consistent, so bail out */
820 KiSetAffinityThread(IN PKTHREAD Thread
,
821 IN KAFFINITY Affinity
)
823 KAFFINITY OldAffinity
;
825 /* Get the current affinity */
826 OldAffinity
= Thread
->UserAffinity
;
828 /* Make sure that the affinity is valid */
829 if (((Affinity
& Thread
->ApcState
.Process
->Affinity
) != (Affinity
)) ||
832 /* Bugcheck the system */
833 KeBugCheck(INVALID_AFFINITY_SET
);
836 /* Update the new affinity */
837 Thread
->UserAffinity
= Affinity
;
839 /* Check if system affinity is disabled */
840 if (!Thread
->SystemAffinityActive
)
843 DPRINT1("Affinity support disabled!\n");
846 /* Return the old affinity */
855 NtYieldExecution(VOID
)
858 NTSTATUS Status
= STATUS_NO_YIELD_PERFORMED
;
860 PKPRCB Prcb
= KeGetCurrentPrcb();
861 PKTHREAD Thread
= KeGetCurrentThread(), NextThread
;
863 /* Fail if there's no ready summary */
864 if (!Prcb
->ReadySummary
) return Status
;
866 /* Raise IRQL to synch */
867 OldIrql
= KeRaiseIrqlToSynchLevel();
869 /* Now check if there's still a ready summary */
870 if (Prcb
->ReadySummary
)
872 /* Acquire thread and PRCB lock */
873 KiAcquireThreadLock(Thread
);
874 KiAcquirePrcbLock(Prcb
);
876 /* Find a new thread to run if none was selected */
877 if (!Prcb
->NextThread
) Prcb
->NextThread
= KiSelectReadyThread(1, Prcb
);
879 /* Make sure we still have a next thread to schedule */
880 NextThread
= Prcb
->NextThread
;
883 /* Reset quantum and recalculate priority */
884 Thread
->Quantum
= Thread
->QuantumReset
;
885 Thread
->Priority
= KiComputeNewPriority(Thread
, 1);
887 /* Release the thread lock */
888 KiReleaseThreadLock(Thread
);
890 /* Set context swap busy */
891 KiSetThreadSwapBusy(Thread
);
893 /* Set the new thread as running */
894 Prcb
->NextThread
= NULL
;
895 Prcb
->CurrentThread
= NextThread
;
896 NextThread
->State
= Running
;
898 /* Setup a yield wait and queue the thread */
899 Thread
->WaitReason
= WrYieldExecution
;
900 KxQueueReadyThread(Thread
, Prcb
);
902 /* Make it wait at APC_LEVEL */
903 Thread
->WaitIrql
= APC_LEVEL
;
906 ASSERT(OldIrql
<= DISPATCH_LEVEL
);
908 /* Swap to new thread */
909 KiSwapContext(Thread
, NextThread
);
910 Status
= STATUS_SUCCESS
;
914 /* Release the PRCB and thread lock */
915 KiReleasePrcbLock(Prcb
);
916 KiReleaseThreadLock(Thread
);
920 /* Lower IRQL and return */
921 KeLowerIrql(OldIrql
);
924 KiDispatchThread(Ready
);
925 return STATUS_SUCCESS
;