2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/include/ke_x.h
5 * PURPOSE: Internal Inlined Functions for the Kernel
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
10 // Enters a Guarded Region
12 #define KeEnterGuardedRegion() \
14 PKTHREAD Thread = KeGetCurrentThread(); \
17 ASSERT_IRQL_LESS_OR_EQUAL(APC_LEVEL); \
18 ASSERT(Thread == KeGetCurrentThread()); \
19 ASSERT((Thread->SpecialApcDisable <= 0) && \
20 (Thread->SpecialApcDisable != -32768)); \
22 /* Disable Special APCs */ \
23 Thread->SpecialApcDisable--; \
27 // Leaves a Guarded Region
29 #define KeLeaveGuardedRegion() \
31 PKTHREAD Thread = KeGetCurrentThread(); \
34 ASSERT_IRQL_LESS_OR_EQUAL(APC_LEVEL); \
35 ASSERT(Thread == KeGetCurrentThread()); \
36 ASSERT(Thread->SpecialApcDisable < 0); \
38 /* Leave region and check if APCs are OK now */ \
39 if (!(++Thread->SpecialApcDisable)) \
41 /* Check for Kernel APCs on the list */ \
42 if (!IsListEmpty(&Thread->ApcState. \
43 ApcListHead[KernelMode])) \
45 /* Check for APC Delivery */ \
46 KiCheckForKernelApcDelivery(); \
52 // TODO: Guarded Mutex Routines
56 // Enters a Critical Region
58 #define KeEnterCriticalRegion() \
60 PKTHREAD Thread = KeGetCurrentThread(); \
64 ASSERT(Thread == KeGetCurrentThread()); \
65 ASSERT((Thread->KernelApcDisable <= 0) && \
66 (Thread->KernelApcDisable != -32768)); \
68 /* Disable Kernel APCs */ \
69 Thread->KernelApcDisable--; \
74 // Leaves a Critical Region
76 #define KeLeaveCriticalRegion() \
78 PKTHREAD Thread = KeGetCurrentThread(); \
82 ASSERT(Thread == KeGetCurrentThread()); \
83 ASSERT(Thread->KernelApcDisable < 0); \
85 /* Enable Kernel APCs */ \
86 Thread->KernelApcDisable++; \
88 /* Check if Kernel APCs are now enabled */ \
89 if (!(Thread->KernelApcDisable)) \
91 /* Check if we need to request an APC Delivery */ \
92 if (!(IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) && \
93 !(Thread->KernelApcDisable)) \
95 /* Check for the right environment */ \
96 KiCheckForKernelApcDelivery(); \
103 // Satisfies the wait of any dispatcher object
105 #define KiSatisfyObjectWait(Object, Thread) \
107 /* Special case for Mutants */ \
108 if ((Object)->Header.Type == MutantObject) \
110 /* Decrease the Signal State */ \
111 (Object)->Header.SignalState--; \
113 /* Check if it's now non-signaled */ \
114 if (!(Object)->Header.SignalState) \
116 /* Set the Owner Thread */ \
117 (Object)->OwnerThread = Thread; \
119 /* Disable APCs if needed */ \
120 Thread->KernelApcDisable -= (Object)->ApcDisable; \
122 /* Check if it's abandoned */ \
123 if ((Object)->Abandoned) \
126 (Object)->Abandoned = FALSE; \
128 /* Return Status */ \
129 Thread->WaitStatus = STATUS_ABANDONED; \
132 /* Insert it into the Mutant List */ \
133 InsertHeadList(Thread->MutantListHead.Blink, \
134 &(Object)->MutantListEntry); \
137 else if (((Object)->Header.Type & TIMER_OR_EVENT_TYPE) == \
138 EventSynchronizationObject) \
140 /* Synchronization Timers and Events just get un-signaled */ \
141 (Object)->Header.SignalState = 0; \
143 else if ((Object)->Header.Type == SemaphoreObject) \
145 /* These ones can have multiple states, so we only decrease it */ \
146 (Object)->Header.SignalState--; \
151 // Satisfies the wait of a mutant dispatcher object
153 #define KiSatisfyMutantWait(Object, Thread) \
155 /* Decrease the Signal State */ \
156 (Object)->Header.SignalState--; \
158 /* Check if it's now non-signaled */ \
159 if (!(Object)->Header.SignalState) \
161 /* Set the Owner Thread */ \
162 (Object)->OwnerThread = Thread; \
164 /* Disable APCs if needed */ \
165 Thread->KernelApcDisable -= (Object)->ApcDisable; \
167 /* Check if it's abandoned */ \
168 if ((Object)->Abandoned) \
171 (Object)->Abandoned = FALSE; \
173 /* Return Status */ \
174 Thread->WaitStatus = STATUS_ABANDONED; \
177 /* Insert it into the Mutant List */ \
178 InsertHeadList(Thread->MutantListHead.Blink, \
179 &(Object)->MutantListEntry); \
184 // Satisfies the wait of any nonmutant dispatcher object
186 #define KiSatisfyNonMutantWait(Object, Thread) \
188 if (((Object)->Header.Type & TIMER_OR_EVENT_TYPE) == \
189 EventSynchronizationObject) \
191 /* Synchronization Timers and Events just get un-signaled */ \
192 (Object)->Header.SignalState = 0; \
194 else if ((Object)->Header.Type == SemaphoreObject) \
196 /* These ones can have multiple states, so we only decrease it */ \
197 (Object)->Header.SignalState--; \
202 // Recalculates the due time
206 KiRecalculateDueTime(IN PLARGE_INTEGER OriginalDueTime
,
207 IN PLARGE_INTEGER DueTime
,
208 IN OUT PLARGE_INTEGER NewDueTime
)
210 /* Don't do anything for absolute waits */
211 if (OriginalDueTime
->QuadPart
>= 0) return OriginalDueTime
;
213 /* Otherwise, query the interrupt time and recalculate */
214 NewDueTime
->QuadPart
= KeQueryInterruptTime();
215 NewDueTime
->QuadPart
-= DueTime
->QuadPart
;
220 // Determines wether a thread should be added to the wait list
222 #define KiCheckThreadStackSwap(WaitMode, Thread, Swappable) \
224 /* Check the required conditions */ \
225 if ((WaitMode != KernelMode) && \
226 (Thread->EnableStackSwap) && \
227 (Thread->Priority >= (LOW_REALTIME_PRIORITY + 9))) \
229 /* We are go for swap */ \
234 /* Don't swap the thread */ \
240 // Adds a thread to the wait list
242 #define KiAddThreadToWaitList(Thread, Swappable) \
244 /* Make sure it's swappable */ \
247 /* Insert it into the PRCB's List */ \
248 InsertTailList(&KeGetCurrentPrcb()->WaitListHead, \
249 &Thread->WaitListEntry); \
254 // Rules for checking alertability:
255 // - For Alertable waits ONLY:
256 // * We don't wait and return STATUS_ALERTED if the thread is alerted
257 // in EITHER the specified wait mode OR in Kernel Mode.
258 // - For BOTH Alertable AND Non-Alertable waits:
259 // * We don't want and return STATUS_USER_APC if the User Mode APC list
260 // is not empty AND the wait mode is User Mode.
262 #define KiCheckAlertability() \
266 if (CurrentThread->Alerted[(int)WaitMode]) \
268 CurrentThread->Alerted[(int)WaitMode] = FALSE; \
269 WaitStatus = STATUS_ALERTED; \
272 else if ((WaitMode != KernelMode) && \
273 (!IsListEmpty(&CurrentThread-> \
274 ApcState.ApcListHead[UserMode]))) \
276 CurrentThread->ApcState.UserApcPending = TRUE; \
277 WaitStatus = STATUS_USER_APC; \
280 else if (CurrentThread->Alerted[KernelMode]) \
282 CurrentThread->Alerted[KernelMode] = FALSE; \
283 WaitStatus = STATUS_ALERTED; \
287 else if ((WaitMode != KernelMode) && \
288 (CurrentThread->ApcState.UserApcPending)) \
290 WaitStatus = STATUS_USER_APC; \
296 // Thread Scheduling Routines
301 KiAcquireDispatcherLock(VOID
)
303 /* Raise to DPC level */
304 return KeRaiseIrqlToDpcLevel();
309 KiReleaseDispatcherLock(IN KIRQL OldIrql
)
311 /* Just exit the dispatcher */
312 KiExitDispatcher(OldIrql
);
317 KiAcquireDispatcherLockAtDpcLevel(VOID
)
319 /* This is a no-op at DPC Level for UP systems */
325 KiReleaseDispatcherLockFromDpcLevel(VOID
)
327 /* This is a no-op at DPC Level for UP systems */
332 // This routine makes the thread deferred ready on the boot CPU.
336 KiInsertDeferredReadyList(IN PKTHREAD Thread
)
338 /* Set the thread to deferred state and boot CPU */
339 Thread
->State
= DeferredReady
;
340 Thread
->DeferredProcessor
= 0;
342 /* Make the thread ready immediately */
343 KiDeferredReadyThread(Thread
);
348 KiRescheduleThread(IN BOOLEAN NewThread
,
351 /* This is meaningless on UP systems */
352 UNREFERENCED_PARAMETER(NewThread
);
353 UNREFERENCED_PARAMETER(Cpu
);
357 // This routine protects against multiple CPU acquires, it's meaningless on UP.
361 KiSetThreadSwapBusy(IN PKTHREAD Thread
)
363 UNREFERENCED_PARAMETER(Thread
);
367 // This routine protects against multiple CPU acquires, it's meaningless on UP.
371 KiAcquirePrcbLock(IN PKPRCB Prcb
)
373 UNREFERENCED_PARAMETER(Prcb
);
377 // This routine protects against multiple CPU acquires, it's meaningless on UP.
381 KiReleasePrcbLock(IN PKPRCB Prcb
)
383 UNREFERENCED_PARAMETER(Prcb
);
387 // This routine protects against multiple CPU acquires, it's meaningless on UP.
391 KiAcquireThreadLock(IN PKTHREAD Thread
)
393 UNREFERENCED_PARAMETER(Thread
);
397 // This routine protects against multiple CPU acquires, it's meaningless on UP.
401 KiReleaseThreadLock(IN PKTHREAD Thread
)
403 UNREFERENCED_PARAMETER(Thread
);
408 KiCheckDeferredReadyList(IN PKPRCB Prcb
)
410 /* There are no deferred ready lists on UP systems */
411 UNREFERENCED_PARAMETER(Prcb
);
416 KiRundownThread(IN PKTHREAD Thread
)
418 /* Check if this is the NPX Thread */
419 if (KeGetCurrentPrcb()->NpxThread
== Thread
)
422 KeGetCurrentPrcb()->NpxThread
= NULL
;
424 __asm__("fninit\n\t");
435 KiAcquireDispatcherLock(VOID
)
437 /* Raise to synchronization level and acquire the dispatcher lock */
438 return KeAcquireQueuedSpinLockRaiseToSynch(LockQueueDispatcherLock
);
443 KiReleaseDispatcherLock(IN KIRQL OldIrql
)
445 /* First release the lock */
446 KeReleaseQueuedSpinLockFromDpcLevel(&KeGetCurrentPrcb()->
447 LockQueue
[LockQueueDispatcherLock
]);
449 /* Then exit the dispatcher */
450 KiExitDispatcher(OldIrql
);
454 // This routine inserts a thread into the deferred ready list of the given CPU
458 KiInsertDeferredReadyList(IN PKTHREAD Thread
)
460 PKPRCB Prcb
= KeGetCurrentPrcb();
462 /* Set the thread to deferred state and CPU */
463 Thread
->State
= DeferredReady
;
464 Thread
->DeferredProcessor
= Prcb
->Number
;
466 /* Add it on the list */
467 PushEntryList(&Prcb
->DeferredReadyListHead
, &Thread
->SwapListEntry
);
472 KiRescheduleThread(IN BOOLEAN NewThread
,
475 /* Check if a new thread needs to be scheduled on a different CPU */
476 if ((NewThread
) && !(KeGetPcr()->Number
== Cpu
))
478 /* Send an IPI to request delivery */
479 KiIpiSendRequest(AFFINITY_MASK(Cpu
), IPI_DPC
);
484 // This routine sets the current thread in a swap busy state, which ensure that
485 // nobody else tries to swap it concurrently.
489 KiSetThreadSwapBusy(IN PKTHREAD Thread
)
491 /* Make sure nobody already set it */
492 ASSERT(Thread
->SwapBusy
== FALSE
);
494 /* Set it ourselves */
495 Thread
->SwapBusy
= TRUE
;
499 // This routine acquires the PRCB lock so that only one caller can touch
500 // volatile PRCB data.
502 // Since this is a simple optimized spin-lock, it must be be only acquired
503 // at dispatcher level or higher!
507 KiAcquirePrcbLock(IN PKPRCB Prcb
)
509 /* Make sure we're at a safe level to touch the PRCB lock */
510 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL
);
512 /* Start acquire loop */
515 /* Acquire the lock and break out if we acquired it first */
516 if (!InterlockedExchange(&Prcb
->PrcbLock
, 1)) break;
518 /* Loop until the other CPU releases it */
521 /* Let the CPU know that this is a loop */
523 } while (Prcb
->PrcbLock
);
528 // This routine releases the PRCB lock so that other callers can touch
529 // volatile PRCB data.
531 // Since this is a simple optimized spin-lock, it must be be only acquired
532 // at dispatcher level or higher!
536 KiReleasePrcbLock(IN PKPRCB Prcb
)
538 /* Make sure it's acquired! */
539 ASSERT(Prcb
->PrcbLock
!= 0);
542 InterlockedAnd(&Prcb
->PrcbLock
, 0);
546 // This routine acquires the thread lock so that only one caller can touch
547 // volatile thread data.
549 // Since this is a simple optimized spin-lock, it must be be only acquired
550 // at dispatcher level or higher!
554 KiAcquireThreadLock(IN PKTHREAD Thread
)
556 /* Make sure we're at a safe level to touch the thread lock */
557 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL
);
559 /* Start acquire loop */
562 /* Acquire the lock and break out if we acquired it first */
563 if (!InterlockedExchange(&Thread
->ThreadLock
, 1)) break;
565 /* Loop until the other CPU releases it */
568 /* Let the CPU know that this is a loop */
570 } while (Thread
->ThreadLock
);
575 // This routine releases the thread lock so that other callers can touch
576 // volatile thread data.
578 // Since this is a simple optimized spin-lock, it must be be only acquired
579 // at dispatcher level or higher!
583 KiReleaseThreadLock(IN PKTHREAD Thread
)
586 InterlockedAnd(&Thread
->ThreadLock
, 0);
591 KiCheckDeferredReadyList(IN PKPRCB Prcb
)
593 /* Scan the deferred ready lists if required */
594 if (Prcb
->DeferredReadyListHead
.Next
) KiProcessDeferredReadyList(Prcb
);
601 KiAcquireApcLock(IN PKTHREAD Thread
,
602 IN PKLOCK_QUEUE_HANDLE Handle
)
604 /* Acquire the lock and raise to synchronization level */
605 KeAcquireInStackQueuedSpinLockRaiseToSynch(&Thread
->ApcQueueLock
, Handle
);
610 KiAcquireApcLockAtDpcLevel(IN PKTHREAD Thread
,
611 IN PKLOCK_QUEUE_HANDLE Handle
)
613 /* Acquire the lock */
614 KeAcquireInStackQueuedSpinLockAtDpcLevel(&Thread
->ApcQueueLock
, Handle
);
619 KiReleaseApcLock(IN PKLOCK_QUEUE_HANDLE Handle
)
621 /* Release the lock */
622 KeReleaseInStackQueuedSpinLock(Handle
);
627 KiReleaseApcLockFromDpcLevel(IN PKLOCK_QUEUE_HANDLE Handle
)
629 /* Release the lock */
630 KeReleaseInStackQueuedSpinLockFromDpcLevel(Handle
);
635 KiAcquireProcessLock(IN PKPROCESS Process
,
636 IN PKLOCK_QUEUE_HANDLE Handle
)
638 /* Acquire the lock and raise to synchronization level */
639 KeAcquireInStackQueuedSpinLockRaiseToSynch(&Process
->ProcessLock
, Handle
);
644 KiReleaseProcessLock(IN PKLOCK_QUEUE_HANDLE Handle
)
646 /* Release the lock */
647 KeReleaseInStackQueuedSpinLock(Handle
);
651 // This routine queues a thread that is ready on the PRCB's ready lists.
652 // If this thread cannot currently run on this CPU, then the thread is
653 // added to the deferred ready list instead.
655 // This routine must be entered with the PRCB lock held and it will exit
656 // with the PRCB lock released!
660 KxQueueReadyThread(IN PKTHREAD Thread
,
667 ASSERT(Prcb
== KeGetCurrentPrcb());
668 ASSERT(Thread
->State
== Running
);
669 ASSERT(Thread
->NextProcessor
== Prcb
->Number
);
671 /* Check if this thread is allowed to run in this CPU */
673 if ((Thread
->Affinity
) & (Prcb
->SetMember
))
678 /* Set thread ready for execution */
679 Thread
->State
= Ready
;
681 /* Save current priority and if someone had pre-empted it */
682 Priority
= Thread
->Priority
;
683 Preempted
= Thread
->Preempted
;
685 /* We're not pre-empting now, and set the wait time */
686 Thread
->Preempted
= FALSE
;
687 Thread
->WaitTime
= KeTickCount
.LowPart
;
690 ASSERT((Priority
>= 0) && (Priority
<= HIGH_PRIORITY
));
692 /* Insert this thread in the appropriate order */
693 Preempted
? InsertHeadList(&Prcb
->DispatcherReadyListHead
[Priority
],
694 &Thread
->WaitListEntry
) :
695 InsertTailList(&Prcb
->DispatcherReadyListHead
[Priority
],
696 &Thread
->WaitListEntry
);
698 /* Update the ready summary */
699 Prcb
->ReadySummary
|= PRIORITY_MASK(Priority
);
702 ASSERT(Priority
== Thread
->Priority
);
704 /* Release the PRCB lock */
705 KiReleasePrcbLock(Prcb
);
709 /* Otherwise, prepare this thread to be deferred */
710 Thread
->State
= DeferredReady
;
711 Thread
->DeferredProcessor
= Prcb
->Number
;
713 /* Release the lock and defer scheduling */
714 KiReleasePrcbLock(Prcb
);
715 KiDeferredReadyThread(Thread
);
720 // This routine scans for an appropriate ready thread to select at the
721 // given priority and for the given CPU.
725 KiSelectReadyThread(IN KPRIORITY Priority
,
728 LONG PriorityMask
, PrioritySet
, HighPriority
;
729 PLIST_ENTRY ListEntry
;
732 /* Save the current mask and get the priority set for the CPU */
733 PriorityMask
= Priority
;
734 PrioritySet
= Prcb
->ReadySummary
>> (UCHAR
)Priority
;
735 if (!PrioritySet
) return NULL
;
737 /* Get the highest priority possible */
738 BitScanReverse((PULONG
)&HighPriority
, PrioritySet
);
739 ASSERT((PrioritySet
& PRIORITY_MASK(HighPriority
)) != 0);
740 HighPriority
+= PriorityMask
;
742 /* Make sure the list isn't at highest priority */
743 ASSERT(IsListEmpty(&Prcb
->DispatcherReadyListHead
[HighPriority
]) == FALSE
);
745 /* Get the first thread on the list */
746 ListEntry
= &Prcb
->DispatcherReadyListHead
[HighPriority
];
747 Thread
= CONTAINING_RECORD(ListEntry
, KTHREAD
, WaitListEntry
);
749 /* Make sure this thread is here for a reason */
750 ASSERT(HighPriority
== Thread
->Priority
);
751 ASSERT(Thread
->Affinity
& AFFINITY_MASK(Prcb
->Number
));
752 ASSERT(Thread
->NextProcessor
== Prcb
->Number
);
754 /* Remove it from the list */
755 RemoveEntryList(&Thread
->WaitListEntry
);
756 if (IsListEmpty(&Thread
->WaitListEntry
))
758 /* The list is empty now, reset the ready summary */
759 Prcb
->ReadySummary
^= PRIORITY_MASK(HighPriority
);
762 /* Sanity check and return the thread */
763 ASSERT((Thread
== NULL
) ||
764 (Thread
->BasePriority
== 0) ||
765 (Thread
->Priority
!= 0));
770 // This routine computes the new priority for a thread. It is only valid for
771 // threads with priorities in the dynamic priority range.
775 KiComputeNewPriority(IN PKTHREAD Thread
)
779 /* Priority sanity checks */
780 ASSERT((Thread
->PriorityDecrement
>= 0) &&
781 (Thread
->PriorityDecrement
<= Thread
->Priority
));
782 ASSERT((Thread
->Priority
< LOW_REALTIME_PRIORITY
) ?
783 TRUE
: (Thread
->PriorityDecrement
== 0));
785 /* Get the current priority */
786 Priority
= Thread
->Priority
;
787 if (Priority
< LOW_REALTIME_PRIORITY
)
789 /* Set the New Priority and add the Priority Decrement */
790 Priority
+= (Priority
- Thread
->PriorityDecrement
- 1);
792 /* Don't go out of bounds */
793 if (Priority
< Thread
->BasePriority
) Priority
= Thread
->BasePriority
;
795 /* Reset the priority decrement */
796 Thread
->PriorityDecrement
= 0;
800 ASSERT((Thread
->BasePriority
== 0) || (Priority
!= 0));
802 /* Return the new priority */