ReactOS 0.4.15-dev-7842-g558ab78
thrdschd.c File Reference
#include <ntoskrnl.h>
#include <debug.h>
Include dependency graph for thrdschd.c:

Go to the source code of this file.

Macros

#define NDEBUG
 
#define InterlockedOrSetMember(Destination, SetMember)    InterlockedOr((PLONG)Destination, SetMember);
 
#define KiGetCurrentReadySummary()   KeGetCurrentPrcb()->ReadySummary
 

Functions

PKTHREAD FASTCALL KiIdleSchedule (IN PKPRCB Prcb)
 
VOID FASTCALL KiProcessDeferredReadyList (IN PKPRCB Prcb)
 
VOID FASTCALL KiQueueReadyThread (IN PKTHREAD Thread, IN PKPRCB Prcb)
 
VOID FASTCALL KiDeferredReadyThread (IN PKTHREAD Thread)
 
PKTHREAD FASTCALL KiSelectNextThread (IN PKPRCB Prcb)
 
LONG_PTR FASTCALL KiSwapThread (IN PKTHREAD CurrentThread, IN PKPRCB Prcb)
 
VOID NTAPI KiReadyThread (IN PKTHREAD Thread)
 
VOID NTAPI KiAdjustQuantumThread (IN PKTHREAD Thread)
 
VOID FASTCALL KiSetPriorityThread (IN PKTHREAD Thread, IN KPRIORITY Priority)
 
KAFFINITY FASTCALL KiSetAffinityThread (IN PKTHREAD Thread, IN KAFFINITY Affinity)
 
NTSTATUS NTAPI NtYieldExecution (VOID)
 

Variables

KAFFINITY KiIdleSummary
 
KAFFINITY KiIdleSMTSummary
 

Macro Definition Documentation

◆ InterlockedOrSetMember

#define InterlockedOrSetMember (   Destination,
  SetMember 
)     InterlockedOr((PLONG)Destination, SetMember);

Definition at line 19 of file thrdschd.c.

◆ KiGetCurrentReadySummary

#define KiGetCurrentReadySummary ( )    KeGetCurrentPrcb()->ReadySummary

Definition at line 736 of file thrdschd.c.

◆ NDEBUG

#define NDEBUG

Definition at line 12 of file thrdschd.c.

Function Documentation

◆ KiAdjustQuantumThread()

VOID NTAPI KiAdjustQuantumThread ( IN PKTHREAD  Thread)

Definition at line 461 of file thrdschd.c.

462{
463 PKPRCB Prcb = KeGetCurrentPrcb();
464 PKTHREAD NextThread;
465
466 /* Acquire thread and PRCB lock */
468 KiAcquirePrcbLock(Prcb);
469
470 /* Don't adjust for RT threads */
471 if ((Thread->Priority < LOW_REALTIME_PRIORITY) &&
472 (Thread->BasePriority < (LOW_REALTIME_PRIORITY - 2)))
473 {
474 /* Decrease Quantum by one and see if we've ran out */
475 if (--Thread->Quantum <= 0)
476 {
477 /* Return quantum */
478 Thread->Quantum = Thread->QuantumReset;
479
480 /* Calculate new Priority */
481 Thread->Priority = KiComputeNewPriority(Thread, 1);
482
483 /* Check if there's no next thread scheduled */
484 if (!Prcb->NextThread)
485 {
486 /* Select a ready thread and check if we found one */
487 NextThread = KiSelectReadyThread(Thread->Priority, Prcb);
488 if (NextThread)
489 {
490 /* Set it on standby and switch to it */
491 NextThread->State = Standby;
492 Prcb->NextThread = NextThread;
493 }
494 }
495 else
496 {
497 /* This thread can be preempted again */
498 Thread->Preempted = FALSE;
499 }
500 }
501 }
502
503 /* Release locks */
504 KiReleasePrcbLock(Prcb);
506 KiExitDispatcher(Thread->WaitIrql);
507}
#define FALSE
Definition: types.h:117
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
#define LOW_REALTIME_PRIORITY
FORCEINLINE PKTHREAD KiSelectReadyThread(IN KPRIORITY Priority, IN PKPRCB Prcb)
Definition: ke_x.h:1422
FORCEINLINE VOID KiReleasePrcbLock(IN PKPRCB Prcb)
Definition: ke_x.h:230
FORCEINLINE VOID KiAcquireThreadLock(IN PKTHREAD Thread)
Definition: ke_x.h:240
FORCEINLINE VOID KiReleaseThreadLock(IN PKTHREAD Thread)
Definition: ke_x.h:250
FORCEINLINE VOID KiAcquirePrcbLock(IN PKPRCB Prcb)
Definition: ke_x.h:220
FORCEINLINE SCHAR KiComputeNewPriority(IN PKTHREAD Thread, IN SCHAR Adjustment)
Definition: ke_x.h:1472
FORCEINLINE struct _KPRCB * KeGetCurrentPrcb(VOID)
Definition: ketypes.h:1148
@ Standby
Definition: ketypes.h:391
VOID FASTCALL KiExitDispatcher(KIRQL OldIrql)
struct _KTHREAD * NextThread
Definition: ketypes.h:637
volatile UCHAR State
Definition: ketypes.h:1789

