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
224 KiCheckThreadStackSwap(IN PKTHREAD Thread
,
225 IN KPROCESSOR_MODE WaitMode
)
227 /* Check the required conditions */
228 if ((WaitMode
!= KernelMode
) &&
229 (Thread
->EnableStackSwap
) &&
230 (Thread
->Priority
>= (LOW_REALTIME_PRIORITY
+ 9)))
232 /* We are go for swap */
237 /* Don't swap the thread */
243 // Adds a thread to the wait list
245 #define KiAddThreadToWaitList(Thread, Swappable) \
247 /* Make sure it's swappable */ \
250 /* Insert it into the PRCB's List */ \
251 InsertTailList(&KeGetCurrentPrcb()->WaitListHead, \
252 &Thread->WaitListEntry); \
257 // Checks if a wait in progress should be interrupted by APCs or an alertable
262 KiCheckAlertability(IN PKTHREAD Thread
,
263 IN BOOLEAN Alertable
,
264 IN KPROCESSOR_MODE WaitMode
)
266 /* Check if the wait is alertable */
269 /* It is, first check if the thread is alerted in this mode */
270 if (Thread
->Alerted
[WaitMode
])
272 /* It is, so bail out of the wait */
273 Thread
->Alerted
[WaitMode
] = FALSE
;
274 return STATUS_ALERTED
;
276 else if ((WaitMode
!= KernelMode
) &&
277 (!IsListEmpty(&Thread
->ApcState
.ApcListHead
[UserMode
])))
279 /* It's isn't, but this is a user wait with queued user APCs */
280 Thread
->ApcState
.UserApcPending
= TRUE
;
281 return STATUS_USER_APC
;
283 else if (Thread
->Alerted
[KernelMode
])
285 /* It isn't that either, but we're alered in kernel mode */
286 Thread
->Alerted
[KernelMode
] = FALSE
;
287 return STATUS_ALERTED
;
290 else if ((WaitMode
!= KernelMode
) && (Thread
->ApcState
.UserApcPending
))
292 /* Not alertable, but this is a user wait with pending user APCs */
293 return STATUS_USER_APC
;
296 /* Otherwise, we're fine */
297 return STATUS_WAIT_0
;
302 KxDelayThreadWait(IN PKTHREAD Thread
,
303 IN BOOLEAN Alertable
,
304 IN KPROCESSOR_MODE WaitMode
)
307 PKWAIT_BLOCK TimerBlock
= &Thread
->WaitBlock
[TIMER_WAIT_BLOCK
];
309 /* Setup the Wait Block */
310 Thread
->WaitBlockList
= TimerBlock
;
311 TimerBlock
->NextWaitBlock
= TimerBlock
;
313 /* Link the timer to this Wait Block */
314 Thread
->Timer
.Header
.WaitListHead
.Flink
= &TimerBlock
->WaitListEntry
;
315 Thread
->Timer
.Header
.WaitListHead
.Blink
= &TimerBlock
->WaitListEntry
;
317 /* Clear wait status */
318 Thread
->WaitStatus
= STATUS_WAIT_0
;
320 /* Setup wait fields */
321 Thread
->Alertable
= Alertable
;
322 Thread
->WaitReason
= DelayExecution
;
323 Thread
->WaitMode
= WaitMode
;
325 /* Check if we can swap the thread's stack */
326 Thread
->WaitListEntry
.Flink
= NULL
;
327 Swappable
= KiCheckThreadStackSwap(Thread
, WaitMode
);
329 /* Set the wait time */
330 Thread
->WaitTime
= ((PLARGE_INTEGER
)&KeTickCount
)->LowPart
;
336 KxSingleThreadWait(IN PKTHREAD Thread
,
337 IN PKWAIT_BLOCK WaitBlock
,
339 IN PLARGE_INTEGER Timeout
,
340 IN BOOLEAN Alertable
,
341 IN KWAIT_REASON WaitReason
,
342 IN KPROCESSOR_MODE WaitMode
)
345 PKWAIT_BLOCK TimerBlock
= &Thread
->WaitBlock
[TIMER_WAIT_BLOCK
];
347 /* Setup the Wait Block */
348 Thread
->WaitBlockList
= WaitBlock
;
349 WaitBlock
->WaitKey
= STATUS_WAIT_0
;
350 WaitBlock
->Object
= Object
;
351 WaitBlock
->WaitType
= WaitAny
;
353 /* Clear wait status */
354 Thread
->WaitStatus
= STATUS_WAIT_0
;
356 /* Check if we have a timer */
359 /* Pointer to timer block */
360 WaitBlock
->NextWaitBlock
= TimerBlock
;
361 TimerBlock
->NextWaitBlock
= WaitBlock
;
363 /* Link the timer to this Wait Block */
364 Thread
->Timer
.Header
.WaitListHead
.Flink
= &TimerBlock
->WaitListEntry
;
365 Thread
->Timer
.Header
.WaitListHead
.Blink
= &TimerBlock
->WaitListEntry
;
369 /* No timer block, just ourselves */
370 WaitBlock
->NextWaitBlock
= WaitBlock
;
373 /* Setup wait fields */
374 Thread
->Alertable
= Alertable
;
375 Thread
->WaitReason
= WaitReason
;
376 Thread
->WaitMode
= WaitMode
;
378 /* Check if we can swap the thread's stack */
379 Thread
->WaitListEntry
.Flink
= NULL
;
380 Swappable
= KiCheckThreadStackSwap(Thread
, WaitMode
);
382 /* Set the wait time */
383 Thread
->WaitTime
= ((PLARGE_INTEGER
)&KeTickCount
)->LowPart
;
392 KxUnwaitThread(IN DISPATCHER_HEADER
*Object
,
393 IN KPRIORITY Increment
)
395 PLIST_ENTRY WaitEntry
, WaitList
;
396 PKWAIT_BLOCK CurrentWaitBlock
;
400 /* Loop the Wait Entries */
401 WaitList
= &Object
->WaitListHead
;
402 WaitEntry
= WaitList
->Flink
;
405 /* Get the current wait block */
406 CurrentWaitBlock
= CONTAINING_RECORD(WaitEntry
,
410 /* Get the waiting thread */
411 WaitThread
= CurrentWaitBlock
->Thread
;
413 /* Check the current Wait Mode */
414 if (CurrentWaitBlock
->WaitType
== WaitAny
)
416 /* Use the actual wait key */
417 WaitKey
= CurrentWaitBlock
->WaitKey
;
421 /* Otherwise, use STATUS_KERNEL_APC */
422 WaitKey
= STATUS_KERNEL_APC
;
425 /* Unwait the thread */
426 KiUnwaitThread(WaitThread
, WaitKey
, Increment
);
429 WaitEntry
= WaitList
->Flink
;
430 } while (WaitEntry
!= WaitList
);
434 // Unwaits a Thread waiting on an event
438 KxUnwaitThreadForEvent(IN PKEVENT Event
,
439 IN KPRIORITY Increment
)
441 PLIST_ENTRY WaitEntry
, WaitList
;
442 PKWAIT_BLOCK CurrentWaitBlock
;
445 /* Loop the Wait Entries */
446 WaitList
= &Event
->Header
.WaitListHead
;
447 WaitEntry
= WaitList
->Flink
;
450 /* Get the current wait block */
451 CurrentWaitBlock
= CONTAINING_RECORD(WaitEntry
,
455 /* Get the waiting thread */
456 WaitThread
= CurrentWaitBlock
->Thread
;
458 /* Check the current Wait Mode */
459 if (CurrentWaitBlock
->WaitType
== WaitAny
)
462 Event
->Header
.SignalState
= 0;
464 /* Un-signal the event and unwait the thread */
465 KiUnwaitThread(WaitThread
, CurrentWaitBlock
->WaitKey
, Increment
);
470 /* Unwait the thread with STATUS_KERNEL_APC */
471 KiUnwaitThread(WaitThread
, STATUS_KERNEL_APC
, Increment
);
475 WaitEntry
= WaitList
->Flink
;
476 } while (WaitEntry
!= WaitList
);
481 // Spinlock Acquire at IRQL >= DISPATCH_LEVEL
485 KxAcquireSpinLock(IN PKSPIN_LOCK SpinLock
)
487 /* On UP builds, spinlocks don't exist at IRQL >= DISPATCH */
488 UNREFERENCED_PARAMETER(SpinLock
);
492 // Spinlock Release at IRQL >= DISPATCH_LEVEL
496 KxReleaseSpinLock(IN PKSPIN_LOCK SpinLock
)
498 /* On UP builds, spinlocks don't exist at IRQL >= DISPATCH */
499 UNREFERENCED_PARAMETER(SpinLock
);
503 // This routine protects against multiple CPU acquires, it's meaningless on UP.
507 KiAcquireDispatcherObject(IN DISPATCHER_HEADER
* Object
)
509 UNREFERENCED_PARAMETER(Object
);
513 // This routine protects against multiple CPU acquires, it's meaningless on UP.
517 KiReleaseDispatcherObject(IN DISPATCHER_HEADER
* Object
)
519 UNREFERENCED_PARAMETER(Object
);
524 KiAcquireDispatcherLock(VOID
)
526 /* Raise to DPC level */
527 return KeRaiseIrqlToDpcLevel();
532 KiReleaseDispatcherLock(IN KIRQL OldIrql
)
534 /* Just exit the dispatcher */
535 KiExitDispatcher(OldIrql
);
540 KiAcquireDispatcherLockAtDpcLevel(VOID
)
542 /* This is a no-op at DPC Level for UP systems */
548 KiReleaseDispatcherLockFromDpcLevel(VOID
)
550 /* This is a no-op at DPC Level for UP systems */
555 // This routine makes the thread deferred ready on the boot CPU.
559 KiInsertDeferredReadyList(IN PKTHREAD Thread
)
561 /* Set the thread to deferred state and boot CPU */
562 Thread
->State
= DeferredReady
;
563 Thread
->DeferredProcessor
= 0;
565 /* Make the thread ready immediately */
566 KiDeferredReadyThread(Thread
);
571 KiRescheduleThread(IN BOOLEAN NewThread
,
574 /* This is meaningless on UP systems */
575 UNREFERENCED_PARAMETER(NewThread
);
576 UNREFERENCED_PARAMETER(Cpu
);
580 // This routine protects against multiple CPU acquires, it's meaningless on UP.
584 KiSetThreadSwapBusy(IN PKTHREAD Thread
)
586 UNREFERENCED_PARAMETER(Thread
);
590 // This routine protects against multiple CPU acquires, it's meaningless on UP.
594 KiAcquirePrcbLock(IN PKPRCB Prcb
)
596 UNREFERENCED_PARAMETER(Prcb
);
600 // This routine protects against multiple CPU acquires, it's meaningless on UP.
604 KiReleasePrcbLock(IN PKPRCB Prcb
)
606 UNREFERENCED_PARAMETER(Prcb
);
610 // This routine protects against multiple CPU acquires, it's meaningless on UP.
614 KiAcquireThreadLock(IN PKTHREAD Thread
)
616 UNREFERENCED_PARAMETER(Thread
);
620 // This routine protects against multiple CPU acquires, it's meaningless on UP.
624 KiReleaseThreadLock(IN PKTHREAD Thread
)
626 UNREFERENCED_PARAMETER(Thread
);
630 // This routine protects against multiple CPU acquires, it's meaningless on UP.
634 KiTryThreadLock(IN PKTHREAD Thread
)
636 UNREFERENCED_PARAMETER(Thread
);
642 KiCheckDeferredReadyList(IN PKPRCB Prcb
)
644 /* There are no deferred ready lists on UP systems */
645 UNREFERENCED_PARAMETER(Prcb
);
650 KiRundownThread(IN PKTHREAD Thread
)
652 /* Check if this is the NPX Thread */
653 if (KeGetCurrentPrcb()->NpxThread
== Thread
)
656 KeGetCurrentPrcb()->NpxThread
= NULL
;
658 __asm__("fninit\n\t");
667 KiRequestApcInterrupt(IN BOOLEAN NeedApc
,
670 /* We deliver instantly on UP */
671 UNREFERENCED_PARAMETER(NeedApc
);
672 UNREFERENCED_PARAMETER(Processor
);
678 // Spinlock Acquisition at IRQL >= DISPATCH_LEVEL
682 KxAcquireSpinLock(IN PKSPIN_LOCK SpinLock
)
686 /* Try to acquire it */
687 if (InterlockedBitTestAndSet((PLONG
)SpinLock
, 0))
689 /* Value changed... wait until it's locked */
690 while (*(volatile KSPIN_LOCK
*)SpinLock
== 1)
693 /* On debug builds, we use a much slower but useful routine */
694 Kii386SpinOnSpinLock(SpinLock
, 5);
696 /* Otherwise, just yield and keep looping */
704 /* On debug builds, we OR in the KTHREAD */
705 *SpinLock
= KeGetCurrentThread() | 1;
707 /* All is well, break out */
714 // Spinlock Release at IRQL >= DISPATCH_LEVEL
718 KxReleaseSpinLock(IN PKSPIN_LOCK SpinLock
)
721 /* Make sure that the threads match */
722 if ((KeGetCurrentThread() | 1) != *SpinLock
)
724 /* They don't, bugcheck */
725 KeBugCheckEx(SPIN_LOCK_NOT_OWNED
, SpinLock
, 0, 0, 0);
729 InterlockedAnd(SpinLock
, 0);
734 KiAcquireDispatcherObject(IN DISPATCHER_HEADER
* Object
)
736 LONG OldValue
, NewValue
;
738 /* Make sure we're at a safe level to touch the lock */
739 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL
);
741 /* Start acquire loop */
744 /* Loop until the other CPU releases it */
745 while ((UCHAR
)Object
->Lock
& KOBJECT_LOCK_BIT
)
747 /* Let the CPU know that this is a loop */
751 /* Try acquiring the lock now */
752 NewValue
= InterlockedCompareExchange(&Object
->Lock
,
753 OldValue
| KOBJECT_LOCK_BIT
,
755 } while (NewValue
!= OldValue
);
760 KiReleaseDispatcherObject(IN DISPATCHER_HEADER
* Object
)
762 /* Make sure we're at a safe level to touch the lock */
763 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL
);
766 InterlockedAnd(&Object
->Lock
, ~KOBJECT_LOCK_BIT
);
771 KiAcquireDispatcherLock(VOID
)
773 /* Raise to synchronization level and acquire the dispatcher lock */
774 return KeAcquireQueuedSpinLockRaiseToSynch(LockQueueDispatcherLock
);
779 KiReleaseDispatcherLock(IN KIRQL OldIrql
)
781 /* First release the lock */
782 KeReleaseQueuedSpinLockFromDpcLevel(&KeGetCurrentPrcb()->
783 LockQueue
[LockQueueDispatcherLock
]);
785 /* Then exit the dispatcher */
786 KiExitDispatcher(OldIrql
);
790 // This routine inserts a thread into the deferred ready list of the given CPU
794 KiInsertDeferredReadyList(IN PKTHREAD Thread
)
796 PKPRCB Prcb
= KeGetCurrentPrcb();
798 /* Set the thread to deferred state and CPU */
799 Thread
->State
= DeferredReady
;
800 Thread
->DeferredProcessor
= Prcb
->Number
;
802 /* Add it on the list */
803 PushEntryList(&Prcb
->DeferredReadyListHead
, &Thread
->SwapListEntry
);
808 KiRescheduleThread(IN BOOLEAN NewThread
,
811 /* Check if a new thread needs to be scheduled on a different CPU */
812 if ((NewThread
) && !(KeGetPcr()->Number
== Cpu
))
814 /* Send an IPI to request delivery */
815 KiIpiSendRequest(AFFINITY_MASK(Cpu
), IPI_DPC
);
820 // This routine sets the current thread in a swap busy state, which ensure that
821 // nobody else tries to swap it concurrently.
825 KiSetThreadSwapBusy(IN PKTHREAD Thread
)
827 /* Make sure nobody already set it */
828 ASSERT(Thread
->SwapBusy
== FALSE
);
830 /* Set it ourselves */
831 Thread
->SwapBusy
= TRUE
;
835 // This routine acquires the PRCB lock so that only one caller can touch
836 // volatile PRCB data.
838 // Since this is a simple optimized spin-lock, it must be be only acquired
839 // at dispatcher level or higher!
843 KiAcquirePrcbLock(IN PKPRCB Prcb
)
845 /* Make sure we're at a safe level to touch the PRCB lock */
846 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL
);
848 /* Start acquire loop */
851 /* Acquire the lock and break out if we acquired it first */
852 if (!InterlockedExchange(&Prcb
->PrcbLock
, 1)) break;
854 /* Loop until the other CPU releases it */
857 /* Let the CPU know that this is a loop */
859 } while (Prcb
->PrcbLock
);
864 // This routine releases the PRCB lock so that other callers can touch
865 // volatile PRCB data.
867 // Since this is a simple optimized spin-lock, it must be be only acquired
868 // at dispatcher level or higher!
872 KiReleasePrcbLock(IN PKPRCB Prcb
)
874 /* Make sure it's acquired! */
875 ASSERT(Prcb
->PrcbLock
!= 0);
878 InterlockedAnd(&Prcb
->PrcbLock
, 0);
882 // This routine acquires the thread lock so that only one caller can touch
883 // volatile thread data.
885 // Since this is a simple optimized spin-lock, it must be be only acquired
886 // at dispatcher level or higher!
890 KiAcquireThreadLock(IN PKTHREAD Thread
)
892 /* Make sure we're at a safe level to touch the thread lock */
893 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL
);
895 /* Start acquire loop */
898 /* Acquire the lock and break out if we acquired it first */
899 if (!InterlockedExchange(&Thread
->ThreadLock
, 1)) break;
901 /* Loop until the other CPU releases it */
904 /* Let the CPU know that this is a loop */
906 } while (Thread
->ThreadLock
);
911 // This routine releases the thread lock so that other callers can touch
912 // volatile thread data.
914 // Since this is a simple optimized spin-lock, it must be be only acquired
915 // at dispatcher level or higher!
919 KiReleaseThreadLock(IN PKTHREAD Thread
)
922 InterlockedAnd(&Thread
->ThreadLock
, 0);
927 KiTryThreadLock(IN PKTHREAD Thread
)
931 /* If the lock isn't acquired, return false */
932 if (!Thread
->ThreadLock
) return FALSE
;
934 /* Otherwise, try to acquire it and check the result */
936 Value
= InterlockedExchange(&Thread
->ThreadLock
, &Value
);
938 /* Return the lock state */
939 return (Value
== TRUE
);
944 KiCheckDeferredReadyList(IN PKPRCB Prcb
)
946 /* Scan the deferred ready lists if required */
947 if (Prcb
->DeferredReadyListHead
.Next
) KiProcessDeferredReadyList(Prcb
);
952 KiRequestApcInterrupt(IN BOOLEAN NeedApc
,
955 /* Check if we need to request APC delivery */
958 /* Check if it's on another CPU */
959 if (KeGetPcr()->Number
!= Cpu
)
961 /* Send an IPI to request delivery */
962 KiIpiSendRequest(AFFINITY_MASK(Cpu
), IPI_DPC
);
966 /* Request a software interrupt */
967 HalRequestSoftwareInterrupt(APC_LEVEL
);
976 KiAcquireApcLock(IN PKTHREAD Thread
,
977 IN PKLOCK_QUEUE_HANDLE Handle
)
979 /* Acquire the lock and raise to synchronization level */
980 KeAcquireInStackQueuedSpinLockRaiseToSynch(&Thread
->ApcQueueLock
, Handle
);
985 KiAcquireApcLockAtDpcLevel(IN PKTHREAD Thread
,
986 IN PKLOCK_QUEUE_HANDLE Handle
)
988 /* Acquire the lock */
989 KeAcquireInStackQueuedSpinLockAtDpcLevel(&Thread
->ApcQueueLock
, Handle
);
994 KiAcquireApcLockAtApcLevel(IN PKTHREAD Thread
,
995 IN PKLOCK_QUEUE_HANDLE Handle
)
997 /* Acquire the lock */
998 KeAcquireInStackQueuedSpinLock(&Thread
->ApcQueueLock
, Handle
);
1003 KiReleaseApcLock(IN PKLOCK_QUEUE_HANDLE Handle
)
1005 /* Release the lock */
1006 KeReleaseInStackQueuedSpinLock(Handle
);
1011 KiReleaseApcLockFromDpcLevel(IN PKLOCK_QUEUE_HANDLE Handle
)
1013 /* Release the lock */
1014 KeReleaseInStackQueuedSpinLockFromDpcLevel(Handle
);
1019 KiAcquireProcessLock(IN PKPROCESS Process
,
1020 IN PKLOCK_QUEUE_HANDLE Handle
)
1022 /* Acquire the lock and raise to synchronization level */
1023 KeAcquireInStackQueuedSpinLockRaiseToSynch(&Process
->ProcessLock
, Handle
);
1028 KiReleaseProcessLock(IN PKLOCK_QUEUE_HANDLE Handle
)
1030 /* Release the lock */
1031 KeReleaseInStackQueuedSpinLock(Handle
);
1036 KiReleaseProcessLockFromDpcLevel(IN PKLOCK_QUEUE_HANDLE Handle
)
1038 /* Release the lock */
1039 KeReleaseInStackQueuedSpinLockFromDpcLevel(Handle
);
1044 KiAcquireDeviceQueueLock(IN PKDEVICE_QUEUE DeviceQueue
,
1045 IN PKLOCK_QUEUE_HANDLE DeviceLock
)
1047 /* Check if we were called from a threaded DPC */
1048 if (KeGetCurrentPrcb()->DpcThreadActive
)
1050 /* Lock the Queue, we're not at DPC level */
1051 KeAcquireInStackQueuedSpinLock(&DeviceQueue
->Lock
, DeviceLock
);
1055 /* We must be at DPC level, acquire the lock safely */
1056 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
1057 KeAcquireInStackQueuedSpinLockAtDpcLevel(&DeviceQueue
->Lock
,
1064 KiReleaseDeviceQueueLock(IN PKLOCK_QUEUE_HANDLE DeviceLock
)
1066 /* Check if we were called from a threaded DPC */
1067 if (KeGetCurrentPrcb()->DpcThreadActive
)
1069 /* Unlock the Queue, we're not at DPC level */
1070 KeReleaseInStackQueuedSpinLock(DeviceLock
);
1074 /* We must be at DPC level, release the lock safely */
1075 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
1076 KeReleaseInStackQueuedSpinLockFromDpcLevel(DeviceLock
);
1081 // This routine queues a thread that is ready on the PRCB's ready lists.
1082 // If this thread cannot currently run on this CPU, then the thread is
1083 // added to the deferred ready list instead.
1085 // This routine must be entered with the PRCB lock held and it will exit
1086 // with the PRCB lock released!
1090 KxQueueReadyThread(IN PKTHREAD Thread
,
1097 ASSERT(Prcb
== KeGetCurrentPrcb());
1098 ASSERT(Thread
->State
== Running
);
1099 ASSERT(Thread
->NextProcessor
== Prcb
->Number
);
1101 /* Check if this thread is allowed to run in this CPU */
1103 if ((Thread
->Affinity
) & (Prcb
->SetMember
))
1108 /* Set thread ready for execution */
1109 Thread
->State
= Ready
;
1111 /* Save current priority and if someone had pre-empted it */
1112 Priority
= Thread
->Priority
;
1113 Preempted
= Thread
->Preempted
;
1115 /* We're not pre-empting now, and set the wait time */
1116 Thread
->Preempted
= FALSE
;
1117 Thread
->WaitTime
= KeTickCount
.LowPart
;
1120 ASSERT((Priority
>= 0) && (Priority
<= HIGH_PRIORITY
));
1122 /* Insert this thread in the appropriate order */
1123 Preempted
? InsertHeadList(&Prcb
->DispatcherReadyListHead
[Priority
],
1124 &Thread
->WaitListEntry
) :
1125 InsertTailList(&Prcb
->DispatcherReadyListHead
[Priority
],
1126 &Thread
->WaitListEntry
);
1128 /* Update the ready summary */
1129 Prcb
->ReadySummary
|= PRIORITY_MASK(Priority
);
1132 ASSERT(Priority
== Thread
->Priority
);
1134 /* Release the PRCB lock */
1135 KiReleasePrcbLock(Prcb
);
1139 /* Otherwise, prepare this thread to be deferred */
1140 Thread
->State
= DeferredReady
;
1141 Thread
->DeferredProcessor
= Prcb
->Number
;
1143 /* Release the lock and defer scheduling */
1144 KiReleasePrcbLock(Prcb
);
1145 KiDeferredReadyThread(Thread
);
1150 // This routine scans for an appropriate ready thread to select at the
1151 // given priority and for the given CPU.
1155 KiSelectReadyThread(IN KPRIORITY Priority
,
1158 LONG PriorityMask
, PrioritySet
, HighPriority
;
1159 PLIST_ENTRY ListEntry
;
1162 /* Save the current mask and get the priority set for the CPU */
1163 PriorityMask
= Priority
;
1164 PrioritySet
= Prcb
->ReadySummary
>> (UCHAR
)Priority
;
1165 if (!PrioritySet
) return NULL
;
1167 /* Get the highest priority possible */
1168 BitScanReverse((PULONG
)&HighPriority
, PrioritySet
);
1169 ASSERT((PrioritySet
& PRIORITY_MASK(HighPriority
)) != 0);
1170 HighPriority
+= PriorityMask
;
1172 /* Make sure the list isn't at highest priority */
1173 ASSERT(IsListEmpty(&Prcb
->DispatcherReadyListHead
[HighPriority
]) == FALSE
);
1175 /* Get the first thread on the list */
1176 ListEntry
= &Prcb
->DispatcherReadyListHead
[HighPriority
];
1177 Thread
= CONTAINING_RECORD(ListEntry
, KTHREAD
, WaitListEntry
);
1179 /* Make sure this thread is here for a reason */
1180 ASSERT(HighPriority
== Thread
->Priority
);
1181 ASSERT(Thread
->Affinity
& AFFINITY_MASK(Prcb
->Number
));
1182 ASSERT(Thread
->NextProcessor
== Prcb
->Number
);
1184 /* Remove it from the list */
1185 RemoveEntryList(&Thread
->WaitListEntry
);
1186 if (IsListEmpty(&Thread
->WaitListEntry
))
1188 /* The list is empty now, reset the ready summary */
1189 Prcb
->ReadySummary
^= PRIORITY_MASK(HighPriority
);
1192 /* Sanity check and return the thread */
1193 ASSERT((Thread
== NULL
) ||
1194 (Thread
->BasePriority
== 0) ||
1195 (Thread
->Priority
!= 0));
1200 // This routine computes the new priority for a thread. It is only valid for
1201 // threads with priorities in the dynamic priority range.
1205 KiComputeNewPriority(IN PKTHREAD Thread
)
1209 /* Priority sanity checks */
1210 ASSERT((Thread
->PriorityDecrement
>= 0) &&
1211 (Thread
->PriorityDecrement
<= Thread
->Priority
));
1212 ASSERT((Thread
->Priority
< LOW_REALTIME_PRIORITY
) ?
1213 TRUE
: (Thread
->PriorityDecrement
== 0));
1215 /* Get the current priority */
1216 Priority
= Thread
->Priority
;
1217 if (Priority
< LOW_REALTIME_PRIORITY
)
1219 /* Decrease priority by the priority decrement */
1220 Priority
-= (Thread
->PriorityDecrement
+ 1);
1222 /* Don't go out of bounds */
1223 if (Priority
< Thread
->BasePriority
) Priority
= Thread
->BasePriority
;
1225 /* Reset the priority decrement */
1226 Thread
->PriorityDecrement
= 0;
1230 ASSERT((Thread
->BasePriority
== 0) || (Priority
!= 0));
1232 /* Return the new priority */