ReactOS 0.4.16-dev-981-g80eb313
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 KiSelectNextProcessor(Thread)   0
 
#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 879 of file thrdschd.c.

◆ KiSelectNextProcessor

#define KiSelectNextProcessor (   Thread)    0

Definition at line 145 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 534 of file thrdschd.c.

535{
536 PKPRCB Prcb = KeGetCurrentPrcb();
537 PKTHREAD NextThread;
538
539 /* Acquire thread and PRCB lock */
541 KiAcquirePrcbLock(Prcb);
542
543 /* Don't adjust for RT threads */
544 if ((Thread->Priority < LOW_REALTIME_PRIORITY) &&
545 (Thread->BasePriority < (LOW_REALTIME_PRIORITY - 2)))
546 {
547 /* Decrease Quantum by one and see if we've ran out */
548 if (--Thread->Quantum <= 0)
549 {
550 /* Return quantum */
551 Thread->Quantum = Thread->QuantumReset;
552
553 /* Calculate new Priority */
554 Thread->Priority = KiComputeNewPriority(Thread, 1);
555
556 /* Check if there's no next thread scheduled */
557 if (!Prcb->NextThread)
558 {
559 /* Select a ready thread and check if we found one */
560 NextThread = KiSelectReadyThread(Thread->Priority, Prcb);
561 if (NextThread)
562 {
563 /* Set it on standby and switch to it */
564 NextThread->State = Standby;
565 Prcb->NextThread = NextThread;
566 }
567 }
568 else
569 {
570 /* This thread can be preempted again */
571 Thread->Preempted = FALSE;
572 }
573 }
574 }
575
576 /* Release locks */
577 KiReleasePrcbLock(Prcb);
579 KiExitDispatcher(Thread->WaitIrql);
580}
#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:1182
@ Standby
Definition: ketypes.h:391
VOID FASTCALL KiExitDispatcher(KIRQL OldIrql)
struct _KTHREAD * NextThread
Definition: ketypes.h:660
volatile UCHAR State
Definition: ketypes.h:1789

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

◆ KiDeferredReadyThread()

VOID FASTCALL KiDeferredReadyThread ( IN PKTHREAD  Thread)

Definition at line 150 of file thrdschd.c.