Referenced by KeDelayExecutionThread(), KeWaitForMultipleObjects(), and KeWaitForSingleObject().

◆ KiDeferredReadyThread()

VOID FASTCALL KiDeferredReadyThread ( IN PKTHREAD  Thread)

Definition at line 79 of file thrdschd.c.

80{
81 PKPRCB Prcb;
82 BOOLEAN Preempted;
83 ULONG Processor = 0;
84 KPRIORITY OldPriority;
85 PKTHREAD NextThread;
86
87 /* Sanity checks */
88 ASSERT(Thread->State == DeferredReady);
89 ASSERT((Thread->Priority >= 0) && (Thread->Priority <= HIGH_PRIORITY));
90
91 /* Check if we have any adjusts to do */
92 if (Thread->AdjustReason == AdjustBoost)
93 {
94 /* Lock the thread */
96
97 /* Check if the priority is low enough to qualify for boosting */
98 if ((Thread->Priority <= Thread->AdjustIncrement) &&
99 (Thread->Priority < (LOW_REALTIME_PRIORITY - 3)) &&
100 !(Thread->DisableBoost))
101 {
102 /* Calculate the new priority based on the adjust increment */
103 OldPriority = min(Thread->AdjustIncrement + 1,
105
106 /* Make sure we're not decreasing outside of the priority range */
107 ASSERT((Thread->PriorityDecrement >= 0) &&
108 (Thread->PriorityDecrement <= Thread->Priority));
109
110 /* Calculate the new priority decrement based on the boost */
111 Thread->PriorityDecrement += ((SCHAR)OldPriority - Thread->Priority);
112
113 /* Again verify that this decrement is valid */
114 ASSERT((Thread->PriorityDecrement >= 0) &&
115 (Thread->PriorityDecrement <= OldPriority));
116
117 /* Set the new priority */
118 Thread->Priority = (SCHAR)OldPriority;
119 }
120
121 /* We need 4 quanta, make sure we have them, then decrease by one */
122 if (Thread->Quantum < 4) Thread->Quantum = 4;
123 Thread->Quantum--;
124
125 /* Make sure the priority is still valid */
126 ASSERT((Thread->Priority >= 0) && (Thread->Priority <= HIGH_PRIORITY));
127
128 /* Release the lock and clear the adjust reason */
130 Thread->AdjustReason = AdjustNone;
131 }
132 else if (Thread->AdjustReason == AdjustUnwait)
133 {
134 /* Acquire the thread lock and check if this is a real-time thread */
136 if (Thread->Priority < LOW_REALTIME_PRIORITY)
137 {
138 /* It's not real time, but is it time critical? */
139 if (Thread->BasePriority >= (LOW_REALTIME_PRIORITY - 2))
140 {
141 /* It is, so simply reset its quantum */
142 Thread->Quantum = Thread->QuantumReset;
143 }
144 else
145 {
146 /* Has the priority been adjusted previously? */
147 if (!(Thread->PriorityDecrement) && (Thread->AdjustIncrement))
148 {
149 /* Yes, reset its quantum */
150 Thread->Quantum = Thread->QuantumReset;
151 }
152
153 /* Wait code already handles quantum adjustment during APCs */
154 if (Thread->WaitStatus != STATUS_KERNEL_APC)
155 {
156 /* Decrease the quantum by one and check if we're out */
157 if (--Thread->Quantum <= 0)
158 {
159 /* We are, reset the quantum and get a new priority */
160 Thread->Quantum = Thread->QuantumReset;
161 Thread->Priority = KiComputeNewPriority(Thread, 1);
162 }
163 }
164 }
165
166 /* Now check if we have no decrement and boosts are enabled */
167 if (!(Thread->PriorityDecrement) && !(Thread->DisableBoost))
168 {
169 /* Make sure we have an increment */
170 ASSERT(Thread->AdjustIncrement >= 0);
171
172 /* Calculate the new priority after the increment */
173 OldPriority = Thread->BasePriority + Thread->AdjustIncrement;
174
175 /* Check if this is a foreground process */
176 if (CONTAINING_RECORD(Thread->ApcState.Process, EPROCESS, Pcb)->
177 Vm.Flags.MemoryPriority == MEMORY_PRIORITY_FOREGROUND)
178 {
179 /* Apply the foreground boost */
180 OldPriority += PsPrioritySeparation;
181 }
182
183 /* Check if this new priority is higher */
184 if (OldPriority > Thread->Priority)
185 {
186 /* Make sure we don't go into the real time range */
187 if (OldPriority >= LOW_REALTIME_PRIORITY)
188 {
189 /* Normalize it back down one notch */
190 OldPriority = LOW_REALTIME_PRIORITY - 1;
191 }
192
193 /* Check if the priority is higher then the boosted base */
194 if (OldPriority > (Thread->BasePriority +
195 Thread->AdjustIncrement))
196 {
197 /* Setup a priority decrement to nullify the boost */
198 Thread->PriorityDecrement = ((SCHAR)OldPriority -
199 Thread->BasePriority -
200 Thread->AdjustIncrement);
201 }
202
203 /* Make sure that the priority decrement is valid */
204 ASSERT((Thread->PriorityDecrement >= 0) &&
205 (Thread->PriorityDecrement <= OldPriority));
206
207 /* Set this new priority */
208 Thread->Priority = (SCHAR)OldPriority;
209 }
210 }
211 }
212 else
213 {
214 /* It's a real-time thread, so just reset its quantum */
215 Thread->Quantum = Thread->QuantumReset;
216 }
217
218 /* Make sure the priority makes sense */
219 ASSERT((Thread->Priority >= 0) && (Thread->Priority <= HIGH_PRIORITY));
220
221 /* Release the thread lock and reset the adjust reason */
223 Thread->AdjustReason = AdjustNone;
224 }
225
226 /* Clear thread preemption status and save current values */
227 Preempted = Thread->Preempted;
228 OldPriority = Thread->Priority;
229 Thread->Preempted = FALSE;
230
231 /* Queue the thread on CPU 0 and get the PRCB and lock it */
232 Thread->NextProcessor = 0;
233 Prcb = KiProcessorBlock[0];
234 KiAcquirePrcbLock(Prcb);
235
236 /* Check if we have an idle summary */
237 if (KiIdleSummary)
238 {
239 /* Clear it and set this thread as the next one */
240 KiIdleSummary = 0;
241 Thread->State = Standby;
242 Prcb->NextThread = Thread;
243
244 /* Unlock the PRCB and return */
245 KiReleasePrcbLock(Prcb);
246 return;
247 }
248
249 /* Set the CPU number */
250 Thread->NextProcessor = (UCHAR)Processor;
251
252 /* Get the next scheduled thread */
253 NextThread = Prcb->NextThread;
254 if (NextThread)
255 {
256 /* Sanity check */
257 ASSERT(NextThread->State == Standby);
258
259 /* Check if priority changed */
260 if (OldPriority > NextThread->Priority)
261 {
262 /* Preempt the thread */
263 NextThread->Preempted = TRUE;
264
265 /* Put this one as the next one */
266 Thread->State = Standby;
267 Prcb->NextThread = Thread;
268
269 /* Set it in deferred ready mode */
270 NextThread->State = DeferredReady;
271 NextThread->DeferredProcessor = Prcb->Number;
272 KiReleasePrcbLock(Prcb);
273 KiDeferredReadyThread(NextThread);
274 return;
275 }
276 }
277 else
278 {
279 /* Set the next thread as the current thread */
280 NextThread = Prcb->CurrentThread;
281 if (OldPriority > NextThread->Priority)
282 {
283 /* Preempt it if it's already running */
284 if (NextThread->State == Running) NextThread->Preempted = TRUE;
285
286 /* Set the thread on standby and as the next thread */
287 Thread->State = Standby;
288 Prcb->NextThread = Thread;
289
290 /* Release the lock */
291 KiReleasePrcbLock(Prcb);
292
293 /* Check if we're running on another CPU */
294 if (KeGetCurrentProcessorNumber() != Thread->NextProcessor)
295 {
296 /* We are, send an IPI */
297 KiIpiSend(AFFINITY_MASK(Thread->NextProcessor), IPI_DPC);
298 }
299 return;
300 }
301 }
302
303 /* Sanity check */
304 ASSERT((OldPriority >= 0) && (OldPriority <= HIGH_PRIORITY));
305
306 /* Set this thread as ready */
307 Thread->State = Ready;
308 Thread->WaitTime = KeTickCount.LowPart;
309
310 /* Insert this thread in the appropriate order */
311 Preempted ? InsertHeadList(&Prcb->DispatcherReadyListHead[OldPriority],
312 &Thread->WaitListEntry) :
313 InsertTailList(&Prcb->DispatcherReadyListHead[OldPriority],
314 &Thread->WaitListEntry);
315
316 /* Update the ready summary */
317 Prcb->ReadySummary |= PRIORITY_MASK(OldPriority);
318
319 /* Sanity check */
320 ASSERT(OldPriority == Thread->Priority);
321
322 /* Release the lock */
323 KiReleasePrcbLock(Prcb);
324}
unsigned char BOOLEAN
#define TRUE
Definition: types.h:120
LONG KPRIORITY
Definition: compat.h:803
#define InsertTailList(ListHead, Entry)
#define InsertHeadList(ListHead, Entry)
#define MEMORY_PRIORITY_FOREGROUND
Definition: pstypes.h:126
#define HIGH_PRIORITY
#define ASSERT(a)
Definition: mode.c:44
#define min(a, b)
Definition: monoChain.cc:55
#define IPI_DPC
Definition: ketypes.h:298
FORCEINLINE KAFFINITY AFFINITY_MASK(ULONG Index)
Definition: kefuncs.h:39
@ Ready
Definition: ketypes.h:389
@ Running
Definition: ketypes.h:390
@ DeferredReady
Definition: ketypes.h:395
@ AdjustUnwait
Definition: ketypes.h:440
@ AdjustNone
Definition: ketypes.h:439
@ AdjustBoost
Definition: ketypes.h:441
NTKERNELAPI volatile KSYSTEM_TIME KeTickCount
Definition: clock.c:19
#define PRIORITY_MASK(Priority)
Definition: ke.h:158
PKPRCB KiProcessorBlock[]
Definition: krnlinit.c:32
VOID FASTCALL KiIpiSend(KAFFINITY TargetSet, ULONG IpiRequest)
#define STATUS_KERNEL_APC
Definition: ntstatus.h:79
ULONG PsPrioritySeparation
Definition: process.c:28
FORCEINLINE ULONG KeGetCurrentProcessorNumber(VOID)
Definition: ke.h:341
signed char SCHAR
Definition: sqltypes.h:14
struct _KTHREAD * CurrentThread
Definition: ketypes.h:636
USHORT Number
Definition: ketypes.h:629
ULONG ReadySummary
Definition: ketypes.h:796
LIST_ENTRY DispatcherReadyListHead[32]
Definition: ketypes.h:801
ULONG LowPart
Definition: ketypes.h:929
SCHAR Priority
Definition: ketypes.h:1782
ULONG DeferredProcessor
Definition: ketypes.h:1906
UCHAR Preempted
Definition: ketypes.h:1927
KAFFINITY KiIdleSummary
Definition: thrdschd.c:25
VOID FASTCALL KiDeferredReadyThread(IN PKTHREAD Thread)
Definition: thrdschd.c:79
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
_In_ UCHAR Processor
Definition: kefuncs.h:670
unsigned char UCHAR
Definition: xmlstorage.h:181

Referenced by _Requires_lock_held_(), KiDeferredReadyThread(), KiInsertDeferredReadyList(), and KiProcessDeferredReadyList().

◆ KiIdleSchedule()

PKTHREAD FASTCALL KiIdleSchedule ( IN PKPRCB  Prcb)

Definition at line 32 of file thrdschd.c.

33{
34 /* FIXME: TODO */
35 ASSERTMSG("SMP: Not yet implemented\n", FALSE);
36 return NULL;
37}
#define NULL
Definition: types.h:112
#define ASSERTMSG(msg, exp)
Definition: nt_native.h:431

◆ KiProcessDeferredReadyList()

VOID FASTCALL KiProcessDeferredReadyList ( IN PKPRCB  Prcb)

Definition at line 41 of file thrdschd.c.

42{
43 PSINGLE_LIST_ENTRY ListEntry;
45
46 /* Make sure there is something on the ready list */
47 ASSERT(Prcb->DeferredReadyListHead.Next != NULL);
48
49 /* Get the first entry and clear the list */
50 ListEntry = Prcb->DeferredReadyListHead.Next;
51 Prcb->DeferredReadyListHead.Next = NULL;
52
53 /* Start processing loop */
54 do
55 {
56 /* Get the thread and advance to the next entry */
57 Thread = CONTAINING_RECORD(ListEntry, KTHREAD, SwapListEntry);
58 ListEntry = ListEntry->Next;
59
60 /* Make the thread ready */
62 } while (ListEntry != NULL);
63
64 /* Make sure the ready list is still empty */
65 ASSERT(Prcb->DeferredReadyListHead.Next == NULL);
66}
HRESULT Next([in] ULONG celt, [out, size_is(celt), length_is(*pceltFetched)] STATPROPSETSTG *rgelt, [out] ULONG *pceltFetched)
Definition: ntbasedef.h:628
struct _SINGLE_LIST_ENTRY * Next
Definition: ntbasedef.h:629

Referenced by KiRetireDpcList().

◆ KiQueueReadyThread()

VOID FASTCALL KiQueueReadyThread ( IN PKTHREAD  Thread,
IN PKPRCB  Prcb 
)

Definition at line 70 of file thrdschd.c.

72{
73 /* Call the macro. We keep the API for compatibility with ASM code */
74 KxQueueReadyThread(Thread, Prcb);
75}

◆ KiReadyThread()

VOID NTAPI KiReadyThread ( IN PKTHREAD  Thread)

Definition at line 429 of file thrdschd.c.

430{
431 IN PKPROCESS Process = Thread->ApcState.Process;
432
433 /* Check if the process is paged out */
434 if (Process->State != ProcessInMemory)
435 {
436 /* We don't page out processes in ROS */
437 ASSERT(FALSE);
438 }
439 else if (!Thread->KernelStackResident)
440 {
441 /* Increase the stack count */
442 ASSERT(Process->StackCount != MAXULONG_PTR);
443 Process->StackCount++;
444
445 /* Set the thread to transition */
446 ASSERT(Thread->State != Transition);
447 Thread->State = Transition;
448
449 /* The stack is always resident in ROS */
450 ASSERT(FALSE);
451 }
452 else
453 {
454 /* Insert the thread on the deferred ready list */
456 }
457}
#define MAXULONG_PTR
Definition: basetsd.h:103
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:223
FORCEINLINE VOID KiInsertDeferredReadyList(IN PKTHREAD Thread)
Definition: ke_x.h:185
@ ProcessInMemory
Definition: ketypes.h:460
@ Transition
Definition: ketypes.h:394
#define IN
Definition: typedefs.h:39

Referenced by KeReadyThread(), KeSetEventBoostPriority(), KeSignalGateBoostPriority(), KiAttachProcess(), KiInsertQueue(), and KiUnwaitThread().

◆ KiSelectNextThread()

PKTHREAD FASTCALL KiSelectNextThread ( IN PKPRCB  Prcb)

Definition at line 328 of file thrdschd.c.

329{
331
332 /* Select a ready thread */
333 Thread = KiSelectReadyThread(0, Prcb);
334 if (!Thread)
335 {
336 /* Didn't find any, get the current idle thread */
337 Thread = Prcb->IdleThread;
338
339 /* Enable idle scheduling */
340 InterlockedOrSetMember(&KiIdleSummary, Prcb->SetMember);
341 Prcb->IdleSchedule = TRUE;
342
343 /* FIXME: SMT support */
344 ASSERTMSG("SMP: Not yet implemented\n", FALSE);
345 }
346
347 /* Sanity checks and return the thread */
348 ASSERT(Thread != NULL);
349 ASSERT((Thread->BasePriority == 0) || (Thread->Priority != 0));
350 return Thread;
351}
#define InterlockedOrSetMember(Destination, SetMember)
Definition: thrdschd.c:19

Referenced by KeRevertToUserAffinityThread(), and KeSetSystemAffinityThread().

◆ KiSetAffinityThread()

KAFFINITY FASTCALL KiSetAffinityThread ( IN PKTHREAD  Thread,
IN KAFFINITY  Affinity 
)

Definition at line 685 of file thrdschd.c.

687{
688 KAFFINITY OldAffinity;
689
690 /* Get the current affinity */
691 OldAffinity = Thread->UserAffinity;
692
693 /* Make sure that the affinity is valid */
694 if (((Affinity & Thread->ApcState.Process->Affinity) != (Affinity)) ||
695 (!Affinity))
696 {
697 /* Bugcheck the system */
698 KeBugCheck(INVALID_AFFINITY_SET);
699 }
700
701 /* Update the new affinity */
702 Thread->UserAffinity = Affinity;
703
704 /* Check if system affinity is disabled */
705 if (!Thread->SystemAffinityActive)
706 {
707#ifdef CONFIG_SMP
708 /* FIXME: TODO */
709 DPRINT1("Affinity support disabled!\n");
710#endif
711 }
712
713 /* Return the old affinity */
714 return OldAffinity;
715}
#define DPRINT1
Definition: precomp.h:8
DECLSPEC_NORETURN VOID NTAPI KeBugCheck(ULONG BugCheckCode)
Definition: bug.c:1431
ULONG_PTR KAFFINITY
Definition: compat.h:85
_In_ ULONG _In_ ULONG _In_ ULONG _Out_ PKIRQL _Out_ PKAFFINITY Affinity
Definition: halfuncs.h:174

Referenced by KeSetAffinityProcess(), and KeSetAffinityThread().

◆ KiSetPriorityThread()

VOID FASTCALL KiSetPriorityThread ( IN PKTHREAD  Thread,
IN KPRIORITY  Priority 
)

Definition at line 511 of file thrdschd.c.

513{
514 PKPRCB Prcb;
516 BOOLEAN RequestInterrupt = FALSE;
517 KPRIORITY OldPriority;
518 PKTHREAD NewThread;
519 ASSERT((Priority >= 0) && (Priority <= HIGH_PRIORITY));
520
521 /* Check if priority changed */
522 if (Thread->Priority != Priority)
523 {
524 /* Loop priority setting in case we need to start over */
525 for (;;)
526 {
527 /* Choose action based on thread's state */
528 if (Thread->State == Ready)
529 {
530 /* Make sure we're not on the ready queue */
531 if (!Thread->ProcessReadyQueue)
532 {
533 /* Get the PRCB for the thread and lock it */
534 Processor = Thread->NextProcessor;
536 KiAcquirePrcbLock(Prcb);
537
538 /* Make sure the thread is still ready and on this CPU */
539 if ((Thread->State == Ready) &&
540 (Thread->NextProcessor == Prcb->Number))
541 {
542 /* Sanity check */
543 ASSERT((Prcb->ReadySummary &
544 PRIORITY_MASK(Thread->Priority)));
545
546 /* Remove it from the current queue */
547 if (RemoveEntryList(&Thread->WaitListEntry))
548 {
549 /* Update the ready summary */
551 Priority);
552 }
553
554 /* Update priority */
555 Thread->Priority = (SCHAR)Priority;
556
557 /* Re-insert it at its current priority */
559
560 /* Release the PRCB Lock */
561 KiReleasePrcbLock(Prcb);
562 }
563 else
564 {
565 /* Release the lock and loop again */
566 KiReleasePrcbLock(Prcb);
567 continue;
568 }
569 }
570 else
571 {
572 /* It's already on the ready queue, just update priority */
573 Thread->Priority = (SCHAR)Priority;
574 }
575 }
576 else if (Thread->State == Standby)
577 {
578 /* Get the PRCB for the thread and lock it */
579 Processor = Thread->NextProcessor;
581 KiAcquirePrcbLock(Prcb);
582
583 /* Check if we're still the next thread to run */
584 if (Thread == Prcb->NextThread)
585 {
586 /* Get the old priority and update ours */
587 OldPriority = Thread->Priority;
588 Thread->Priority = (SCHAR)Priority;
589
590 /* Check if there was a change */
591 if (Priority < OldPriority)
592 {
593 /* Find a new thread */
594 NewThread = KiSelectReadyThread(Priority + 1, Prcb);
595 if (NewThread)
596 {
597 /* Found a new one, set it on standby */
598 NewThread->State = Standby;
599 Prcb->NextThread = NewThread;
600
601 /* Dispatch our thread */
603 }
604 }
605
606 /* Release the PRCB lock */
607 KiReleasePrcbLock(Prcb);
608 }
609 else
610 {
611 /* Release the lock and try again */
612 KiReleasePrcbLock(Prcb);
613 continue;
614 }
615 }
616 else if (Thread->State == Running)
617 {
618 /* Get the PRCB for the thread and lock it */
619 Processor = Thread->NextProcessor;
621 KiAcquirePrcbLock(Prcb);
622
623 /* Check if we're still the current thread running */
624 if (Thread == Prcb->CurrentThread)
625 {
626 /* Get the old priority and update ours */
627 OldPriority = Thread->Priority;
628 Thread->Priority = (SCHAR)Priority;
629
630 /* Check if there was a change and there's no new thread */
631 if ((Priority < OldPriority) && !(Prcb->NextThread))
632 {
633 /* Find a new thread */
634 NewThread = KiSelectReadyThread(Priority + 1, Prcb);
635 if (NewThread)
636 {
637 /* Found a new one, set it on standby */
638 NewThread->State = Standby;
639 Prcb->NextThread = NewThread;
640
641 /* Request an interrupt */
642 RequestInterrupt = TRUE;
643 }
644 }
645
646 /* Release the lock and check if we need an interrupt */
647 KiReleasePrcbLock(Prcb);
648 if (RequestInterrupt)
649 {
650 /* Check if we're running on another CPU */
652 {
653 /* We are, send an IPI */
655 }
656 }
657 }
658 else
659 {
660 /* Thread changed, release lock and restart */
661 KiReleasePrcbLock(Prcb);
662 continue;
663 }
664 }
665 else if (Thread->State == DeferredReady)
666 {
667 /* FIXME: TODO */
668 DPRINT1("Deferred state not yet supported\n");
669 ASSERT(FALSE);
670 }
671 else
672 {
673 /* Any other state, just change priority */
674 Thread->Priority = (SCHAR)Priority;
675 }
676
677 /* If we got here, then thread state was consistent, so bail out */
678 break;
679 }
680 }
681}
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986
_In_ WDFINTERRUPT _In_ WDF_INTERRUPT_POLICY _In_ WDF_INTERRUPT_PRIORITY Priority
Definition: wdfinterrupt.h:655

