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; \
300 KxUnwaitThread(IN DISPATCHER_HEADER
*Object
,
301 IN KPRIORITY Increment
)
303 PLIST_ENTRY WaitEntry
, WaitList
;
304 PKWAIT_BLOCK CurrentWaitBlock
;
308 /* Loop the Wait Entries */
309 WaitList
= &Object
->WaitListHead
;
310 WaitEntry
= WaitList
->Flink
;
313 /* Get the current wait block */
314 CurrentWaitBlock
= CONTAINING_RECORD(WaitEntry
,
318 /* Get the waiting thread */
319 WaitThread
= CurrentWaitBlock
->Thread
;
321 /* Check the current Wait Mode */
322 if (CurrentWaitBlock
->WaitType
== WaitAny
)
324 /* Use the actual wait key */
325 WaitKey
= CurrentWaitBlock
->WaitKey
;
329 /* Otherwise, use STATUS_KERNEL_APC */
330 WaitKey
= STATUS_KERNEL_APC
;
333 /* Unwait the thread */
334 KiUnwaitThread(WaitThread
, WaitKey
, Increment
);
337 WaitEntry
= WaitList
->Flink
;
338 } while (WaitEntry
!= WaitList
);
342 // Unwaits a Thread waiting on an event
346 KxUnwaitThreadForEvent(IN PKEVENT Event
,
347 IN KPRIORITY Increment
)
349 PLIST_ENTRY WaitEntry
, WaitList
;
350 PKWAIT_BLOCK CurrentWaitBlock
;
353 /* Loop the Wait Entries */
354 WaitList
= &Event
->Header
.WaitListHead
;
355 WaitEntry
= WaitList
->Flink
;
358 /* Get the current wait block */
359 CurrentWaitBlock
= CONTAINING_RECORD(WaitEntry
,
363 /* Get the waiting thread */
364 WaitThread
= CurrentWaitBlock
->Thread
;
366 /* Check the current Wait Mode */
367 if (CurrentWaitBlock
->WaitType
== WaitAny
)
370 Event
->Header
.SignalState
= 0;
372 /* Un-signal the event and unwait the thread */
373 KiUnwaitThread(WaitThread
, CurrentWaitBlock
->WaitKey
, Increment
);
378 /* Unwait the thread with STATUS_KERNEL_APC */
379 KiUnwaitThread(WaitThread
, STATUS_KERNEL_APC
, Increment
);
383 WaitEntry
= WaitList
->Flink
;
384 } while (WaitEntry
!= WaitList
);
389 // Spinlock Acquire at IRQL >= DISPATCH_LEVEL
393 KxAcquireSpinLock(IN PKSPIN_LOCK SpinLock
)
395 /* On UP builds, spinlocks don't exist at IRQL >= DISPATCH */
396 UNREFERENCED_PARAMETER(SpinLock
);
400 // Spinlock Release at IRQL >= DISPATCH_LEVEL
404 KxReleaseSpinLock(IN PKSPIN_LOCK SpinLock
)
406 /* On UP builds, spinlocks don't exist at IRQL >= DISPATCH */
407 UNREFERENCED_PARAMETER(SpinLock
);
411 // This routine protects against multiple CPU acquires, it's meaningless on UP.
415 KiAcquireDispatcherObject(IN DISPATCHER_HEADER
* Object
)
417 UNREFERENCED_PARAMETER(Object
);
421 // This routine protects against multiple CPU acquires, it's meaningless on UP.
425 KiReleaseDispatcherObject(IN DISPATCHER_HEADER
* Object
)
427 UNREFERENCED_PARAMETER(Object
);
432 KiAcquireDispatcherLock(VOID
)
434 /* Raise to DPC level */
435 return KeRaiseIrqlToDpcLevel();
440 KiReleaseDispatcherLock(IN KIRQL OldIrql
)
442 /* Just exit the dispatcher */
443 KiExitDispatcher(OldIrql
);
448 KiAcquireDispatcherLockAtDpcLevel(VOID
)
450 /* This is a no-op at DPC Level for UP systems */
456 KiReleaseDispatcherLockFromDpcLevel(VOID
)
458 /* This is a no-op at DPC Level for UP systems */
463 // This routine makes the thread deferred ready on the boot CPU.
467 KiInsertDeferredReadyList(IN PKTHREAD Thread
)
469 /* Set the thread to deferred state and boot CPU */
470 Thread
->State
= DeferredReady
;
471 Thread
->DeferredProcessor
= 0;
473 /* Make the thread ready immediately */
474 KiDeferredReadyThread(Thread
);
479 KiRescheduleThread(IN BOOLEAN NewThread
,
482 /* This is meaningless on UP systems */
483 UNREFERENCED_PARAMETER(NewThread
);
484 UNREFERENCED_PARAMETER(Cpu
);
488 // This routine protects against multiple CPU acquires, it's meaningless on UP.
492 KiSetThreadSwapBusy(IN PKTHREAD Thread
)
494 UNREFERENCED_PARAMETER(Thread
);
498 // This routine protects against multiple CPU acquires, it's meaningless on UP.
502 KiAcquirePrcbLock(IN PKPRCB Prcb
)
504 UNREFERENCED_PARAMETER(Prcb
);
508 // This routine protects against multiple CPU acquires, it's meaningless on UP.
512 KiReleasePrcbLock(IN PKPRCB Prcb
)
514 UNREFERENCED_PARAMETER(Prcb
);
518 // This routine protects against multiple CPU acquires, it's meaningless on UP.
522 KiAcquireThreadLock(IN PKTHREAD Thread
)
524 UNREFERENCED_PARAMETER(Thread
);
528 // This routine protects against multiple CPU acquires, it's meaningless on UP.
532 KiReleaseThreadLock(IN PKTHREAD Thread
)
534 UNREFERENCED_PARAMETER(Thread
);
538 // This routine protects against multiple CPU acquires, it's meaningless on UP.
542 KiTryThreadLock(IN PKTHREAD Thread
)
544 UNREFERENCED_PARAMETER(Thread
);
550 KiCheckDeferredReadyList(IN PKPRCB Prcb
)
552 /* There are no deferred ready lists on UP systems */
553 UNREFERENCED_PARAMETER(Prcb
);
558 KiRundownThread(IN PKTHREAD Thread
)
560 /* Check if this is the NPX Thread */
561 if (KeGetCurrentPrcb()->NpxThread
== Thread
)
564 KeGetCurrentPrcb()->NpxThread
= NULL
;
566 __asm__("fninit\n\t");
575 KiRequestApcInterrupt(IN BOOLEAN NeedApc
,
578 /* We deliver instantly on UP */
579 UNREFERENCED_PARAMETER(NeedApc
);
580 UNREFERENCED_PARAMETER(Processor
);
586 // Spinlock Acquisition at IRQL >= DISPATCH_LEVEL
590 KxAcquireSpinLock(IN PKSPIN_LOCK SpinLock
)
594 /* Try to acquire it */
595 if (InterlockedBitTestAndSet((PLONG
)SpinLock
, 0))
597 /* Value changed... wait until it's locked */
598 while (*(volatile KSPIN_LOCK
*)SpinLock
== 1)
601 /* On debug builds, we use a much slower but useful routine */
602 Kii386SpinOnSpinLock(SpinLock
, 5);
604 /* Otherwise, just yield and keep looping */
612 /* On debug builds, we OR in the KTHREAD */
613 *SpinLock
= KeGetCurrentThread() | 1;
615 /* All is well, break out */
622 // Spinlock Release at IRQL >= DISPATCH_LEVEL
626 KxReleaseSpinLock(IN PKSPIN_LOCK SpinLock
)
629 /* Make sure that the threads match */
630 if ((KeGetCurrentThread() | 1) != *SpinLock
)
632 /* They don't, bugcheck */
633 KeBugCheckEx(SPIN_LOCK_NOT_OWNED
, SpinLock
, 0, 0, 0);
637 InterlockedAnd(SpinLock
, 0);
642 KiAcquireDispatcherObject(IN DISPATCHER_HEADER
* Object
)
644 LONG OldValue
, NewValue
;
646 /* Make sure we're at a safe level to touch the lock */
647 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL
);
649 /* Start acquire loop */
652 /* Loop until the other CPU releases it */
653 while ((UCHAR
)Object
->Lock
& KOBJECT_LOCK_BIT
)
655 /* Let the CPU know that this is a loop */
659 /* Try acquiring the lock now */
660 NewValue
= InterlockedCompareExchange(&Object
->Lock
,
661 OldValue
| KOBJECT_LOCK_BIT
,
663 } while (NewValue
!= OldValue
);
668 KiReleaseDispatcherObject(IN DISPATCHER_HEADER
* Object
)
670 /* Make sure we're at a safe level to touch the lock */
671 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL
);
674 InterlockedAnd(&Object
->Lock
, ~KOBJECT_LOCK_BIT
);
679 KiAcquireDispatcherLock(VOID
)
681 /* Raise to synchronization level and acquire the dispatcher lock */
682 return KeAcquireQueuedSpinLockRaiseToSynch(LockQueueDispatcherLock
);
687 KiReleaseDispatcherLock(IN KIRQL OldIrql
)
689 /* First release the lock */
690 KeReleaseQueuedSpinLockFromDpcLevel(&KeGetCurrentPrcb()->
691 LockQueue
[LockQueueDispatcherLock
]);
693 /* Then exit the dispatcher */
694 KiExitDispatcher(OldIrql
);
698 // This routine inserts a thread into the deferred ready list of the given CPU
702 KiInsertDeferredReadyList(IN PKTHREAD Thread
)
704 PKPRCB Prcb
= KeGetCurrentPrcb();
706 /* Set the thread to deferred state and CPU */
707 Thread
->State
= DeferredReady
;
708 Thread
->DeferredProcessor
= Prcb
->Number
;
710 /* Add it on the list */
711 PushEntryList(&Prcb
->DeferredReadyListHead
, &Thread
->SwapListEntry
);
716 KiRescheduleThread(IN BOOLEAN NewThread
,
719 /* Check if a new thread needs to be scheduled on a different CPU */
720 if ((NewThread
) && !(KeGetPcr()->Number
== Cpu
))
722 /* Send an IPI to request delivery */
723 KiIpiSendRequest(AFFINITY_MASK(Cpu
), IPI_DPC
);
728 // This routine sets the current thread in a swap busy state, which ensure that
729 // nobody else tries to swap it concurrently.
733 KiSetThreadSwapBusy(IN PKTHREAD Thread
)
735 /* Make sure nobody already set it */
736 ASSERT(Thread
->SwapBusy
== FALSE
);
738 /* Set it ourselves */
739 Thread
->SwapBusy
= TRUE
;
743 // This routine acquires the PRCB lock so that only one caller can touch
744 // volatile PRCB data.
746 // Since this is a simple optimized spin-lock, it must be be only acquired
747 // at dispatcher level or higher!
751 KiAcquirePrcbLock(IN PKPRCB Prcb
)
753 /* Make sure we're at a safe level to touch the PRCB lock */
754 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL
);
756 /* Start acquire loop */
759 /* Acquire the lock and break out if we acquired it first */
760 if (!InterlockedExchange(&Prcb
->PrcbLock
, 1)) break;
762 /* Loop until the other CPU releases it */
765 /* Let the CPU know that this is a loop */
767 } while (Prcb
->PrcbLock
);
772 // This routine releases the PRCB lock so that other callers can touch
773 // volatile PRCB data.
775 // Since this is a simple optimized spin-lock, it must be be only acquired
776 // at dispatcher level or higher!
780 KiReleasePrcbLock(IN PKPRCB Prcb
)
782 /* Make sure it's acquired! */
783 ASSERT(Prcb
->PrcbLock
!= 0);
786 InterlockedAnd(&Prcb
->PrcbLock
, 0);
790 // This routine acquires the thread lock so that only one caller can touch
791 // volatile thread data.
793 // Since this is a simple optimized spin-lock, it must be be only acquired
794 // at dispatcher level or higher!
798 KiAcquireThreadLock(IN PKTHREAD Thread
)
800 /* Make sure we're at a safe level to touch the thread lock */
801 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL
);
803 /* Start acquire loop */
806 /* Acquire the lock and break out if we acquired it first */
807 if (!InterlockedExchange(&Thread
->ThreadLock
, 1)) break;
809 /* Loop until the other CPU releases it */
812 /* Let the CPU know that this is a loop */
814 } while (Thread
->ThreadLock
);
819 // This routine releases the thread lock so that other callers can touch
820 // volatile thread data.
822 // Since this is a simple optimized spin-lock, it must be be only acquired
823 // at dispatcher level or higher!
827 KiReleaseThreadLock(IN PKTHREAD Thread
)
830 InterlockedAnd(&Thread
->ThreadLock
, 0);
835 KiTryThreadLock(IN PKTHREAD Thread
)
839 /* If the lock isn't acquired, return false */
840 if (!Thread
->ThreadLock
) return FALSE
;
842 /* Otherwise, try to acquire it and check the result */
844 Value
= InterlockedExchange(&Thread
->ThreadLock
, &Value
);
846 /* Return the lock state */
847 return (Value
== TRUE
);
852 KiCheckDeferredReadyList(IN PKPRCB Prcb
)
854 /* Scan the deferred ready lists if required */
855 if (Prcb
->DeferredReadyListHead
.Next
) KiProcessDeferredReadyList(Prcb
);
860 KiRequestApcInterrupt(IN BOOLEAN NeedApc
,
863 /* Check if we need to request APC delivery */
866 /* Check if it's on another CPU */
867 if (KeGetPcr()->Number
!= Cpu
)
869 /* Send an IPI to request delivery */
870 KiIpiSendRequest(AFFINITY_MASK(Cpu
), IPI_DPC
);
874 /* Request a software interrupt */
875 HalRequestSoftwareInterrupt(APC_LEVEL
);
884 KiAcquireApcLock(IN PKTHREAD Thread
,
885 IN PKLOCK_QUEUE_HANDLE Handle
)
887 /* Acquire the lock and raise to synchronization level */
888 KeAcquireInStackQueuedSpinLockRaiseToSynch(&Thread
->ApcQueueLock
, Handle
);
893 KiAcquireApcLockAtDpcLevel(IN PKTHREAD Thread
,
894 IN PKLOCK_QUEUE_HANDLE Handle
)
896 /* Acquire the lock */
897 KeAcquireInStackQueuedSpinLockAtDpcLevel(&Thread
->ApcQueueLock
, Handle
);
902 KiAcquireApcLockAtApcLevel(IN PKTHREAD Thread
,
903 IN PKLOCK_QUEUE_HANDLE Handle
)
905 /* Acquire the lock */
906 KeAcquireInStackQueuedSpinLock(&Thread
->ApcQueueLock
, Handle
);
911 KiReleaseApcLock(IN PKLOCK_QUEUE_HANDLE Handle
)
913 /* Release the lock */
914 KeReleaseInStackQueuedSpinLock(Handle
);
919 KiReleaseApcLockFromDpcLevel(IN PKLOCK_QUEUE_HANDLE Handle
)
921 /* Release the lock */
922 KeReleaseInStackQueuedSpinLockFromDpcLevel(Handle
);
927 KiAcquireProcessLock(IN PKPROCESS Process
,
928 IN PKLOCK_QUEUE_HANDLE Handle
)
930 /* Acquire the lock and raise to synchronization level */
931 KeAcquireInStackQueuedSpinLockRaiseToSynch(&Process
->ProcessLock
, Handle
);
936 KiReleaseProcessLock(IN PKLOCK_QUEUE_HANDLE Handle
)
938 /* Release the lock */
939 KeReleaseInStackQueuedSpinLock(Handle
);
944 KiReleaseProcessLockFromDpcLevel(IN PKLOCK_QUEUE_HANDLE Handle
)
946 /* Release the lock */
947 KeReleaseInStackQueuedSpinLockFromDpcLevel(Handle
);
952 KiAcquireDeviceQueueLock(IN PKDEVICE_QUEUE DeviceQueue
,
953 IN PKLOCK_QUEUE_HANDLE DeviceLock
)
955 /* Check if we were called from a threaded DPC */
956 if (KeGetCurrentPrcb()->DpcThreadActive
)
958 /* Lock the Queue, we're not at DPC level */
959 KeAcquireInStackQueuedSpinLock(&DeviceQueue
->Lock
, DeviceLock
);
963 /* We must be at DPC level, acquire the lock safely */
964 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
965 KeAcquireInStackQueuedSpinLockAtDpcLevel(&DeviceQueue
->Lock
,
972 KiReleaseDeviceQueueLock(IN PKLOCK_QUEUE_HANDLE DeviceLock
)
974 /* Check if we were called from a threaded DPC */
975 if (KeGetCurrentPrcb()->DpcThreadActive
)
977 /* Unlock the Queue, we're not at DPC level */
978 KeReleaseInStackQueuedSpinLock(DeviceLock
);
982 /* We must be at DPC level, release the lock safely */
983 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
984 KeReleaseInStackQueuedSpinLockFromDpcLevel(DeviceLock
);
989 // This routine queues a thread that is ready on the PRCB's ready lists.
990 // If this thread cannot currently run on this CPU, then the thread is
991 // added to the deferred ready list instead.
993 // This routine must be entered with the PRCB lock held and it will exit
994 // with the PRCB lock released!
998 KxQueueReadyThread(IN PKTHREAD Thread
,
1005 ASSERT(Prcb
== KeGetCurrentPrcb());
1006 ASSERT(Thread
->State
== Running
);
1007 ASSERT(Thread
->NextProcessor
== Prcb
->Number
);
1009 /* Check if this thread is allowed to run in this CPU */
1011 if ((Thread
->Affinity
) & (Prcb
->SetMember
))
1016 /* Set thread ready for execution */
1017 Thread
->State
= Ready
;
1019 /* Save current priority and if someone had pre-empted it */
1020 Priority
= Thread
->Priority
;
1021 Preempted
= Thread
->Preempted
;
1023 /* We're not pre-empting now, and set the wait time */
1024 Thread
->Preempted
= FALSE
;
1025 Thread
->WaitTime
= KeTickCount
.LowPart
;
1028 ASSERT((Priority
>= 0) && (Priority
<= HIGH_PRIORITY
));
1030 /* Insert this thread in the appropriate order */
1031 Preempted
? InsertHeadList(&Prcb
->DispatcherReadyListHead
[Priority
],
1032 &Thread
->WaitListEntry
) :
1033 InsertTailList(&Prcb
->DispatcherReadyListHead
[Priority
],
1034 &Thread
->WaitListEntry
);
1036 /* Update the ready summary */
1037 Prcb
->ReadySummary
|= PRIORITY_MASK(Priority
);
1040 ASSERT(Priority
== Thread
->Priority
);
1042 /* Release the PRCB lock */
1043 KiReleasePrcbLock(Prcb
);
1047 /* Otherwise, prepare this thread to be deferred */
1048 Thread
->State
= DeferredReady
;
1049 Thread
->DeferredProcessor
= Prcb
->Number
;
1051 /* Release the lock and defer scheduling */
1052 KiReleasePrcbLock(Prcb
);
1053 KiDeferredReadyThread(Thread
);
1058 // This routine scans for an appropriate ready thread to select at the
1059 // given priority and for the given CPU.
1063 KiSelectReadyThread(IN KPRIORITY Priority
,
1066 LONG PriorityMask
, PrioritySet
, HighPriority
;
1067 PLIST_ENTRY ListEntry
;
1070 /* Save the current mask and get the priority set for the CPU */
1071 PriorityMask
= Priority
;
1072 PrioritySet
= Prcb
->ReadySummary
>> (UCHAR
)Priority
;
1073 if (!PrioritySet
) return NULL
;
1075 /* Get the highest priority possible */
1076 BitScanReverse((PULONG
)&HighPriority
, PrioritySet
);
1077 ASSERT((PrioritySet
& PRIORITY_MASK(HighPriority
)) != 0);
1078 HighPriority
+= PriorityMask
;
1080 /* Make sure the list isn't at highest priority */
1081 ASSERT(IsListEmpty(&Prcb
->DispatcherReadyListHead
[HighPriority
]) == FALSE
);
1083 /* Get the first thread on the list */
1084 ListEntry
= &Prcb
->DispatcherReadyListHead
[HighPriority
];
1085 Thread
= CONTAINING_RECORD(ListEntry
, KTHREAD
, WaitListEntry
);
1087 /* Make sure this thread is here for a reason */
1088 ASSERT(HighPriority
== Thread
->Priority
);
1089 ASSERT(Thread
->Affinity
& AFFINITY_MASK(Prcb
->Number
));
1090 ASSERT(Thread
->NextProcessor
== Prcb
->Number
);
1092 /* Remove it from the list */
1093 RemoveEntryList(&Thread
->WaitListEntry
);
1094 if (IsListEmpty(&Thread
->WaitListEntry
))
1096 /* The list is empty now, reset the ready summary */
1097 Prcb
->ReadySummary
^= PRIORITY_MASK(HighPriority
);
1100 /* Sanity check and return the thread */
1101 ASSERT((Thread
== NULL
) ||
1102 (Thread
->BasePriority
== 0) ||
1103 (Thread
->Priority
!= 0));
1108 // This routine computes the new priority for a thread. It is only valid for
1109 // threads with priorities in the dynamic priority range.
1113 KiComputeNewPriority(IN PKTHREAD Thread
)
1117 /* Priority sanity checks */
1118 ASSERT((Thread
->PriorityDecrement
>= 0) &&
1119 (Thread
->PriorityDecrement
<= Thread
->Priority
));
1120 ASSERT((Thread
->Priority
< LOW_REALTIME_PRIORITY
) ?
1121 TRUE
: (Thread
->PriorityDecrement
== 0));
1123 /* Get the current priority */
1124 Priority
= Thread
->Priority
;
1125 if (Priority
< LOW_REALTIME_PRIORITY
)
1127 /* Decrease priority by the priority decrement */
1128 Priority
-= (Thread
->PriorityDecrement
+ 1);
1130 /* Don't go out of bounds */
1131 if (Priority
< Thread
->BasePriority
) Priority
= Thread
->BasePriority
;
1133 /* Reset the priority decrement */
1134 Thread
->PriorityDecrement
= 0;
1138 ASSERT((Thread
->BasePriority
== 0) || (Priority
!= 0));
1140 /* Return the new priority */