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");
433 KiRequestApcInterrupt(IN BOOLEAN NeedApc
,
436 /* We deliver instantly on UP */
437 UNREFERENCED_PARAMETER(NeedApc
);
438 UNREFERENCED_PARAMETER(Processor
);
445 KiAcquireDispatcherLock(VOID
)
447 /* Raise to synchronization level and acquire the dispatcher lock */
448 return KeAcquireQueuedSpinLockRaiseToSynch(LockQueueDispatcherLock
);
453 KiReleaseDispatcherLock(IN KIRQL OldIrql
)
455 /* First release the lock */
456 KeReleaseQueuedSpinLockFromDpcLevel(&KeGetCurrentPrcb()->
457 LockQueue
[LockQueueDispatcherLock
]);
459 /* Then exit the dispatcher */
460 KiExitDispatcher(OldIrql
);
464 // This routine inserts a thread into the deferred ready list of the given CPU
468 KiInsertDeferredReadyList(IN PKTHREAD Thread
)
470 PKPRCB Prcb
= KeGetCurrentPrcb();
472 /* Set the thread to deferred state and CPU */
473 Thread
->State
= DeferredReady
;
474 Thread
->DeferredProcessor
= Prcb
->Number
;
476 /* Add it on the list */
477 PushEntryList(&Prcb
->DeferredReadyListHead
, &Thread
->SwapListEntry
);
482 KiRescheduleThread(IN BOOLEAN NewThread
,
485 /* Check if a new thread needs to be scheduled on a different CPU */
486 if ((NewThread
) && !(KeGetPcr()->Number
== Cpu
))
488 /* Send an IPI to request delivery */
489 KiIpiSendRequest(AFFINITY_MASK(Cpu
), IPI_DPC
);
494 // This routine sets the current thread in a swap busy state, which ensure that
495 // nobody else tries to swap it concurrently.
499 KiSetThreadSwapBusy(IN PKTHREAD Thread
)
501 /* Make sure nobody already set it */
502 ASSERT(Thread
->SwapBusy
== FALSE
);
504 /* Set it ourselves */
505 Thread
->SwapBusy
= TRUE
;
509 // This routine acquires the PRCB lock so that only one caller can touch
510 // volatile PRCB data.
512 // Since this is a simple optimized spin-lock, it must be be only acquired
513 // at dispatcher level or higher!
517 KiAcquirePrcbLock(IN PKPRCB Prcb
)
519 /* Make sure we're at a safe level to touch the PRCB lock */
520 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL
);
522 /* Start acquire loop */
525 /* Acquire the lock and break out if we acquired it first */
526 if (!InterlockedExchange(&Prcb
->PrcbLock
, 1)) break;
528 /* Loop until the other CPU releases it */
531 /* Let the CPU know that this is a loop */
533 } while (Prcb
->PrcbLock
);
538 // This routine releases the PRCB lock so that other callers can touch
539 // volatile PRCB data.
541 // Since this is a simple optimized spin-lock, it must be be only acquired
542 // at dispatcher level or higher!
546 KiReleasePrcbLock(IN PKPRCB Prcb
)
548 /* Make sure it's acquired! */
549 ASSERT(Prcb
->PrcbLock
!= 0);
552 InterlockedAnd(&Prcb
->PrcbLock
, 0);
556 // This routine acquires the thread lock so that only one caller can touch
557 // volatile thread data.
559 // Since this is a simple optimized spin-lock, it must be be only acquired
560 // at dispatcher level or higher!
564 KiAcquireThreadLock(IN PKTHREAD Thread
)
566 /* Make sure we're at a safe level to touch the thread lock */
567 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL
);
569 /* Start acquire loop */
572 /* Acquire the lock and break out if we acquired it first */
573 if (!InterlockedExchange(&Thread
->ThreadLock
, 1)) break;
575 /* Loop until the other CPU releases it */
578 /* Let the CPU know that this is a loop */
580 } while (Thread
->ThreadLock
);
585 // This routine releases the thread lock so that other callers can touch
586 // volatile thread data.
588 // Since this is a simple optimized spin-lock, it must be be only acquired
589 // at dispatcher level or higher!
593 KiReleaseThreadLock(IN PKTHREAD Thread
)
596 InterlockedAnd(&Thread
->ThreadLock
, 0);
601 KiCheckDeferredReadyList(IN PKPRCB Prcb
)
603 /* Scan the deferred ready lists if required */
604 if (Prcb
->DeferredReadyListHead
.Next
) KiProcessDeferredReadyList(Prcb
);
609 KiRequestApcInterrupt(IN BOOLEAN NeedApc
,
612 /* Check if we need to request APC delivery */
615 /* Check if it's on another CPU */
616 if (KeGetPcr()->Number
!= Cpu
)
618 /* Send an IPI to request delivery */
619 KiIpiSendRequest(AFFINITY_MASK(Cpu
), IPI_DPC
);
623 /* Request a software interrupt */
624 HalRequestSoftwareInterrupt(APC_LEVEL
);
633 KiAcquireApcLock(IN PKTHREAD Thread
,
634 IN PKLOCK_QUEUE_HANDLE Handle
)
636 /* Acquire the lock and raise to synchronization level */
637 KeAcquireInStackQueuedSpinLockRaiseToSynch(&Thread
->ApcQueueLock
, Handle
);
642 KiAcquireApcLockAtDpcLevel(IN PKTHREAD Thread
,
643 IN PKLOCK_QUEUE_HANDLE Handle
)
645 /* Acquire the lock */
646 KeAcquireInStackQueuedSpinLockAtDpcLevel(&Thread
->ApcQueueLock
, Handle
);
651 KiReleaseApcLock(IN PKLOCK_QUEUE_HANDLE Handle
)
653 /* Release the lock */
654 KeReleaseInStackQueuedSpinLock(Handle
);
659 KiReleaseApcLockFromDpcLevel(IN PKLOCK_QUEUE_HANDLE Handle
)
661 /* Release the lock */
662 KeReleaseInStackQueuedSpinLockFromDpcLevel(Handle
);
667 KiAcquireProcessLock(IN PKPROCESS Process
,
668 IN PKLOCK_QUEUE_HANDLE Handle
)
670 /* Acquire the lock and raise to synchronization level */
671 KeAcquireInStackQueuedSpinLockRaiseToSynch(&Process
->ProcessLock
, Handle
);
676 KiReleaseProcessLock(IN PKLOCK_QUEUE_HANDLE Handle
)
678 /* Release the lock */
679 KeReleaseInStackQueuedSpinLock(Handle
);
683 // This routine queues a thread that is ready on the PRCB's ready lists.
684 // If this thread cannot currently run on this CPU, then the thread is
685 // added to the deferred ready list instead.
687 // This routine must be entered with the PRCB lock held and it will exit
688 // with the PRCB lock released!
692 KxQueueReadyThread(IN PKTHREAD Thread
,
699 ASSERT(Prcb
== KeGetCurrentPrcb());
700 ASSERT(Thread
->State
== Running
);
701 ASSERT(Thread
->NextProcessor
== Prcb
->Number
);
703 /* Check if this thread is allowed to run in this CPU */
705 if ((Thread
->Affinity
) & (Prcb
->SetMember
))
710 /* Set thread ready for execution */
711 Thread
->State
= Ready
;
713 /* Save current priority and if someone had pre-empted it */
714 Priority
= Thread
->Priority
;
715 Preempted
= Thread
->Preempted
;
717 /* We're not pre-empting now, and set the wait time */
718 Thread
->Preempted
= FALSE
;
719 Thread
->WaitTime
= KeTickCount
.LowPart
;
722 ASSERT((Priority
>= 0) && (Priority
<= HIGH_PRIORITY
));
724 /* Insert this thread in the appropriate order */
725 Preempted
? InsertHeadList(&Prcb
->DispatcherReadyListHead
[Priority
],
726 &Thread
->WaitListEntry
) :
727 InsertTailList(&Prcb
->DispatcherReadyListHead
[Priority
],
728 &Thread
->WaitListEntry
);
730 /* Update the ready summary */
731 Prcb
->ReadySummary
|= PRIORITY_MASK(Priority
);
734 ASSERT(Priority
== Thread
->Priority
);
736 /* Release the PRCB lock */
737 KiReleasePrcbLock(Prcb
);
741 /* Otherwise, prepare this thread to be deferred */
742 Thread
->State
= DeferredReady
;
743 Thread
->DeferredProcessor
= Prcb
->Number
;
745 /* Release the lock and defer scheduling */
746 KiReleasePrcbLock(Prcb
);
747 KiDeferredReadyThread(Thread
);
752 // This routine scans for an appropriate ready thread to select at the
753 // given priority and for the given CPU.
757 KiSelectReadyThread(IN KPRIORITY Priority
,
760 LONG PriorityMask
, PrioritySet
, HighPriority
;
761 PLIST_ENTRY ListEntry
;
764 /* Save the current mask and get the priority set for the CPU */
765 PriorityMask
= Priority
;
766 PrioritySet
= Prcb
->ReadySummary
>> (UCHAR
)Priority
;
767 if (!PrioritySet
) return NULL
;
769 /* Get the highest priority possible */
770 BitScanReverse((PULONG
)&HighPriority
, PrioritySet
);
771 ASSERT((PrioritySet
& PRIORITY_MASK(HighPriority
)) != 0);
772 HighPriority
+= PriorityMask
;
774 /* Make sure the list isn't at highest priority */
775 ASSERT(IsListEmpty(&Prcb
->DispatcherReadyListHead
[HighPriority
]) == FALSE
);
777 /* Get the first thread on the list */
778 ListEntry
= &Prcb
->DispatcherReadyListHead
[HighPriority
];
779 Thread
= CONTAINING_RECORD(ListEntry
, KTHREAD
, WaitListEntry
);
781 /* Make sure this thread is here for a reason */
782 ASSERT(HighPriority
== Thread
->Priority
);
783 ASSERT(Thread
->Affinity
& AFFINITY_MASK(Prcb
->Number
));
784 ASSERT(Thread
->NextProcessor
== Prcb
->Number
);
786 /* Remove it from the list */
787 RemoveEntryList(&Thread
->WaitListEntry
);
788 if (IsListEmpty(&Thread
->WaitListEntry
))
790 /* The list is empty now, reset the ready summary */
791 Prcb
->ReadySummary
^= PRIORITY_MASK(HighPriority
);
794 /* Sanity check and return the thread */
795 ASSERT((Thread
== NULL
) ||
796 (Thread
->BasePriority
== 0) ||
797 (Thread
->Priority
!= 0));
802 // This routine computes the new priority for a thread. It is only valid for
803 // threads with priorities in the dynamic priority range.
807 KiComputeNewPriority(IN PKTHREAD Thread
)
811 /* Priority sanity checks */
812 ASSERT((Thread
->PriorityDecrement
>= 0) &&
813 (Thread
->PriorityDecrement
<= Thread
->Priority
));
814 ASSERT((Thread
->Priority
< LOW_REALTIME_PRIORITY
) ?
815 TRUE
: (Thread
->PriorityDecrement
== 0));
817 /* Get the current priority */
818 Priority
= Thread
->Priority
;
819 if (Priority
< LOW_REALTIME_PRIORITY
)
821 /* Set the New Priority and add the Priority Decrement */
822 Priority
+= (Priority
- Thread
->PriorityDecrement
- 1);
824 /* Don't go out of bounds */
825 if (Priority
< Thread
->BasePriority
) Priority
= Thread
->BasePriority
;
827 /* Reset the priority decrement */
828 Thread
->PriorityDecrement
= 0;
832 ASSERT((Thread
->BasePriority
== 0) || (Priority
!= 0));
834 /* Return the new priority */