151{
152 PKPRCB Prcb;
153 BOOLEAN Preempted;
155 KPRIORITY OldPriority;
156 PKTHREAD NextThread;
157
158 /* Sanity checks */
159 ASSERT(Thread->State == DeferredReady);
160 ASSERT((Thread->Priority >= 0) && (Thread->Priority <= HIGH_PRIORITY));
161
162 /* Check if we have any adjusts to do */
163 if (Thread->AdjustReason == AdjustBoost)
164 {
165 /* Lock the thread */
167
168 /* Check if the priority is low enough to qualify for boosting */
169 if ((Thread->Priority <= Thread->AdjustIncrement) &&
170 (Thread->Priority < (LOW_REALTIME_PRIORITY - 3)) &&
171 !(Thread->DisableBoost))
172 {
173 /* Calculate the new priority based on the adjust increment */
174 OldPriority = min(Thread->AdjustIncrement + 1,
176
177 /* Make sure we're not decreasing outside of the priority range */
178 ASSERT((Thread->PriorityDecrement >= 0) &&
179 (Thread->PriorityDecrement <= Thread->Priority));
180
181 /* Calculate the new priority decrement based on the boost */
182 Thread->PriorityDecrement += ((SCHAR)OldPriority - Thread->Priority);
183
184 /* Again verify that this decrement is valid */
185 ASSERT((Thread->PriorityDecrement >= 0) &&
186 (Thread->PriorityDecrement <= OldPriority));
187
188 /* Set the new priority */
189 Thread->Priority = (SCHAR)OldPriority;
190 }
191
192 /* We need 4 quanta, make sure we have them, then decrease by one */
193 if (Thread->Quantum < 4) Thread->Quantum = 4;
194 Thread->Quantum--;
195
196 /* Make sure the priority is still valid */
197 ASSERT((Thread->Priority >= 0) && (Thread->Priority <= HIGH_PRIORITY));
198
199 /* Release the lock and clear the adjust reason */
201 Thread->AdjustReason = AdjustNone;
202 }
203 else if (Thread->AdjustReason == AdjustUnwait)
204 {
205 /* Acquire the thread lock and check if this is a real-time thread */
207 if (Thread->Priority < LOW_REALTIME_PRIORITY)
208 {
209 /* It's not real time, but is it time critical? */
210 if (Thread->BasePriority >= (LOW_REALTIME_PRIORITY - 2))
211 {
212 /* It is, so simply reset its quantum */
213 Thread->Quantum = Thread->QuantumReset;
214 }
215 else
216 {
217 /* Has the priority been adjusted previously? */
218 if (!(Thread->PriorityDecrement) && (Thread->AdjustIncrement))
219 {
220 /* Yes, reset its quantum */
221 Thread->Quantum = Thread->QuantumReset;
222 }
223
224 /* Wait code already handles quantum adjustment during APCs */
225 if (Thread->WaitStatus != STATUS_KERNEL_APC)
226 {
227 /* Decrease the quantum by one and check if we're out */
228 if (--Thread->Quantum <= 0)
229 {
230 /* We are, reset the quantum and get a new priority */
231 Thread->Quantum = Thread->QuantumReset;
232 Thread->Priority = KiComputeNewPriority(Thread, 1);
233 }
234 }
235 }
236
237 /* Now check if we have no decrement and boosts are enabled */
238 if (!(Thread->PriorityDecrement) && !(Thread->DisableBoost))
239 {
240 /* Make sure we have an increment */
241 ASSERT(Thread->AdjustIncrement >= 0);
242
243 /* Calculate the new priority after the increment */
244 OldPriority = Thread->BasePriority + Thread->AdjustIncrement;
245
246 /* Check if this is a foreground process */
247 if (CONTAINING_RECORD(Thread->ApcState.Process, EPROCESS, Pcb)->
248 Vm.Flags.MemoryPriority == MEMORY_PRIORITY_FOREGROUND)
249 {
250 /* Apply the foreground boost */
251 OldPriority += PsPrioritySeparation;
252 }
253
254 /* Check if this new priority is higher */
255 if (OldPriority > Thread->Priority)
256 {
257 /* Make sure we don't go into the real time range */
258 if (OldPriority >= LOW_REALTIME_PRIORITY)
259 {
260 /* Normalize it back down one notch */
261 OldPriority = LOW_REALTIME_PRIORITY - 1;
262 }
263
264 /* Check if the priority is higher then the boosted base */
265 if (OldPriority > (Thread->BasePriority +
266 Thread->AdjustIncrement))
267 {
268 /* Setup a priority decrement to nullify the boost */
269 Thread->PriorityDecrement = ((SCHAR)OldPriority -
270 Thread->BasePriority -
271 Thread->AdjustIncrement);
272 }
273
274 /* Make sure that the priority decrement is valid */
275 ASSERT((Thread->PriorityDecrement >= 0) &&
276 (Thread->PriorityDecrement <= OldPriority));
277
278 /* Set this new priority */
279 Thread->Priority = (SCHAR)OldPriority;
280 }
281 }
282 }
283 else
284 {
285 /* It's a real-time thread, so just reset its quantum */
286 Thread->Quantum = Thread->QuantumReset;
287 }
288
289 /* Make sure the priority makes sense */
290 ASSERT((Thread->Priority >= 0) && (Thread->Priority <= HIGH_PRIORITY));
291
292 /* Release the thread lock and reset the adjust reason */
294 Thread->AdjustReason = AdjustNone;
295 }
296
297 /* Clear thread preemption status and save current values */
298 Preempted = Thread->Preempted;
299 OldPriority = Thread->Priority;
300 Thread->Preempted = FALSE;
301
302 /* Select a processor to run on */
304 Thread->NextProcessor = Processor;
305
306 /* Get the PRCB and lock it */
308 KiAcquirePrcbLock(Prcb);
309
310#ifndef CONFIG_SMP
311 /* Check if we have an idle summary */
312 if (KiIdleSummary)
313 {
314 /* Clear it and set this thread as the next one */
315 KiIdleSummary = 0;
316 Thread->State = Standby;
317 Prcb->NextThread = Thread;
318
319 /* Unlock the PRCB and return */
320 KiReleasePrcbLock(Prcb);
321 return;
322 }
323#endif // !CONFIG_SMP
324
325 /* Get the next scheduled thread */
326 NextThread = Prcb->NextThread;
327 if (NextThread)
328 {
329 /* Sanity check */
330 ASSERT(NextThread->State == Standby);
331
332 /* Check if priority changed */
333 if (OldPriority > NextThread->Priority)
334 {
335 /* Preempt the thread */
336 NextThread->Preempted = TRUE;
337
338 /* Put this one as the next one */
339 Thread->State = Standby;
340 Prcb->NextThread = Thread;
341
342 /* Set it in deferred ready mode */
343 NextThread->State = DeferredReady;
344 NextThread->DeferredProcessor = Prcb->Number;
345 KiReleasePrcbLock(Prcb);
346 KiDeferredReadyThread(NextThread);
347 return;
348 }
349 }
350 else
351 {
352 /* Set the next thread as the current thread */
353 NextThread = Prcb->CurrentThread;
354 if (OldPriority > NextThread->Priority)
355 {
356 /* Preempt it if it's already running */
357 if (NextThread->State == Running) NextThread->Preempted = TRUE;
358
359 /* Set the thread on standby and as the next thread */
360 Thread->State = Standby;
361 Prcb->NextThread = Thread;
362
363 /* Release the lock */
364 KiReleasePrcbLock(Prcb);
365
366 /* Check if we're running on another CPU */
367 if (KeGetCurrentProcessorNumber() != Thread->NextProcessor)
368 {
369 /* We are, send an IPI */
370 KiIpiSend(AFFINITY_MASK(Thread->NextProcessor), IPI_DPC);
371 }
372 return;
373 }
374 }
375
376 /* Sanity check */
377 ASSERT((OldPriority >= 0) && (OldPriority <= HIGH_PRIORITY));
378
379 /* Set this thread as ready */
380 Thread->State = Ready;
381 Thread->WaitTime = KeTickCount.LowPart;
382
383 /* Insert this thread in the appropriate order */
384 Preempted ? InsertHeadList(&Prcb->DispatcherReadyListHead[OldPriority],
385 &Thread->WaitListEntry) :
386 InsertTailList(&Prcb->DispatcherReadyListHead[OldPriority],
387 &Thread->WaitListEntry);
388
389 /* Update the ready summary */
390 Prcb->ReadySummary |= PRIORITY_MASK(OldPriority);
391
392 /* Sanity check */
393 ASSERT(OldPriority == Thread->Priority);
394
395 /* Release the lock */
396 KiReleasePrcbLock(Prcb);
397}
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:127
#define HIGH_PRIORITY
#define ASSERT(a)
Definition: mode.c:44
#define min(a, b)
Definition: monoChain.cc:55
#define IPI_DPC
Definition: ketypes.h:302
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:163
PKPRCB KiProcessorBlock[]
Definition: krnlinit.c:31
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
USHORT Number
Definition: ketypes.h:652
struct _KTHREAD * CurrentThread
Definition: ketypes.h:659
ULONG ReadySummary
Definition: ketypes.h:819
LIST_ENTRY DispatcherReadyListHead[32]
Definition: ketypes.h:824
ULONG LowPart
Definition: ketypes.h:929
SCHAR Priority
Definition: ketypes.h:1782
ULONG DeferredProcessor
Definition: ketypes.h:1906
UCHAR Preempted
Definition: ketypes.h:1927
#define KiSelectNextProcessor(Thread)
Definition: thrdschd.c:145
KAFFINITY KiIdleSummary
Definition: thrdschd.c:25
VOID FASTCALL KiDeferredReadyThread(IN PKTHREAD Thread)
Definition: thrdschd.c:150
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
_In_ UCHAR Processor
Definition: kefuncs.h:670

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:636
struct _SINGLE_LIST_ENTRY * Next
Definition: ntbasedef.h:637

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 502 of file thrdschd.c.

503{
504 IN PKPROCESS Process = Thread->ApcState.Process;
505
506 /* Check if the process is paged out */
507 if (Process->State != ProcessInMemory)
508 {
509 /* We don't page out processes in ROS */
510 ASSERT(FALSE);
511 }
512 else if (!Thread->KernelStackResident)
513 {
514 /* Increase the stack count */
515 ASSERT(Process->StackCount != MAXULONG_PTR);
516 Process->StackCount++;
517
518 /* Set the thread to transition */
519 ASSERT(Thread->State != Transition);
520 Thread->State = Transition;
521
522 /* The stack is always resident in ROS */
523 ASSERT(FALSE);
524 }
525 else
526 {
527 /* Insert the thread on the deferred ready list */
529 }
530}
#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 401 of file thrdschd.c.

402{
404
405 /* Select a ready thread */
406 Thread = KiSelectReadyThread(0, Prcb);
407 if (!Thread)
408 {
409 /* Didn't find any, get the current idle thread */
410 Thread = Prcb->IdleThread;
411
412 /* Enable idle scheduling */
413 InterlockedOrSetMember(&KiIdleSummary, Prcb->SetMember);
414 Prcb->IdleSchedule = TRUE;
415
416 /* FIXME: SMT support */
417 //ASSERTMSG("SMP: Not yet implemented\n", FALSE);
418 }
419
420 /* Sanity checks and return the thread */
421 ASSERT(Thread != NULL);
422 //ASSERT((Thread->BasePriority == 0) || (Thread->Priority != 0));
423 return Thread;
424}
#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 825 of file thrdschd.c.

827{
828 KAFFINITY OldAffinity;
829
830 /* Get the current affinity */
831 OldAffinity = Thread->UserAffinity;
832
833 /* Make sure that the affinity is valid */
834 if (((Affinity & Thread->ApcState.Process->Affinity) != (Affinity)) ||
835 (!Affinity))
836 {
837 /* Bugcheck the system */
838 KeBugCheck(INVALID_AFFINITY_SET);
839 }
840
841 /* Update the new affinity */
842 Thread->UserAffinity = Affinity;
843
844#ifdef CONFIG_SMP
845 /* Check if system affinity is not active */
846 if (!Thread->SystemAffinityActive)
847 {
848 /* Calculate the new ideal processor from the affinity set */
849 Thread->UserIdealProcessor =
850 KiFindIdealProcessor(Affinity, Thread->UserIdealProcessor);
851
852 /* Update the effective affinity */
853 KiUpdateEffectiveAffinityThread(Thread);
854 }
855#endif
856
857 /* Return the old affinity */
858 return OldAffinity;
859}
DECLSPEC_NORETURN VOID NTAPI KeBugCheck(ULONG BugCheckCode)
Definition: bug.c:1434
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 584 of file thrdschd.c.

586{
587 PKPRCB Prcb;
589 BOOLEAN RequestInterrupt = FALSE;
590 KPRIORITY OldPriority;
591 PKTHREAD NewThread;
592 ASSERT((Priority >= 0) && (Priority <= HIGH_PRIORITY));
593
594 /* Check if priority changed */
595 if (Thread->Priority != Priority)
596 {
597 /* Loop priority setting in case we need to start over */
598 for (;;)
599 {
600 /* Choose action based on thread's state */
601 if (Thread->State == Ready)
602 {
603 /* Make sure we're not on the ready queue */
604 if (!Thread->ProcessReadyQueue)
605 {
606 /* Get the PRCB for the thread and lock it */
607 Processor = Thread->NextProcessor;
609 KiAcquirePrcbLock(Prcb);
610
611 /* Make sure the thread is still ready and on this CPU */
612 if ((Thread->State == Ready) &&
613 (Thread->NextProcessor == Prcb->Number))
614 {
615 /* Sanity check */
616 ASSERT((Prcb->ReadySummary &
617 PRIORITY_MASK(Thread->Priority)));
618
619 /* Remove it from the current queue */
620 if (RemoveEntryList(&Thread->WaitListEntry))
621 {
622 /* Update the ready summary */
624 Priority);
625 }
626
627 /* Update priority */
628 Thread->Priority = (SCHAR)Priority;
629
630 /* Re-insert it at its current priority */
632
633 /* Release the PRCB Lock */
634 KiReleasePrcbLock(Prcb);
635 }
636 else
637 {
638 /* Release the lock and loop again */
639 KiReleasePrcbLock(Prcb);
640 continue;
641 }
642 }
643 else
644 {
645 /* It's already on the ready queue, just update priority */
646 Thread->Priority = (SCHAR)Priority;
647 }
648 }
649 else if (Thread->State == Standby)
650 {
651 /* Get the PRCB for the thread and lock it */
652 Processor = Thread->NextProcessor;
654 KiAcquirePrcbLock(Prcb);
655
656 /* Check if we're still the next thread to run */
657 if (Thread == Prcb->NextThread)
658 {
659 /* Get the old priority and update ours */
660 OldPriority = Thread->Priority;
661 Thread->Priority = (SCHAR)Priority;
662
663 /* Check if there was a change */
664 if (Priority < OldPriority)
665 {
666 /* Find a new thread */
667 NewThread = KiSelectReadyThread(Priority + 1, Prcb);
668 if (NewThread)
669 {
670 /* Found a new one, set it on standby */
671 NewThread->State = Standby;
672 Prcb->NextThread = NewThread;
673
674 /* Dispatch our thread */
676 }
677 }
678
679 /* Release the PRCB lock */
680 KiReleasePrcbLock(Prcb);
681 }
682 else
683 {
684 /* Release the lock and try again */
685 KiReleasePrcbLock(Prcb);
686 continue;
687 }
688 }
689 else if (Thread->State == Running)
690 {
691 /* Get the PRCB for the thread and lock it */
692 Processor = Thread->NextProcessor;
694 KiAcquirePrcbLock(Prcb);
695
696 /* Check if we're still the current thread running */
697 if (Thread == Prcb->CurrentThread)
698 {
699 /* Get the old priority and update ours */
700 OldPriority = Thread->Priority;
701 Thread->Priority = (SCHAR)Priority;
702
703 /* Check if there was a change and there's no new thread */
704 if ((Priority < OldPriority) && !(Prcb->NextThread))
705 {
706 /* Find a new thread */
707 NewThread = KiSelectReadyThread(Priority + 1, Prcb);
708 if (NewThread)
709 {
710 /* Found a new one, set it on standby */
711 NewThread->State = Standby;
712 Prcb->NextThread = NewThread;
713
714 /* Request an interrupt */
715 RequestInterrupt = TRUE;
716 }
717 }
718
719 /* Release the lock and check if we need an interrupt */
720 KiReleasePrcbLock(Prcb);
721 if (RequestInterrupt)
722 {
723 /* Check if we're running on another CPU */
725 {
726 /* We are, send an IPI */
728 }
729 }
730 }
731 else
732 {
733 /* Thread changed, release lock and restart */
734 KiReleasePrcbLock(Prcb);
735 continue;
736 }
737 }
738 else if (Thread->State == DeferredReady)
739 {
740 /* FIXME: TODO */
741 DPRINT1("Deferred state not yet supported\n");
742 ASSERT(FALSE);
743 }
744 else
745 {
746 /* Any other state, just change priority */
747 Thread->Priority = (SCHAR)Priority;
748 }
749
750 /* If we got here, then thread state was consistent, so bail out */
751 break;
752 }
753 }
754}
#define DPRINT1
Definition: precomp.h:8
#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 428 of file thrdschd.c.

