ReactOS 0.4.16-dev-979-g79f281e
thrdschd.c
Go to the documentation of this file.
1/*
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)
7 */
8
9/* INCLUDES ******************************************************************/
10
11#include <ntoskrnl.h>
12#define NDEBUG
13#include <debug.h>
14
15#ifdef _WIN64
16# define InterlockedOrSetMember(Destination, SetMember) \
17 InterlockedOr64((PLONG64)Destination, SetMember);
18#else
19# define InterlockedOrSetMember(Destination, SetMember) \
20 InterlockedOr((PLONG)Destination, SetMember);
21#endif
22
23/* GLOBALS *******************************************************************/
24
27
28/* FUNCTIONS *****************************************************************/
29
33{
34 /* FIXME: TODO */
35 ASSERTMSG("SMP: Not yet implemented\n", FALSE);
36 return NULL;
37}
38
39VOID
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}
67
68VOID
71 IN PKPRCB Prcb)
72{
73 /* Call the macro. We keep the API for compatibility with ASM code */
74 KxQueueReadyThread(Thread, Prcb);
75}
76
77#ifdef CONFIG_SMP
80KiFindIdealProcessor(
81 _In_ KAFFINITY ProcessorSet,
82 _In_ UCHAR OriginalIdealProcessor)
83{
84 PKPRCB OriginalIdealPrcb;
85 KAFFINITY NodeMask;
87
88 /* Check if we can use the original ideal processor */
89 if (ProcessorSet & AFFINITY_MASK(OriginalIdealProcessor))
90 {
91 /* We can, so use it */
92 return OriginalIdealProcessor;
93 }
94
95 /* Only use active processors */
96 ProcessorSet &= KeActiveProcessors;
97
98 /* Get the original ideal PRCB */
99 OriginalIdealPrcb = KiProcessorBlock[OriginalIdealProcessor];
100
101 /* Check if we can use the original node */
102 NodeMask = OriginalIdealPrcb->ParentNode->ProcessorMask & ProcessorSet;
103 if (NodeMask)
104 {
105 /* Use the node set instead */
106 ProcessorSet = NodeMask;
107 }
108
109 /* Calculate the ideal CPU from the affinity set */
110 BitScanReverseAffinity(&Processor, ProcessorSet);
111 return Processor;
112}
113
114static
115ULONG
118{
119 KAFFINITY PreferredSet, IdleSet;
121
122 /* Start with the affinity */
123 PreferredSet = Thread->Affinity;
124
125 /* If we have matching idle processors, use them */
126 IdleSet = PreferredSet & KiIdleSummary;
127 if (IdleSet != 0)
128 {
129 PreferredSet = IdleSet;
130 }
131
132 /* Check if we can use the ideal processor */
133 if (PreferredSet & AFFINITY_MASK(Thread->IdealProcessor))
134 {
135 return Thread->IdealProcessor;
136 }
137
138 /* Return the first set bit */
141
142 return Processor;
143}
144#else
145#define KiSelectNextProcessor(Thread) 0
146#endif
147
148VOID
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}
398
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}
425
429 IN PKPRCB Prcb)
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}
499
500VOID
501NTAPI
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}
531
532VOID
533NTAPI
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}
581
582VOID
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}
755
756#ifdef CONFIG_SMP
757static
758VOID
759KiUpdateEffectiveAffinityThread(
761{
762 PKPRCB Prcb;
763
764 /* Acquire the thread lock */
766
767 /* Get the PRCB that the thread is to be run on and lock it */
768 Prcb = KiProcessorBlock[Thread->NextProcessor];
769 KiAcquirePrcbLock(Prcb);
770
771 /* Set the thread's affinity and ideal processor */
772 Thread->Affinity = Thread->UserAffinity;
773 Thread->IdealProcessor = Thread->UserIdealProcessor;
774
775 /* Check if the affinity doesn't match with the current processor */
776 if ((Prcb->SetMember & Thread->Affinity) == 0)
777 {
778 if (Thread->State == Running)
779 {
780 /* Check if there is the next thread is selected already */
781 if (Prcb->NextThread == NULL)
782 {
783 /* It is not, select a new thread and set it on standby */
784 Prcb->NextThread = KiSelectNextThread(Prcb);
785 Prcb->NextThread->State = Standby;
786 }
787
788 /* Check if the thread is running on a different processor */
789 if (Prcb != KeGetCurrentPrcb())
790 {
791 /* It is, send an IPI */
792 KiIpiSend(AFFINITY_MASK(Thread->NextProcessor), IPI_DPC);
793 }
794 }
795 else if (Thread->State == Standby)
796 {
797 /* Select a new thread and set it on standby */
798 Prcb->NextThread = KiSelectNextThread(Prcb);
799 Prcb->NextThread->State = Standby;
800
801 /* Insert the thread back into the ready list */
803 }
804 else if (Thread->State == Ready)
805 {
806 /* Remove it from the list */
807 if (RemoveEntryList(&Thread->WaitListEntry))
808 {
809 /* The list is empty now, reset the ready summary */
810 Prcb->ReadySummary &= ~PRIORITY_MASK(Thread->Priority);
811 }
812
813 /* Insert the thread back into the ready list */
815 }
816 }
817
818 KiReleasePrcbLock(Prcb);
820}
821#endif // CONFIG_SMP
822
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}
860
861//
862// This macro exists because NtYieldExecution locklessly attempts to read from
863// the KPRCB's ready summary, and the usual way of going through KeGetCurrentPrcb
864// would require getting fs:1C first (or gs), and then doing another dereference.
865// In an attempt to minimize the amount of instructions and potential race/tear
866// that could happen, Windows seems to define this as a macro that directly acceses
867// the ready summary through a single fs: read by going through the KPCR's PrcbData.
868//
869// See http://research.microsoft.com/en-us/collaboration/global/asia-pacific/programs/trk_case4_process-thread_management.pdf (DEAD_LINK)
870//
871// We need this per-arch because sometimes it's Prcb and sometimes PrcbData, and
872// because on x86 it's FS, and on x64 it's GS (not sure what it is on ARM/PPC).
873//
874#ifdef _M_IX86
875#define KiGetCurrentReadySummary() __readfsdword(FIELD_OFFSET(KIPCR, PrcbData.ReadySummary))
876#elif _M_AMD64
877#define KiGetCurrentReadySummary() __readgsdword(FIELD_OFFSET(KIPCR, Prcb.ReadySummary))
878#else
879#define KiGetCurrentReadySummary() KeGetCurrentPrcb()->ReadySummary
880#endif
881
882/*
883 * @implemented
884 */
886NTAPI
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}
unsigned char BOOLEAN
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
#define MAXULONG_PTR
Definition: basetsd.h:103
DECLSPEC_NORETURN VOID NTAPI KeBugCheck(ULONG BugCheckCode)
Definition: bug.c:1434
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
ULONG_PTR KAFFINITY
Definition: compat.h:85
LONG KPRIORITY
Definition: compat.h:803
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986
#define InsertTailList(ListHead, Entry)
#define InsertHeadList(ListHead, Entry)
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
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:223
Status
Definition: gdiplustypes.h:25
KIRQL NTAPI KeRaiseIrqlToSynchLevel(VOID)
Definition: pic.c:156
#define KeGetCurrentThread
Definition: hal.h:55
#define MEMORY_PRIORITY_FOREGROUND
Definition: pstypes.h:127
NTSYSAPI NTSTATUS WINAPI NtYieldExecution(void)
Definition: thrdschd.c:887
#define LOW_REALTIME_PRIORITY
#define HIGH_PRIORITY
HRESULT Next([in] ULONG celt, [out, size_is(celt), length_is(*pceltFetched)] STATPROPSETSTG *rgelt, [out] ULONG *pceltFetched)
FORCEINLINE PKTHREAD KiSelectReadyThread(IN KPRIORITY Priority, IN PKPRCB Prcb)
Definition: ke_x.h:1422
FORCEINLINE VOID KiSetThreadSwapBusy(IN PKTHREAD Thread)
Definition: ke_x.h:210
FORCEINLINE VOID KiReleasePrcbLock(IN PKPRCB Prcb)
Definition: ke_x.h:230
FORCEINLINE VOID KiAcquireThreadLock(IN PKTHREAD Thread)
Definition: ke_x.h:240
FORCEINLINE VOID KiInsertDeferredReadyList(IN PKTHREAD Thread)
Definition: ke_x.h:185
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
#define ASSERT(a)
Definition: mode.c:44
#define min(a, b)
Definition: monoChain.cc:55
__int3264 LONG_PTR
Definition: mstsclib_h.h:276
FORCEINLINE struct _KPRCB * KeGetCurrentPrcb(VOID)
Definition: ketypes.h:1182
#define IPI_DPC
Definition: ketypes.h:302
#define KernelMode
Definition: asm.h:38
FORCEINLINE KAFFINITY AFFINITY_MASK(ULONG Index)
Definition: kefuncs.h:39
FORCEINLINE BOOLEAN BitScanForwardAffinity(PULONG Index, KAFFINITY Mask)
Definition: kefuncs.h:45
FORCEINLINE BOOLEAN BitScanReverseAffinity(PULONG Index, KAFFINITY Mask)
Definition: kefuncs.h:54
@ ProcessInMemory
Definition: ketypes.h:460
@ Ready
Definition: ketypes.h:389
@ Running
Definition: ketypes.h:390
@ Standby
Definition: ketypes.h:391
@ DeferredReady
Definition: ketypes.h:395
@ Transition
Definition: ketypes.h:394
@ AdjustUnwait
Definition: ketypes.h:440
@ AdjustNone
Definition: ketypes.h:439
@ AdjustBoost
Definition: ketypes.h:441
#define _In_
Definition: no_sal2.h:158
#define ASSERTMSG(msg, exp)
Definition: nt_native.h:431
#define FASTCALL
Definition: nt_native.h:50
NTKERNELAPI volatile KSYSTEM_TIME KeTickCount
Definition: clock.c:19
#define PRIORITY_MASK(Priority)
Definition: ke.h:163
PKPRCB KiProcessorBlock[]
Definition: krnlinit.c:31
BOOLEAN FASTCALL KiSwapContext(IN KIRQL WaitIrql, IN PKTHREAD CurrentThread)
KAFFINITY KeActiveProcessors
Definition: processor.c:16
VOID FASTCALL KiIpiSend(KAFFINITY TargetSet, ULONG IpiRequest)
VOID FASTCALL KiExitDispatcher(KIRQL OldIrql)
_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
CCHAR KeNumberProcessors
Definition: processor.c:19
#define STATUS_KERNEL_APC
Definition: ntstatus.h:79
#define STATUS_NO_YIELD_PERFORMED
Definition: ntstatus.h:150
ULONG PsPrioritySeparation
Definition: process.c:28
FORCEINLINE ULONG KeGetCurrentProcessorNumber(VOID)
Definition: ke.h:341
#define STATUS_SUCCESS
Definition: shellext.h:65
signed char SCHAR
Definition: sqltypes.h:14
USHORT Number
Definition: ketypes.h:652
struct _KTHREAD * CurrentThread
Definition: ketypes.h:659
struct _KTHREAD * NextThread
Definition: ketypes.h:660
UINT64 SetMember
Definition: ketypes.h:671
struct _KNODE * ParentNode
Definition: ketypes.h:844
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
volatile UCHAR State
Definition: ketypes.h:1789
Definition: ntbasedef.h:636
struct _SINGLE_LIST_ENTRY * Next
Definition: ntbasedef.h:637
#define KiSelectNextProcessor(Thread)
Definition: thrdschd.c:145
VOID NTAPI KiReadyThread(IN PKTHREAD Thread)
Definition: thrdschd.c:502
LONG_PTR FASTCALL KiSwapThread(IN PKTHREAD CurrentThread, IN PKPRCB Prcb)
Definition: thrdschd.c:428
PKTHREAD FASTCALL KiIdleSchedule(IN PKPRCB Prcb)
Definition: thrdschd.c:32
#define KiGetCurrentReadySummary()
Definition: thrdschd.c:879
VOID FASTCALL KiQueueReadyThread(IN PKTHREAD Thread, IN PKPRCB Prcb)
Definition: thrdschd.c:70
KAFFINITY KiIdleSummary
Definition: thrdschd.c:25
VOID NTAPI KiAdjustQuantumThread(IN PKTHREAD Thread)
Definition: thrdschd.c:534
KAFFINITY FASTCALL KiSetAffinityThread(IN PKTHREAD Thread, IN KAFFINITY Affinity)
Definition: thrdschd.c:825
VOID FASTCALL KiProcessDeferredReadyList(IN PKPRCB Prcb)
Definition: thrdschd.c:41
VOID FASTCALL KiDeferredReadyThread(IN PKTHREAD Thread)
Definition: thrdschd.c:150
KAFFINITY KiIdleSMTSummary
Definition: thrdschd.c:26
PKTHREAD FASTCALL KiSelectNextThread(IN PKPRCB Prcb)
Definition: thrdschd.c:401
VOID FASTCALL KiSetPriorityThread(IN PKTHREAD Thread, IN KPRIORITY Priority)
Definition: thrdschd.c:584
#define InterlockedOrSetMember(Destination, SetMember)
Definition: thrdschd.c:19
#define NTAPI
Definition: typedefs.h:36
#define IN
Definition: typedefs.h:39
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
_In_ WDFINTERRUPT _In_ WDF_INTERRUPT_POLICY _In_ WDF_INTERRUPT_PRIORITY Priority
Definition: wdfinterrupt.h:655
_In_ ULONG _In_ ULONG _In_ ULONG _Out_ PKIRQL _Out_ PKAFFINITY Affinity
Definition: halfuncs.h:174
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:778
_In_ UCHAR Processor
Definition: kefuncs.h:670
@ WrYieldExecution
Definition: ketypes.h:448
#define NT_VERIFY(exp)
Definition: rtlfuncs.h:3304
unsigned char UCHAR
Definition: xmlstorage.h:181