Referenced by ExpBoostOwnerThread(), KeBoostPriorityThread(), KeSetBasePriorityThread(), KeSetPriorityAndQuantumProcess(), and KeSetPriorityThread().

◆ KiSwapThread()

LONG_PTR FASTCALL KiSwapThread ( IN PKTHREAD  CurrentThread,
IN PKPRCB  Prcb 
)

Definition at line 355 of file thrdschd.c.

357{
359 KIRQL WaitIrql;
360 LONG_PTR WaitStatus;
361 PKTHREAD NextThread;
363
364 /* Acquire the PRCB lock */
365 KiAcquirePrcbLock(Prcb);
366
367 /* Get the next thread */
368 NextThread = Prcb->NextThread;
369 if (NextThread)
370 {
371 /* Already got a thread, set it up */
372 Prcb->NextThread = NULL;
373 Prcb->CurrentThread = NextThread;
374 NextThread->State = Running;
375 }
376 else
377 {
378 /* Try to find a ready thread */
379 NextThread = KiSelectReadyThread(0, Prcb);
380 if (NextThread)
381 {
382 /* Switch to it */
383 Prcb->CurrentThread = NextThread;
384 NextThread->State = Running;
385 }
386 else
387 {
388 /* Set the idle summary */
389 InterlockedOrSetMember(&KiIdleSummary, Prcb->SetMember);
390
391 /* Schedule the idle thread */
392 NextThread = Prcb->IdleThread;
393 Prcb->CurrentThread = NextThread;
394 NextThread->State = Running;
395 }
396 }
397
398 /* Sanity check and release the PRCB */
399 ASSERT(CurrentThread != Prcb->IdleThread);
400 KiReleasePrcbLock(Prcb);
401
402 /* Save the wait IRQL */
403 WaitIrql = CurrentThread->WaitIrql;
404
405 /* Swap contexts */
406 ApcState = KiSwapContext(WaitIrql, CurrentThread);
407
408 /* Get the wait status */
409 WaitStatus = CurrentThread->WaitStatus;
410
411 /* Check if we need to deliver APCs */
412 if (ApcState)
413 {
414 /* Lower to APC_LEVEL */
416
417 /* Deliver APCs */
419 ASSERT(WaitIrql == 0);
420 }
421
422 /* Lower IRQL back to what it was and return the wait status */
423 KeLowerIrql(WaitIrql);
424 return WaitStatus;
425}
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define APC_LEVEL
Definition: env_spec_w32.h:695
#define KeLowerIrql(oldIrql)
Definition: env_spec_w32.h:602
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
__int3264 LONG_PTR
Definition: mstsclib_h.h:276
#define KernelMode
Definition: asm.h:34
BOOLEAN FASTCALL KiSwapContext(IN KIRQL WaitIrql, IN PKTHREAD CurrentThread)
_Out_ PKAPC_STATE ApcState
Definition: mm.h:1765
VOID NTAPI KiDeliverApc(IN KPROCESSOR_MODE DeliveryMode, IN PKEXCEPTION_FRAME ExceptionFrame, IN PKTRAP_FRAME TrapFrame)
Definition: apc.c:302