430{
432 KIRQL WaitIrql;
433 LONG_PTR WaitStatus;
434 PKTHREAD NextThread;
436
437 /* Acquire the PRCB lock */
438 KiAcquirePrcbLock(Prcb);
439
440 /* Get the next thread */
441 NextThread = Prcb->NextThread;
442 if (NextThread)
443 {
444 /* Already got a thread, set it up */
445 Prcb->NextThread = NULL;
446 Prcb->CurrentThread = NextThread;
447 NextThread->State = Running;
448 }
449 else
450 {
451 /* Try to find a ready thread */
452 NextThread = KiSelectReadyThread(0, Prcb);
453 if (NextThread)
454 {
455 /* Switch to it */
456 Prcb->CurrentThread = NextThread;
457 NextThread->State = Running;
458 }
459 else
460 {
461 /* Set the idle summary */
462 InterlockedOrSetMember(&KiIdleSummary, Prcb->SetMember);
463
464 /* Schedule the idle thread */
465 NextThread = Prcb->IdleThread;
466 Prcb->CurrentThread = NextThread;
467 NextThread->State = Running;
468 }
469 }
470
471 /* Sanity check and release the PRCB */
472 ASSERT(CurrentThread != Prcb->IdleThread);
473 KiReleasePrcbLock(Prcb);
474
475 /* Save the wait IRQL */
476 WaitIrql = CurrentThread->WaitIrql;
477
478 /* Swap contexts */
479 ApcState = KiSwapContext(WaitIrql, CurrentThread);
480
481 /* Get the wait status */
482 WaitStatus = CurrentThread->WaitStatus;
483
484 /* Check if we need to deliver APCs */
485 if (ApcState)
486 {
487 /* Lower to APC_LEVEL */
489
490 /* Deliver APCs */
492 ASSERT(WaitIrql == 0);
493 }
494
495 /* Lower IRQL back to what it was and return the wait status */
496 KeLowerIrql(WaitIrql);
497 return WaitStatus;
498}
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:38
BOOLEAN FASTCALL KiSwapContext(IN KIRQL WaitIrql, IN PKTHREAD CurrentThread)
_Out_ PKAPC_STATE ApcState
Definition: mm.h:1777
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 887 of file thrdschd.c.

