ReactOS  r76032
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 
39 VOID
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 */
61  KiDeferredReadyThread(Thread);
62  } while (ListEntry != NULL);
63 
64  /* Make sure the ready list is still empty */
65  ASSERT(Prcb->DeferredReadyListHead.Next == NULL);
66 }
67 
68 VOID
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 VOID
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 */
95  KiAcquireThreadLock(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 */
129  KiReleaseThreadLock(Thread);
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 */
135  KiAcquireThreadLock(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 */
222  KiReleaseThreadLock(Thread);
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 }
325 
326 PKTHREAD
327 FASTCALL
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 }
352 
353 LONG_PTR
354 FASTCALL
355 KiSwapThread(IN PKTHREAD CurrentThread,
356  IN PKPRCB Prcb)
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 }
426 
427 VOID
428 NTAPI
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 }
458 
459 VOID
460 NTAPI
462 {
463  PKPRCB Prcb = KeGetCurrentPrcb();
464  PKTHREAD NextThread;
465 
466  /* Acquire thread and PRCB lock */
467  KiAcquireThreadLock(Thread);
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);
505  KiReleaseThreadLock(Thread);
506  KiExitDispatcher(Thread->WaitIrql);
507 }
508 
509 VOID
510 FASTCALL
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;
535  Prcb = KiProcessorBlock[Processor];
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 */
550  Prcb->ReadySummary ^= PRIORITY_MASK(Thread->
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;
580  Prcb = KiProcessorBlock[Processor];
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;
620  Prcb = KiProcessorBlock[Processor];
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 */
651  if (KeGetCurrentProcessorNumber() != Processor)
652  {
653  /* We are, send an IPI */
654  KiIpiSend(AFFINITY_MASK(Processor), IPI_DPC);
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 }
682 
683 KAFFINITY
684 FASTCALL
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 }
716 
717 //
718 // This macro exists because NtYieldExecution locklessly attempts to read from
719 // the KPRCB's ready summary, and the usual way of going through KeGetCurrentPrcb
720 // would require getting fs:1C first (or gs), and then doing another dereference.
721 // In an attempt to minimize the amount of instructions and potential race/tear
722 // that could happen, Windows seems to define this as a macro that directly acceses
723 // the ready summary through a single fs: read by going through the KPCR's PrcbData.
724 //
725 // See http://research.microsoft.com/en-us/collaboration/global/asia-pacific/
726 // programs/trk_case4_process-thread_management.pdf
727 //
728 // We need this per-arch because sometimes it's Prcb and sometimes PrcbData, and
729 // because on x86 it's FS, and on x64 it's GS (not sure what it is on ARM/PPC).
730 //
731 #ifdef _M_IX86
732 #define KiGetCurrentReadySummary() __readfsdword(FIELD_OFFSET(KIPCR, PrcbData.ReadySummary))
733 #elif _M_AMD64
734 #define KiGetCurrentReadySummary() __readgsdword(FIELD_OFFSET(KIPCR, Prcb.ReadySummary))
735 #else
736 #define KiGetCurrentReadySummary() KeGetCurrentPrcb()->ReadySummary
737 #endif
738 
739 /*
740  * @implemented
741  */
742 NTSTATUS
743 NTAPI
745 {
747  KIRQL OldIrql;
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... */
757  Status = STATUS_NO_YIELD_PERFORMED;
758  Thread = KeGetCurrentThread();
759 
760  /* Raise IRQL to synch and get the KPRCB now */
761  OldIrql = KeRaiseIrqlToSynchLevel();
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 */
768  KiAcquireThreadLock(Thread);
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 */
783  KiReleaseThreadLock(Thread);
784 
785  /* Set context swap busy */
786  KiSetThreadSwapBusy(Thread);
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 */
801  ASSERT(OldIrql <= DISPATCH_LEVEL);
802 
803  /* Swap to new thread */
804  KiSwapContext(APC_LEVEL, Thread);
805  Status = STATUS_SUCCESS;
806  }
807  else
808  {
809  /* Release the PRCB and thread lock */
810  KiReleasePrcbLock(Prcb);
811  KiReleaseThreadLock(Thread);
812  }
813  }
814 
815  /* Lower IRQL and return */
816  KeLowerIrql(OldIrql);
817  return Status;
818 }
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
FORCEINLINE VOID KiReleaseThreadLock(IN PKTHREAD Thread)
Definition: ke_x.h:244
ULONG LowPart
Definition: ketypes.h:895
#define IN
Definition: typedefs.h:38
KAFFINITY FASTCALL KiSetAffinityThread(IN PKTHREAD Thread, IN KAFFINITY Affinity)
Definition: thrdschd.c:685
#define TRUE
Definition: types.h:120
#define PRIORITY_MASK(Id)
Definition: ke.h:149
#define KeLowerIrql(oldIrql)
Definition: env_spec_w32.h:602
PKTHREAD FASTCALL KiSelectNextThread(IN PKPRCB Prcb)
Definition: thrdschd.c:328
FORCEINLINE VOID KiReleasePrcbLock(IN PKPRCB Prcb)
Definition: ke_x.h:224
Definition: ntbasedef.h:627
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel)?(CompletionRoutine!=NULL):TRUE)
#define STATUS_NO_YIELD_PERFORMED
Definition: ntstatus.h:150
FORCEINLINE VOID InsertHeadList(_Inout_ PLIST_ENTRY ListHead, _Inout_ __drv_aliasesMem PLIST_ENTRY Entry)
Definition: rtlfuncs.h:201
return STATUS_SUCCESS
Definition: btrfs.c:2664
VOID FASTCALL KiSetPriorityThread(IN PKTHREAD Thread, IN KPRIORITY Priority)
Definition: thrdschd.c:511
FORCEINLINE VOID KiInsertDeferredReadyList(IN PKTHREAD Thread)
Definition: ke_x.h:179
FORCEINLINE VOID KiSetThreadSwapBusy(IN PKTHREAD Thread)
Definition: ke_x.h:204
FORCEINLINE struct _KPRCB * KeGetCurrentPrcb(VOID)
Definition: ketypes.h:1054
_In_ KPRIORITY Priority
Definition: kefuncs.h:516
SCHAR Priority
Definition: ketypes.h:974
#define MAXULONG_PTR
Definition: basetsd.h:102
_In_ UCHAR Processor
Definition: kefuncs.h:695
#define AFFINITY_MASK(Id)
Definition: ke.h:148
#define InsertTailList(ListHead, Entry)
#define LOW_REALTIME_PRIORITY
#define FASTCALL
Definition: nt_native.h:50
BOOLEAN Preempted
Definition: ketypes.h:1212
struct _KTHREAD * NextThread
Definition: ketypes.h:567
LONG KPRIORITY
Definition: compat.h:454
uint32_t ULONG_PTR
Definition: typedefs.h:63
BOOLEAN FASTCALL KiSwapContext(IN KIRQL WaitIrql, IN PKTHREAD CurrentThread)
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
FORCEINLINE ULONG KeGetCurrentProcessorNumber(VOID)
Definition: ke.h:325
FORCEINLINE SCHAR KiComputeNewPriority(IN PKTHREAD Thread, IN SCHAR Adjustment)
Definition: ke_x.h:1458
UCHAR KIRQL
Definition: env_spec_w32.h:591
FORCEINLINE VOID KxQueueReadyThread(IN PKTHREAD Thread, IN PKPRCB Prcb)
Definition: ke_x.h:1343
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define FALSE
Definition: types.h:117
#define KiGetCurrentReadySummary()
Definition: thrdschd.c:736
#define ASSERTMSG(msg, exp)
Definition: nt_native.h:431
LONG_PTR FASTCALL KiSwapThread(IN PKTHREAD CurrentThread, IN PKPRCB Prcb)
Definition: thrdschd.c:355
struct _KTHREAD * CurrentThread
Definition: ketypes.h:566
FORCEINLINE VOID KiAcquirePrcbLock(IN PKPRCB Prcb)
Definition: ke_x.h:214
VOID FASTCALL KiDeferredReadyThread(IN PKTHREAD Thread)
Definition: thrdschd.c:79
smooth NULL
Definition: ftsmooth.c:557
VOID NTAPI KeBugCheck(ULONG BugCheckCode)
Definition: bug.c:1469
#define STATUS_KERNEL_APC
Definition: ntstatus.h:79
#define IPI_DPC
Definition: ketypes.h:233
UCHAR WaitReason
Definition: ketypes.h:1249
VOID FASTCALL KiExitDispatcher(KIRQL OldIrql)
FORCEINLINE VOID KiAcquireThreadLock(IN PKTHREAD Thread)
Definition: ke_x.h:234
SCHAR BasePriority
Definition: ketypes.h:1209
unsigned char BOOLEAN
volatile ULONG DeferredProcessor
Definition: ketypes.h:978
NTSTATUS NTAPI NtYieldExecution(VOID)
Definition: thrdschd.c:744
signed char SCHAR
Definition: sqltypes.h:14
_In_ ULONG _In_ ULONG _In_ ULONG _Out_ PKIRQL _Out_ PKAFFINITY Affinity
Definition: halfuncs.h:170
HRESULT Next([in] ULONG celt, [out, size_is(celt), length_is(*pceltFetched)] STATPROPSETSTG *rgelt, [out] ULONG *pceltFetched)
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
unsigned char UCHAR
Definition: xmlstorage.h:181
struct _SINGLE_LIST_ENTRY * Next
Definition: ntbasedef.h:628
NTKERNELAPI volatile KSYSTEM_TIME KeTickCount
Definition: clock.c:19
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:803
Definition: ketypes.h:370
#define InterlockedOrSetMember(Destination, SetMember)
Definition: thrdschd.c:19
VOID NTAPI KiReadyThread(IN PKTHREAD Thread)
Definition: thrdschd.c:429
VOID FASTCALL KiIpiSend(KAFFINITY TargetSet, ULONG IpiRequest)
Status
Definition: gdiplustypes.h:24
UCHAR QuantumReset
Definition: ketypes.h:1300
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
ULONG ReadySummary
Definition: ketypes.h:726
ULONG_PTR KiIdleSummary
Definition: thrdschd.c:25
LONG NTSTATUS
Definition: DriverTester.h:11
FORCEINLINE PKTHREAD KiSelectReadyThread(IN KPRIORITY Priority, IN PKPRCB Prcb)
Definition: ke_x.h:1408
ULONG_PTR KiIdleSMTSummary
Definition: thrdschd.c:26
ULONG_PTR KAFFINITY
Definition: compat.h:75
PKPRCB KiProcessorBlock[]
Definition: krnlinit.c:32
_Out_ PKAPC_STATE ApcState
Definition: mm.h:1411
ULONG PsPrioritySeparation
Definition: process.c:28
__int3264 LONG_PTR
Definition: mstsclib_h.h:276
#define min(a, b)
Definition: monoChain.cc:55
#define DPRINT1
Definition: precomp.h:8
VOID FASTCALL KiProcessDeferredReadyList(IN PKPRCB Prcb)
Definition: thrdschd.c:41
LIST_ENTRY DispatcherReadyListHead[32]
Definition: ketypes.h:731
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:219
volatile UCHAR State
Definition: ketypes.h:997
USHORT Number
Definition: ketypes.h:559
unsigned int ULONG
Definition: retypes.h:1
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:259
#define HIGH_PRIORITY
#define KeGetCurrentThread
Definition: hal.h:44
#define MEMORY_PRIORITY_FOREGROUND
Definition: pstypes.h:127
VOID NTAPI KiAdjustQuantumThread(IN PKTHREAD Thread)
Definition: thrdschd.c:461
VOID NTAPI KiDeliverApc(IN KPROCESSOR_MODE DeliveryMode, IN PKEXCEPTION_FRAME ExceptionFrame, IN PKTRAP_FRAME TrapFrame)
Definition: apc.c:302
PKTHREAD FASTCALL KiIdleSchedule(IN PKPRCB Prcb)
Definition: thrdschd.c:32
VOID FASTCALL KiQueueReadyThread(IN PKTHREAD Thread, IN PKPRCB Prcb)
Definition: thrdschd.c:70
#define APC_LEVEL
Definition: env_spec_w32.h:695
KIRQL WaitIrql
Definition: ketypes.h:999
KIRQL NTAPI KeRaiseIrqlToSynchLevel(VOID)
Definition: pic.c:156