Referenced by KeDelayExecutionThread(), KeRemoveQueue(), KeTerminateThread(), KeWaitForGate(), KeWaitForMultipleObjects(), and KeWaitForSingleObject().

◆ NtYieldExecution()

NTSTATUS NTAPI NtYieldExecution ( VOID  )

Definition at line 744 of file thrdschd.c.

745{
748 PKPRCB Prcb;
749 PKTHREAD Thread, NextThread;
750
751 /* NB: No instructions (other than entry code) should preceed this line */
752
753 /* Fail if there's no ready summary */
755
756 /* Now get the current thread, set the status... */
759
760 /* Raise IRQL to synch and get the KPRCB now */
762 Prcb = KeGetCurrentPrcb();
763
764 /* Now check if there's still a ready summary */
765 if (Prcb->ReadySummary)
766 {
767 /* Acquire thread and PRCB lock */
769 KiAcquirePrcbLock(Prcb);
770
771 /* Find a new thread to run if none was selected */
772 if (!Prcb->NextThread) Prcb->NextThread = KiSelectReadyThread(1, Prcb);
773
774 /* Make sure we still have a next thread to schedule */
775 NextThread = Prcb->NextThread;
776 if (NextThread)
777 {
778 /* Reset quantum and recalculate priority */
779 Thread->Quantum = Thread->QuantumReset;
780 Thread->Priority = KiComputeNewPriority(Thread, 1);
781
782 /* Release the thread lock */
784
785 /* Set context swap busy */
787
788 /* Set the new thread as running */
789 Prcb->NextThread = NULL;
790 Prcb->CurrentThread = NextThread;
791 NextThread->State = Running;
792
793 /* Setup a yield wait and queue the thread */
794 Thread->WaitReason = WrYieldExecution;
795 KxQueueReadyThread(Thread, Prcb);
796
797 /* Make it wait at APC_LEVEL */
798 Thread->WaitIrql = APC_LEVEL;
799
800 /* Sanity check */
802
803 /* Swap to new thread */
806 }
807 else
808 {
809 /* Release the PRCB and thread lock */
810 KiReleasePrcbLock(Prcb);
812 }
813 }
814
815 /* Lower IRQL and return */
817 return Status;
818}
LONG NTSTATUS
Definition: precomp.h:26
Status
Definition: gdiplustypes.h:25
KIRQL NTAPI KeRaiseIrqlToSynchLevel(VOID)
Definition: pic.c:156
#define KeGetCurrentThread
Definition: hal.h:55
FORCEINLINE VOID KiSetThreadSwapBusy(IN PKTHREAD Thread)
Definition: ke_x.h:210
#define STATUS_NO_YIELD_PERFORMED
Definition: ntstatus.h:150
#define STATUS_SUCCESS
Definition: shellext.h:65
#define KiGetCurrentReadySummary()
Definition: thrdschd.c:736
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:778
@ WrYieldExecution
Definition: ketypes.h:448

Referenced by IntReadConsole(), KeDelayExecutionThread(), and SwitchToThread().

Variable Documentation

◆ KiIdleSMTSummary

KAFFINITY KiIdleSMTSummary

Definition at line 26 of file thrdschd.c.

◆ KiIdleSummary