888{
891 PKPRCB Prcb;
892 PKTHREAD Thread, NextThread;
893
894 /* NB: No instructions (other than entry code) should preceed this line */
895
896 /* Fail if there's no ready summary */
898
899 /* Now get the current thread, set the status... */
902
903 /* Raise IRQL to synch and get the KPRCB now */
905 Prcb = KeGetCurrentPrcb();
906
907 /* Now check if there's still a ready summary */
908 if (Prcb->ReadySummary)
909 {
910 /* Acquire thread and PRCB lock */
912 KiAcquirePrcbLock(Prcb);
913
914 /* Find a new thread to run if none was selected */
915 if (!Prcb->NextThread) Prcb->NextThread = KiSelectReadyThread(1, Prcb);
916
917 /* Make sure we still have a next thread to schedule */
918 NextThread = Prcb->NextThread;
919 if (NextThread)
920 {
921 /* Reset quantum and recalculate priority */
922 Thread->Quantum = Thread->QuantumReset;
923 Thread->Priority = KiComputeNewPriority(Thread, 1);
924
925 /* Release the thread lock */
927
928 /* Set context swap busy */
930
931 /* Set the new thread as running */
932 Prcb->NextThread = NULL;
933 Prcb->CurrentThread = NextThread;
934 NextThread->State = Running;
935
936 /* Setup a yield wait and queue the thread */
937 Thread->WaitReason = WrYieldExecution;
938 KxQueueReadyThread(Thread, Prcb);
939
940 /* Make it wait at APC_LEVEL */
941 Thread->WaitIrql = APC_LEVEL;
942
943 /* Sanity check */
945
946 /* Swap to new thread */
949 }
950 else
951 {
952 /* Release the PRCB and thread lock */
953 KiReleasePrcbLock(Prcb);
955 }
956 }
957
958 /* Lower IRQL and return */
960 return Status;
961}
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:879
_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