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)
12 KeGetPreviousMode(VOID
)
14 /* Return the current mode */
15 return KeGetCurrentThread()->PreviousMode
;
20 // Enters a Guarded Region
22 #define KeEnterGuardedRegion() \
24 PKTHREAD _Thread = KeGetCurrentThread(); \
27 ASSERT(KeGetCurrentIrql() <= APC_LEVEL); \
28 ASSERT(_Thread == KeGetCurrentThread()); \
29 ASSERT((_Thread->SpecialApcDisable <= 0) && \
30 (_Thread->SpecialApcDisable != -32768)); \
32 /* Disable Special APCs */ \
33 _Thread->SpecialApcDisable--; \
37 // Leaves a Guarded Region
39 #define KeLeaveGuardedRegion() \
41 PKTHREAD _Thread = KeGetCurrentThread(); \
44 ASSERT(KeGetCurrentIrql() <= APC_LEVEL); \
45 ASSERT(_Thread == KeGetCurrentThread()); \
46 ASSERT(_Thread->SpecialApcDisable < 0); \
48 /* Leave region and check if APCs are OK now */ \
49 if (!(++_Thread->SpecialApcDisable)) \
51 /* Check for Kernel APCs on the list */ \
52 if (!IsListEmpty(&_Thread->ApcState. \
53 ApcListHead[KernelMode])) \
55 /* Check for APC Delivery */ \
56 KiCheckForKernelApcDelivery(); \
62 // Enters a Critical Region
64 #define KeEnterCriticalRegion() \
66 PKTHREAD _Thread = KeGetCurrentThread(); \
69 ASSERT(_Thread == KeGetCurrentThread()); \
70 ASSERT((_Thread->KernelApcDisable <= 0) && \
71 (_Thread->KernelApcDisable != -32768)); \
73 /* Disable Kernel APCs */ \
74 _Thread->KernelApcDisable--; \
78 // Leaves a Critical Region
80 #define KeLeaveCriticalRegion() \
82 PKTHREAD _Thread = KeGetCurrentThread(); \
85 ASSERT(_Thread == KeGetCurrentThread()); \
86 ASSERT(_Thread->KernelApcDisable < 0); \
88 /* Enable Kernel APCs */ \
89 _Thread->KernelApcDisable++; \
91 /* Check if Kernel APCs are now enabled */ \
92 if (!(_Thread->KernelApcDisable)) \
94 /* Check if we need to request an APC Delivery */ \
95 if (!(IsListEmpty(&_Thread->ApcState.ApcListHead[KernelMode])) && \
96 !(_Thread->SpecialApcDisable)) \
98 /* Check for the right environment */ \
99 KiCheckForKernelApcDelivery(); \
107 // This routine protects against multiple CPU acquires, it's meaningless on UP.
111 KiAcquireDispatcherObject(IN DISPATCHER_HEADER
* Object
)
113 UNREFERENCED_PARAMETER(Object
);
117 // This routine protects against multiple CPU acquires, it's meaningless on UP.
121 KiReleaseDispatcherObject(IN DISPATCHER_HEADER
* Object
)
123 UNREFERENCED_PARAMETER(Object
);
128 KiAcquireDispatcherLock(VOID
)
130 /* Raise to DPC level */
131 return KeRaiseIrqlToDpcLevel();
136 KiReleaseDispatcherLock(IN KIRQL OldIrql
)
138 /* Just exit the dispatcher */
139 KiExitDispatcher(OldIrql
);
144 KiAcquireDispatcherLockAtDpcLevel(VOID
)
146 /* This is a no-op at DPC Level for UP systems */
152 KiReleaseDispatcherLockFromDpcLevel(VOID
)
154 /* This is a no-op at DPC Level for UP systems */
159 // This routine makes the thread deferred ready on the boot CPU.
163 KiInsertDeferredReadyList(IN PKTHREAD Thread
)
165 /* Set the thread to deferred state and boot CPU */
166 Thread
->State
= DeferredReady
;
167 Thread
->DeferredProcessor
= 0;
169 /* Make the thread ready immediately */
170 KiDeferredReadyThread(Thread
);
175 KiRescheduleThread(IN BOOLEAN NewThread
,
178 /* This is meaningless on UP systems */
179 UNREFERENCED_PARAMETER(NewThread
);
180 UNREFERENCED_PARAMETER(Cpu
);
184 // This routine protects against multiple CPU acquires, it's meaningless on UP.
188 KiSetThreadSwapBusy(IN PKTHREAD Thread
)
190 UNREFERENCED_PARAMETER(Thread
);
194 // This routine protects against multiple CPU acquires, it's meaningless on UP.
198 KiAcquirePrcbLock(IN PKPRCB Prcb
)
200 UNREFERENCED_PARAMETER(Prcb
);
204 // This routine protects against multiple CPU acquires, it's meaningless on UP.
208 KiReleasePrcbLock(IN PKPRCB Prcb
)
210 UNREFERENCED_PARAMETER(Prcb
);
214 // This routine protects against multiple CPU acquires, it's meaningless on UP.
218 KiAcquireThreadLock(IN PKTHREAD Thread
)
220 UNREFERENCED_PARAMETER(Thread
);
224 // This routine protects against multiple CPU acquires, it's meaningless on UP.
228 KiReleaseThreadLock(IN PKTHREAD Thread
)
230 UNREFERENCED_PARAMETER(Thread
);
234 // This routine protects against multiple CPU acquires, it's meaningless on UP.
238 KiTryThreadLock(IN PKTHREAD Thread
)
240 UNREFERENCED_PARAMETER(Thread
);
246 KiCheckDeferredReadyList(IN PKPRCB Prcb
)
248 /* There are no deferred ready lists on UP systems */
249 UNREFERENCED_PARAMETER(Prcb
);
254 KiRequestApcInterrupt(IN BOOLEAN NeedApc
,
257 /* We deliver instantly on UP */
258 UNREFERENCED_PARAMETER(NeedApc
);
259 UNREFERENCED_PARAMETER(Processor
);
264 KiAcquireTimerLock(IN ULONG Hand
)
266 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL
);
268 /* Nothing to do on UP */
269 UNREFERENCED_PARAMETER(Hand
);
275 KiReleaseTimerLock(IN PKSPIN_LOCK_QUEUE LockQueue
)
277 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL
);
279 /* Nothing to do on UP */
280 UNREFERENCED_PARAMETER(LockQueue
);
287 KiAcquireDispatcherObject(IN DISPATCHER_HEADER
* Object
)
291 /* Make sure we're at a safe level to touch the lock */
292 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL
);
294 /* Start acquire loop */
297 /* Loop until the other CPU releases it */
300 /* Check if it got released */
301 OldValue
= Object
->Lock
;
302 if ((OldValue
& KOBJECT_LOCK_BIT
) == 0) break;
304 /* Let the CPU know that this is a loop */
308 /* Try acquiring the lock now */
309 } while (InterlockedCompareExchange(&Object
->Lock
,
310 OldValue
| KOBJECT_LOCK_BIT
,
311 OldValue
) != OldValue
);
316 KiReleaseDispatcherObject(IN DISPATCHER_HEADER
* Object
)
318 /* Make sure we're at a safe level to touch the lock */
319 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL
);
322 InterlockedAnd(&Object
->Lock
, ~KOBJECT_LOCK_BIT
);
327 KiAcquireDispatcherLock(VOID
)
329 /* Raise to synchronization level and acquire the dispatcher lock */
330 return KeAcquireQueuedSpinLockRaiseToSynch(LockQueueDispatcherLock
);
335 KiReleaseDispatcherLock(IN KIRQL OldIrql
)
337 /* First release the lock */
338 KeReleaseQueuedSpinLockFromDpcLevel(&KeGetCurrentPrcb()->
339 LockQueue
[LockQueueDispatcherLock
]);
341 /* Then exit the dispatcher */
342 KiExitDispatcher(OldIrql
);
347 KiAcquireDispatcherLockAtDpcLevel(VOID
)
349 /* Acquire the dispatcher lock */
350 KeAcquireQueuedSpinLockAtDpcLevel(&KeGetCurrentPrcb()->
351 LockQueue
[LockQueueDispatcherLock
]);
356 KiReleaseDispatcherLockFromDpcLevel(VOID
)
358 /* Release the dispatcher lock */
359 KeReleaseQueuedSpinLockFromDpcLevel(&KeGetCurrentPrcb()->
360 LockQueue
[LockQueueDispatcherLock
]);
364 // This routine inserts a thread into the deferred ready list of the current CPU
368 KiInsertDeferredReadyList(IN PKTHREAD Thread
)
370 PKPRCB Prcb
= KeGetCurrentPrcb();
372 /* Set the thread to deferred state and CPU */
373 Thread
->State
= DeferredReady
;
374 Thread
->DeferredProcessor
= Prcb
->Number
;
376 /* Add it on the list */
377 PushEntryList(&Prcb
->DeferredReadyListHead
, &Thread
->SwapListEntry
);
382 KiRescheduleThread(IN BOOLEAN NewThread
,
385 /* Check if a new thread needs to be scheduled on a different CPU */
386 if ((NewThread
) && !(KeGetPcr()->Number
== Cpu
))
388 /* Send an IPI to request delivery */
389 KiIpiSend(AFFINITY_MASK(Cpu
), IPI_DPC
);
394 // This routine sets the current thread in a swap busy state, which ensure that
395 // nobody else tries to swap it concurrently.
399 KiSetThreadSwapBusy(IN PKTHREAD Thread
)
401 /* Make sure nobody already set it */
402 ASSERT(Thread
->SwapBusy
== FALSE
);
404 /* Set it ourselves */
405 Thread
->SwapBusy
= TRUE
;
409 // This routine acquires the PRCB lock so that only one caller can touch
410 // volatile PRCB data.
412 // Since this is a simple optimized spin-lock, it must only be acquired
413 // at dispatcher level or higher!
417 KiAcquirePrcbLock(IN PKPRCB Prcb
)
419 /* Make sure we're at a safe level to touch the PRCB lock */
420 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL
);
422 /* Start acquire loop */
425 /* Acquire the lock and break out if we acquired it first */
426 if (!InterlockedExchange((PLONG
)&Prcb
->PrcbLock
, 1)) break;
428 /* Loop until the other CPU releases it */
431 /* Let the CPU know that this is a loop */
433 } while (Prcb
->PrcbLock
);
438 // This routine releases the PRCB lock so that other callers can touch
439 // volatile PRCB data.
441 // Since this is a simple optimized spin-lock, it must be be only acquired
442 // at dispatcher level or higher!
446 KiReleasePrcbLock(IN PKPRCB Prcb
)
448 /* Make sure we are above dispatch and the lock is acquired! */
449 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL
);
450 ASSERT(Prcb
->PrcbLock
!= 0);
453 InterlockedAnd((PLONG
)&Prcb
->PrcbLock
, 0);
457 // This routine acquires the thread lock so that only one caller can touch
458 // volatile thread data.
460 // Since this is a simple optimized spin-lock, it must be be only acquired
461 // at dispatcher level or higher!
465 KiAcquireThreadLock(IN PKTHREAD Thread
)
467 /* Make sure we're at a safe level to touch the thread lock */
468 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL
);
470 /* Start acquire loop */
473 /* Acquire the lock and break out if we acquired it first */
474 if (!InterlockedExchange((PLONG
)&Thread
->ThreadLock
, 1)) break;
476 /* Loop until the other CPU releases it */
479 /* Let the CPU know that this is a loop */
481 } while (Thread
->ThreadLock
);
486 // This routine releases the thread lock so that other callers can touch
487 // volatile thread data.
489 // Since this is a simple optimized spin-lock, it must be be only acquired
490 // at dispatcher level or higher!
494 KiReleaseThreadLock(IN PKTHREAD Thread
)
496 /* Make sure we are still above dispatch */
497 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL
);
500 InterlockedAnd((PLONG
)&Thread
->ThreadLock
, 0);
505 KiTryThreadLock(IN PKTHREAD Thread
)
509 /* If the lock isn't acquired, return false */
510 if (!Thread
->ThreadLock
) return FALSE
;
512 /* Otherwise, try to acquire it and check the result */
514 Value
= InterlockedExchange((PLONG
)&Thread
->ThreadLock
, Value
);
516 /* Return the lock state */
517 return (Value
== TRUE
);
522 KiCheckDeferredReadyList(IN PKPRCB Prcb
)
524 /* Scan the deferred ready lists if required */
525 if (Prcb
->DeferredReadyListHead
.Next
) KiProcessDeferredReadyList(Prcb
);
530 KiRequestApcInterrupt(IN BOOLEAN NeedApc
,
533 /* Check if we need to request APC delivery */
536 /* Check if it's on another CPU */
537 if (KeGetPcr()->Number
!= Processor
)
539 /* Send an IPI to request delivery */
540 KiIpiSend(AFFINITY_MASK(Processor
), IPI_APC
);
544 /* Request a software interrupt */
545 HalRequestSoftwareInterrupt(APC_LEVEL
);
552 KiAcquireTimerLock(IN ULONG Hand
)
554 PKSPIN_LOCK_QUEUE LockQueue
;
556 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL
);
558 /* Get the lock index */
559 LockIndex
= Hand
>> LOCK_QUEUE_TIMER_LOCK_SHIFT
;
560 LockIndex
&= (LOCK_QUEUE_TIMER_TABLE_LOCKS
- 1);
562 /* Now get the lock */
563 LockQueue
= &KeGetCurrentPrcb()->LockQueue
[LockQueueTimerTableLock
+ LockIndex
];
565 /* Acquire it and return */
566 KeAcquireQueuedSpinLockAtDpcLevel(LockQueue
);
572 KiReleaseTimerLock(IN PKSPIN_LOCK_QUEUE LockQueue
)
574 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL
);
576 /* Release the lock */
577 KeReleaseQueuedSpinLockFromDpcLevel(LockQueue
);
584 KiAcquireApcLock(IN PKTHREAD Thread
,
585 IN PKLOCK_QUEUE_HANDLE Handle
)
587 /* Acquire the lock and raise to synchronization level */
588 KeAcquireInStackQueuedSpinLockRaiseToSynch(&Thread
->ApcQueueLock
, Handle
);
593 KiAcquireApcLockAtDpcLevel(IN PKTHREAD Thread
,
594 IN PKLOCK_QUEUE_HANDLE Handle
)
596 /* Acquire the lock */
597 KeAcquireInStackQueuedSpinLockAtDpcLevel(&Thread
->ApcQueueLock
, Handle
);
602 KiAcquireApcLockAtApcLevel(IN PKTHREAD Thread
,
603 IN PKLOCK_QUEUE_HANDLE Handle
)
605 /* Acquire the lock */
606 KeAcquireInStackQueuedSpinLock(&Thread
->ApcQueueLock
, Handle
);
611 KiReleaseApcLock(IN PKLOCK_QUEUE_HANDLE Handle
)
613 /* Release the lock */
614 KeReleaseInStackQueuedSpinLock(Handle
);
619 KiReleaseApcLockFromDpcLevel(IN PKLOCK_QUEUE_HANDLE Handle
)
621 /* Release the lock */
622 KeReleaseInStackQueuedSpinLockFromDpcLevel(Handle
);
627 KiAcquireProcessLock(IN PKPROCESS Process
,
628 IN PKLOCK_QUEUE_HANDLE Handle
)
630 /* Acquire the lock and raise to synchronization level */
631 KeAcquireInStackQueuedSpinLockRaiseToSynch(&Process
->ProcessLock
, Handle
);
636 KiReleaseProcessLock(IN PKLOCK_QUEUE_HANDLE Handle
)
638 /* Release the lock */
639 KeReleaseInStackQueuedSpinLock(Handle
);
644 KiReleaseProcessLockFromDpcLevel(IN PKLOCK_QUEUE_HANDLE Handle
)
646 /* Release the lock */
647 KeReleaseInStackQueuedSpinLockFromDpcLevel(Handle
);
652 KiAcquireDeviceQueueLock(IN PKDEVICE_QUEUE DeviceQueue
,
653 IN PKLOCK_QUEUE_HANDLE DeviceLock
)
655 /* Check if we were called from a threaded DPC */
656 if (KeGetCurrentPrcb()->DpcThreadActive
)
658 /* Lock the Queue, we're not at DPC level */
659 KeAcquireInStackQueuedSpinLock(&DeviceQueue
->Lock
, DeviceLock
);
663 /* We must be at DPC level, acquire the lock safely */
664 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
665 KeAcquireInStackQueuedSpinLockAtDpcLevel(&DeviceQueue
->Lock
,
672 KiReleaseDeviceQueueLock(IN PKLOCK_QUEUE_HANDLE DeviceLock
)
674 /* Check if we were called from a threaded DPC */
675 if (KeGetCurrentPrcb()->DpcThreadActive
)
677 /* Unlock the Queue, we're not at DPC level */
678 KeReleaseInStackQueuedSpinLock(DeviceLock
);
682 /* We must be at DPC level, release the lock safely */
683 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
684 KeReleaseInStackQueuedSpinLockFromDpcLevel(DeviceLock
);
689 // Satisfies the wait of any dispatcher object
691 #define KiSatisfyObjectWait(Object, Thread) \
693 /* Special case for Mutants */ \
694 if ((Object)->Header.Type == MutantObject) \
696 /* Decrease the Signal State */ \
697 (Object)->Header.SignalState--; \
699 /* Check if it's now non-signaled */ \
700 if (!(Object)->Header.SignalState) \
702 /* Set the Owner Thread */ \
703 (Object)->OwnerThread = Thread; \
705 /* Disable APCs if needed */ \
706 Thread->KernelApcDisable = Thread->KernelApcDisable - \
707 (Object)->ApcDisable; \
709 /* Check if it's abandoned */ \
710 if ((Object)->Abandoned) \
713 (Object)->Abandoned = FALSE; \
715 /* Return Status */ \
716 Thread->WaitStatus = STATUS_ABANDONED; \
719 /* Insert it into the Mutant List */ \
720 InsertHeadList(Thread->MutantListHead.Blink, \
721 &(Object)->MutantListEntry); \
724 else if (((Object)->Header.Type & TIMER_OR_EVENT_TYPE) == \
725 EventSynchronizationObject) \
727 /* Synchronization Timers and Events just get un-signaled */ \
728 (Object)->Header.SignalState = 0; \
730 else if ((Object)->Header.Type == SemaphoreObject) \
732 /* These ones can have multiple states, so we only decrease it */ \
733 (Object)->Header.SignalState--; \
738 // Satisfies the wait of a mutant dispatcher object
740 #define KiSatisfyMutantWait(Object, Thread) \
742 /* Decrease the Signal State */ \
743 (Object)->Header.SignalState--; \
745 /* Check if it's now non-signaled */ \
746 if (!(Object)->Header.SignalState) \
748 /* Set the Owner Thread */ \
749 (Object)->OwnerThread = Thread; \
751 /* Disable APCs if needed */ \
752 Thread->KernelApcDisable = Thread->KernelApcDisable - \
753 (Object)->ApcDisable; \
755 /* Check if it's abandoned */ \
756 if ((Object)->Abandoned) \
759 (Object)->Abandoned = FALSE; \
761 /* Return Status */ \
762 Thread->WaitStatus = STATUS_ABANDONED; \
765 /* Insert it into the Mutant List */ \
766 InsertHeadList(Thread->MutantListHead.Blink, \
767 &(Object)->MutantListEntry); \
772 // Satisfies the wait of any nonmutant dispatcher object
774 #define KiSatisfyNonMutantWait(Object) \
776 if (((Object)->Header.Type & TIMER_OR_EVENT_TYPE) == \
777 EventSynchronizationObject) \
779 /* Synchronization Timers and Events just get un-signaled */ \
780 (Object)->Header.SignalState = 0; \
782 else if ((Object)->Header.Type == SemaphoreObject) \
784 /* These ones can have multiple states, so we only decrease it */ \
785 (Object)->Header.SignalState--; \
790 // Recalculates the due time
794 KiRecalculateDueTime(IN PLARGE_INTEGER OriginalDueTime
,
795 IN PLARGE_INTEGER DueTime
,
796 IN OUT PLARGE_INTEGER NewDueTime
)
798 /* Don't do anything for absolute waits */
799 if (OriginalDueTime
->QuadPart
>= 0) return OriginalDueTime
;
801 /* Otherwise, query the interrupt time and recalculate */
802 NewDueTime
->QuadPart
= KeQueryInterruptTime();
803 NewDueTime
->QuadPart
-= DueTime
->QuadPart
;
808 // Determines whether a thread should be added to the wait list
812 KiCheckThreadStackSwap(IN PKTHREAD Thread
,
813 IN KPROCESSOR_MODE WaitMode
)
815 /* Check the required conditions */
816 if ((WaitMode
!= KernelMode
) &&
817 (Thread
->EnableStackSwap
) &&
818 (Thread
->Priority
>= (LOW_REALTIME_PRIORITY
+ 9)))
820 /* We are go for swap */
825 /* Don't swap the thread */
831 // Adds a thread to the wait list
833 #define KiAddThreadToWaitList(Thread, Swappable) \
835 /* Make sure it's swappable */ \
838 /* Insert it into the PRCB's List */ \
839 InsertTailList(&KeGetCurrentPrcb()->WaitListHead, \
840 &Thread->WaitListEntry); \
845 // Checks if a wait in progress should be interrupted by APCs or an alertable
850 KiCheckAlertability(IN PKTHREAD Thread
,
851 IN BOOLEAN Alertable
,
852 IN KPROCESSOR_MODE WaitMode
)
854 /* Check if the wait is alertable */
857 /* It is, first check if the thread is alerted in this mode */
858 if (Thread
->Alerted
[WaitMode
])
860 /* It is, so bail out of the wait */
861 Thread
->Alerted
[WaitMode
] = FALSE
;
862 return STATUS_ALERTED
;
864 else if ((WaitMode
!= KernelMode
) &&
865 (!IsListEmpty(&Thread
->ApcState
.ApcListHead
[UserMode
])))
867 /* It's isn't, but this is a user wait with queued user APCs */
868 Thread
->ApcState
.UserApcPending
= TRUE
;
869 return STATUS_USER_APC
;
871 else if (Thread
->Alerted
[KernelMode
])
873 /* It isn't that either, but we're alered in kernel mode */
874 Thread
->Alerted
[KernelMode
] = FALSE
;
875 return STATUS_ALERTED
;
878 else if ((WaitMode
!= KernelMode
) && (Thread
->ApcState
.UserApcPending
))
880 /* Not alertable, but this is a user wait with pending user APCs */
881 return STATUS_USER_APC
;
884 /* Otherwise, we're fine */
885 return STATUS_WAIT_0
;
890 KiComputeTimerTableIndex(IN ULONGLONG DueTime
)
892 return (DueTime
/ KeMaximumIncrement
) & (TIMER_TABLE_SIZE
- 1);
896 // Called from KiCompleteTimer, KiInsertTreeTimer, KeSetSystemTime
897 // to remove timer entries
898 // See Windows HPI blog for more information.
901 KiRemoveEntryTimer(IN PKTIMER Timer
)
904 PKTIMER_TABLE_ENTRY TableEntry
;
906 /* Remove the timer from the timer list and check if it's empty */
907 Hand
= Timer
->Header
.Hand
;
908 if (RemoveEntryList(&Timer
->TimerListEntry
))
910 /* Get the respective timer table entry */
911 TableEntry
= &KiTimerTableListHead
[Hand
];
912 if (&TableEntry
->Entry
== TableEntry
->Entry
.Flink
)
914 /* Set the entry to an infinite absolute time */
915 TableEntry
->Time
.HighPart
= 0xFFFFFFFF;
919 /* Clear the list entries on dbg builds so we can tell the timer is gone */
921 Timer
->TimerListEntry
.Flink
= NULL
;
922 Timer
->TimerListEntry
.Blink
= NULL
;
927 // Called by Wait and Queue code to insert a timer for dispatching.
928 // Also called by KeSetTimerEx to insert a timer from the caller.
932 KxInsertTimer(IN PKTIMER Timer
,
935 PKSPIN_LOCK_QUEUE LockQueue
;
937 /* Acquire the lock and release the dispatcher lock */
938 LockQueue
= KiAcquireTimerLock(Hand
);
939 KiReleaseDispatcherLockFromDpcLevel();
941 /* Try to insert the timer */
942 if (KiInsertTimerTable(Timer
, Hand
))
945 KiCompleteTimer(Timer
, LockQueue
);
949 /* Do nothing, just release the lock */
950 KiReleaseTimerLock(LockQueue
);
955 // Called by KeSetTimerEx and KiInsertTreeTimer to calculate Due Time
956 // See the Windows HPI Blog for more information
960 KiComputeDueTime(IN PKTIMER Timer
,
961 IN LARGE_INTEGER DueTime
,
964 LARGE_INTEGER InterruptTime
, SystemTime
, DifferenceTime
;
966 /* Convert to relative time if needed */
967 Timer
->Header
.Absolute
= FALSE
;
968 if (DueTime
.HighPart
>= 0)
970 /* Get System Time */
971 KeQuerySystemTime(&SystemTime
);
973 /* Do the conversion */
974 DifferenceTime
.QuadPart
= SystemTime
.QuadPart
- DueTime
.QuadPart
;
976 /* Make sure it hasn't already expired */
977 Timer
->Header
.Absolute
= TRUE
;
978 if (DifferenceTime
.HighPart
>= 0)
980 /* Cancel everything */
981 Timer
->Header
.SignalState
= TRUE
;
982 Timer
->Header
.Hand
= 0;
983 Timer
->DueTime
.QuadPart
= 0;
988 /* Set the time as Absolute */
989 DueTime
= DifferenceTime
;
992 /* Get the Interrupt Time */
993 InterruptTime
.QuadPart
= KeQueryInterruptTime();
995 /* Recalculate due time */
996 Timer
->DueTime
.QuadPart
= InterruptTime
.QuadPart
- DueTime
.QuadPart
;
999 *Hand
= KiComputeTimerTableIndex(Timer
->DueTime
.QuadPart
);
1000 Timer
->Header
.Hand
= (UCHAR
)*Hand
;
1001 Timer
->Header
.Inserted
= TRUE
;
1006 // Called from Unlink and Queue Insert Code.
1007 // Also called by timer code when canceling an inserted timer.
1008 // Removes a timer from it's tree.
1012 KxRemoveTreeTimer(IN PKTIMER Timer
)
1014 ULONG Hand
= Timer
->Header
.Hand
;
1015 PKSPIN_LOCK_QUEUE LockQueue
;
1016 PKTIMER_TABLE_ENTRY TimerEntry
;
1018 /* Acquire timer lock */
1019 LockQueue
= KiAcquireTimerLock(Hand
);
1021 /* Set the timer as non-inserted */
1022 Timer
->Header
.Inserted
= FALSE
;
1024 /* Remove it from the timer list */
1025 if (RemoveEntryList(&Timer
->TimerListEntry
))
1027 /* Get the entry and check if it's empty */
1028 TimerEntry
= &KiTimerTableListHead
[Hand
];
1029 if (IsListEmpty(&TimerEntry
->Entry
))
1031 /* Clear the time then */
1032 TimerEntry
->Time
.HighPart
= 0xFFFFFFFF;
1036 /* Release the timer lock */
1037 KiReleaseTimerLock(LockQueue
);
1042 KxSetTimerForThreadWait(IN PKTIMER Timer
,
1043 IN LARGE_INTEGER Interval
,
1047 LARGE_INTEGER InterruptTime
, SystemTime
, TimeDifference
;
1049 /* Check the timer's interval to see if it's absolute */
1050 Timer
->Header
.Absolute
= FALSE
;
1051 if (Interval
.HighPart
>= 0)
1053 /* Get the system time and calculate the relative time */
1054 KeQuerySystemTime(&SystemTime
);
1055 TimeDifference
.QuadPart
= SystemTime
.QuadPart
- Interval
.QuadPart
;
1056 Timer
->Header
.Absolute
= TRUE
;
1058 /* Check if we've already expired */
1059 if (TimeDifference
.HighPart
>= 0)
1061 /* Reset everything */
1062 Timer
->DueTime
.QuadPart
= 0;
1064 Timer
->Header
.Hand
= 0;
1069 /* Update the interval */
1070 Interval
= TimeDifference
;
1074 /* Calculate the due time */
1075 InterruptTime
.QuadPart
= KeQueryInterruptTime();
1076 DueTime
= InterruptTime
.QuadPart
- Interval
.QuadPart
;
1077 Timer
->DueTime
.QuadPart
= DueTime
;
1079 /* Calculate the timer handle */
1080 *Hand
= KiComputeTimerTableIndex(DueTime
);
1081 Timer
->Header
.Hand
= (UCHAR
)*Hand
;
1084 #define KxDelayThreadWait() \
1086 /* Setup the Wait Block */ \
1087 Thread->WaitBlockList = TimerBlock; \
1089 /* Setup the timer */ \
1090 KxSetTimerForThreadWait(Timer, *Interval, &Hand); \
1092 /* Save the due time for the caller */ \
1093 DueTime.QuadPart = Timer->DueTime.QuadPart; \
1095 /* Link the timer to this Wait Block */ \
1096 TimerBlock->NextWaitBlock = TimerBlock; \
1097 Timer->Header.WaitListHead.Flink = &TimerBlock->WaitListEntry; \
1098 Timer->Header.WaitListHead.Blink = &TimerBlock->WaitListEntry; \
1100 /* Clear wait status */ \
1101 Thread->WaitStatus = STATUS_SUCCESS; \
1103 /* Setup wait fields */ \
1104 Thread->Alertable = Alertable; \
1105 Thread->WaitReason = DelayExecution; \
1106 Thread->WaitMode = WaitMode; \
1108 /* Check if we can swap the thread's stack */ \
1109 Thread->WaitListEntry.Flink = NULL; \
1110 Swappable = KiCheckThreadStackSwap(Thread, WaitMode); \
1112 /* Set the wait time */ \
1113 Thread->WaitTime = KeTickCount.LowPart;
1115 #define KxMultiThreadWait() \
1116 /* Link wait block array to the thread */ \
1117 Thread->WaitBlockList = WaitBlockArray; \
1119 /* Reset the index */ \
1122 /* Loop wait blocks */ \
1125 /* Fill out the wait block */ \
1126 WaitBlock = &WaitBlockArray[Index]; \
1127 WaitBlock->Object = Object[Index]; \
1128 WaitBlock->WaitKey = (USHORT)Index; \
1129 WaitBlock->WaitType = WaitType; \
1130 WaitBlock->Thread = Thread; \
1132 /* Link to next block */ \
1133 WaitBlock->NextWaitBlock = &WaitBlockArray[Index + 1]; \
1135 } while (Index < Count); \
1137 /* Link the last block */ \
1138 WaitBlock->NextWaitBlock = WaitBlockArray; \
1140 /* Set default wait status */ \
1141 Thread->WaitStatus = STATUS_WAIT_0; \
1143 /* Check if we have a timer */ \
1146 /* Link to the block */ \
1147 TimerBlock->NextWaitBlock = WaitBlockArray; \
1149 /* Setup the timer */ \
1150 KxSetTimerForThreadWait(Timer, *Timeout, &Hand); \
1152 /* Save the due time for the caller */ \
1153 DueTime.QuadPart = Timer->DueTime.QuadPart; \
1155 /* Initialize the list */ \
1156 InitializeListHead(&Timer->Header.WaitListHead); \
1159 /* Set wait settings */ \
1160 Thread->Alertable = Alertable; \
1161 Thread->WaitMode = WaitMode; \
1162 Thread->WaitReason = WaitReason; \
1164 /* Check if we can swap the thread's stack */ \
1165 Thread->WaitListEntry.Flink = NULL; \
1166 Swappable = KiCheckThreadStackSwap(Thread, WaitMode); \
1168 /* Set the wait time */ \
1169 Thread->WaitTime = KeTickCount.LowPart;
1171 #define KxSingleThreadWait() \
1172 /* Setup the Wait Block */ \
1173 Thread->WaitBlockList = WaitBlock; \
1174 WaitBlock->WaitKey = STATUS_SUCCESS; \
1175 WaitBlock->Object = Object; \
1176 WaitBlock->WaitType = WaitAny; \
1178 /* Clear wait status */ \
1179 Thread->WaitStatus = STATUS_SUCCESS; \
1181 /* Check if we have a timer */ \
1184 /* Setup the timer */ \
1185 KxSetTimerForThreadWait(Timer, *Timeout, &Hand); \
1187 /* Save the due time for the caller */ \
1188 DueTime.QuadPart = Timer->DueTime.QuadPart; \
1190 /* Pointer to timer block */ \
1191 WaitBlock->NextWaitBlock = TimerBlock; \
1192 TimerBlock->NextWaitBlock = WaitBlock; \
1194 /* Link the timer to this Wait Block */ \
1195 Timer->Header.WaitListHead.Flink = &TimerBlock->WaitListEntry; \
1196 Timer->Header.WaitListHead.Blink = &TimerBlock->WaitListEntry; \
1200 /* No timer block, just ourselves */ \
1201 WaitBlock->NextWaitBlock = WaitBlock; \
1204 /* Set wait settings */ \
1205 Thread->Alertable = Alertable; \
1206 Thread->WaitMode = WaitMode; \
1207 Thread->WaitReason = WaitReason; \
1209 /* Check if we can swap the thread's stack */ \
1210 Thread->WaitListEntry.Flink = NULL; \
1211 Swappable = KiCheckThreadStackSwap(Thread, WaitMode); \
1213 /* Set the wait time */ \
1214 Thread->WaitTime = KeTickCount.LowPart;
1216 #define KxQueueThreadWait() \
1217 /* Setup the Wait Block */ \
1218 Thread->WaitBlockList = WaitBlock; \
1219 WaitBlock->WaitKey = STATUS_SUCCESS; \
1220 WaitBlock->Object = Queue; \
1221 WaitBlock->WaitType = WaitAny; \
1222 WaitBlock->Thread = Thread; \
1224 /* Clear wait status */ \
1225 Thread->WaitStatus = STATUS_SUCCESS; \
1227 /* Check if we have a timer */ \
1230 /* Setup the timer */ \
1231 KxSetTimerForThreadWait(Timer, *Timeout, &Hand); \
1233 /* Save the due time for the caller */ \
1234 DueTime.QuadPart = Timer->DueTime.QuadPart; \
1236 /* Pointer to timer block */ \
1237 WaitBlock->NextWaitBlock = TimerBlock; \
1238 TimerBlock->NextWaitBlock = WaitBlock; \
1240 /* Link the timer to this Wait Block */ \
1241 Timer->Header.WaitListHead.Flink = &TimerBlock->WaitListEntry; \
1242 Timer->Header.WaitListHead.Blink = &TimerBlock->WaitListEntry; \
1246 /* No timer block, just ourselves */ \
1247 WaitBlock->NextWaitBlock = WaitBlock; \
1250 /* Set wait settings */ \
1251 Thread->Alertable = FALSE; \
1252 Thread->WaitMode = WaitMode; \
1253 Thread->WaitReason = WrQueue; \
1255 /* Check if we can swap the thread's stack */ \
1256 Thread->WaitListEntry.Flink = NULL; \
1257 Swappable = KiCheckThreadStackSwap(Thread, WaitMode); \
1259 /* Set the wait time */ \
1260 Thread->WaitTime = KeTickCount.LowPart;
1267 KxUnwaitThread(IN DISPATCHER_HEADER
*Object
,
1268 IN KPRIORITY Increment
)
1270 PLIST_ENTRY WaitEntry
, WaitList
;
1271 PKWAIT_BLOCK WaitBlock
;
1272 PKTHREAD WaitThread
;
1275 /* Loop the Wait Entries */
1276 WaitList
= &Object
->WaitListHead
;
1277 ASSERT(IsListEmpty(&Object
->WaitListHead
) == FALSE
);
1278 WaitEntry
= WaitList
->Flink
;
1281 /* Get the current wait block */
1282 WaitBlock
= CONTAINING_RECORD(WaitEntry
, KWAIT_BLOCK
, WaitListEntry
);
1284 /* Get the waiting thread */
1285 WaitThread
= WaitBlock
->Thread
;
1287 /* Check the current Wait Mode */
1288 if (WaitBlock
->WaitType
== WaitAny
)
1290 /* Use the actual wait key */
1291 WaitKey
= WaitBlock
->WaitKey
;
1295 /* Otherwise, use STATUS_KERNEL_APC */
1296 WaitKey
= STATUS_KERNEL_APC
;
1299 /* Unwait the thread */
1300 KiUnwaitThread(WaitThread
, WaitKey
, Increment
);
1303 WaitEntry
= WaitList
->Flink
;
1304 } while (WaitEntry
!= WaitList
);
1308 // Unwaits a Thread waiting on an event
1312 KxUnwaitThreadForEvent(IN PKEVENT Event
,
1313 IN KPRIORITY Increment
)
1315 PLIST_ENTRY WaitEntry
, WaitList
;
1316 PKWAIT_BLOCK WaitBlock
;
1317 PKTHREAD WaitThread
;
1319 /* Loop the Wait Entries */
1320 WaitList
= &Event
->Header
.WaitListHead
;
1321 ASSERT(IsListEmpty(&Event
->Header
.WaitListHead
) == FALSE
);
1322 WaitEntry
= WaitList
->Flink
;
1325 /* Get the current wait block */
1326 WaitBlock
= CONTAINING_RECORD(WaitEntry
, KWAIT_BLOCK
, WaitListEntry
);
1328 /* Get the waiting thread */
1329 WaitThread
= WaitBlock
->Thread
;
1331 /* Check the current Wait Mode */
1332 if (WaitBlock
->WaitType
== WaitAny
)
1335 Event
->Header
.SignalState
= 0;
1337 /* Un-signal the event and unwait the thread */
1338 KiUnwaitThread(WaitThread
, WaitBlock
->WaitKey
, Increment
);
1342 /* Unwait the thread with STATUS_KERNEL_APC */
1343 KiUnwaitThread(WaitThread
, STATUS_KERNEL_APC
, Increment
);
1346 WaitEntry
= WaitList
->Flink
;
1347 } while (WaitEntry
!= WaitList
);
1351 // This routine queues a thread that is ready on the PRCB's ready lists.
1352 // If this thread cannot currently run on this CPU, then the thread is
1353 // added to the deferred ready list instead.
1355 // This routine must be entered with the PRCB lock held and it will exit
1356 // with the PRCB lock released!
1360 KxQueueReadyThread(IN PKTHREAD Thread
,
1367 ASSERT(Prcb
== KeGetCurrentPrcb());
1368 ASSERT(Thread
->State
== Running
);
1369 ASSERT(Thread
->NextProcessor
== Prcb
->Number
);
1371 /* Check if this thread is allowed to run in this CPU */
1373 if ((Thread
->Affinity
) & (Prcb
->SetMember
))
1378 /* Set thread ready for execution */
1379 Thread
->State
= Ready
;
1381 /* Save current priority and if someone had pre-empted it */
1382 Priority
= Thread
->Priority
;
1383 Preempted
= Thread
->Preempted
;
1385 /* We're not pre-empting now, and set the wait time */
1386 Thread
->Preempted
= FALSE
;
1387 Thread
->WaitTime
= KeTickCount
.LowPart
;
1390 ASSERT((Priority
>= 0) && (Priority
<= HIGH_PRIORITY
));
1392 /* Insert this thread in the appropriate order */
1393 Preempted
? InsertHeadList(&Prcb
->DispatcherReadyListHead
[Priority
],
1394 &Thread
->WaitListEntry
) :
1395 InsertTailList(&Prcb
->DispatcherReadyListHead
[Priority
],
1396 &Thread
->WaitListEntry
);
1398 /* Update the ready summary */
1399 Prcb
->ReadySummary
|= PRIORITY_MASK(Priority
);
1402 ASSERT(Priority
== Thread
->Priority
);
1404 /* Release the PRCB lock */
1405 KiReleasePrcbLock(Prcb
);
1409 /* Otherwise, prepare this thread to be deferred */
1410 Thread
->State
= DeferredReady
;
1411 Thread
->DeferredProcessor
= Prcb
->Number
;
1413 /* Release the lock and defer scheduling */
1414 KiReleasePrcbLock(Prcb
);
1415 KiDeferredReadyThread(Thread
);
1420 // This routine scans for an appropriate ready thread to select at the
1421 // given priority and for the given CPU.
1425 KiSelectReadyThread(IN KPRIORITY Priority
,
1430 PLIST_ENTRY ListEntry
;
1431 PKTHREAD Thread
= NULL
;
1433 /* Save the current mask and get the priority set for the CPU */
1434 PrioritySet
= Prcb
->ReadySummary
>> Priority
;
1435 if (!PrioritySet
) goto Quickie
;
1437 /* Get the highest priority possible */
1438 BitScanReverse((PULONG
)&HighPriority
, PrioritySet
);
1439 ASSERT((PrioritySet
& PRIORITY_MASK(HighPriority
)) != 0);
1440 HighPriority
+= Priority
;
1442 /* Make sure the list isn't empty at the highest priority */
1443 ASSERT(IsListEmpty(&Prcb
->DispatcherReadyListHead
[HighPriority
]) == FALSE
);
1445 /* Get the first thread on the list */
1446 ListEntry
= Prcb
->DispatcherReadyListHead
[HighPriority
].Flink
;
1447 Thread
= CONTAINING_RECORD(ListEntry
, KTHREAD
, WaitListEntry
);
1449 /* Make sure this thread is here for a reason */
1450 ASSERT(HighPriority
== Thread
->Priority
);
1451 ASSERT(Thread
->Affinity
& AFFINITY_MASK(Prcb
->Number
));
1452 ASSERT(Thread
->NextProcessor
== Prcb
->Number
);
1454 /* Remove it from the list */
1455 if (RemoveEntryList(&Thread
->WaitListEntry
))
1457 /* The list is empty now, reset the ready summary */
1458 Prcb
->ReadySummary
^= PRIORITY_MASK(HighPriority
);
1461 /* Sanity check and return the thread */
1463 ASSERT((Thread
== NULL
) ||
1464 (Thread
->BasePriority
== 0) ||
1465 (Thread
->Priority
!= 0));
1470 // This routine computes the new priority for a thread. It is only valid for
1471 // threads with priorities in the dynamic priority range.
1475 KiComputeNewPriority(IN PKTHREAD Thread
,
1476 IN SCHAR Adjustment
)
1480 /* Priority sanity checks */
1481 ASSERT((Thread
->PriorityDecrement
>= 0) &&
1482 (Thread
->PriorityDecrement
<= Thread
->Priority
));
1483 ASSERT((Thread
->Priority
< LOW_REALTIME_PRIORITY
) ?
1484 TRUE
: (Thread
->PriorityDecrement
== 0));
1486 /* Get the current priority */
1487 Priority
= Thread
->Priority
;
1488 if (Priority
< LOW_REALTIME_PRIORITY
)
1490 /* Decrease priority by the priority decrement */
1491 Priority
-= (Thread
->PriorityDecrement
+ Adjustment
);
1493 /* Don't go out of bounds */
1494 if (Priority
< Thread
->BasePriority
) Priority
= Thread
->BasePriority
;
1496 /* Reset the priority decrement */
1497 Thread
->PriorityDecrement
= 0;
1501 ASSERT((Thread
->BasePriority
== 0) || (Priority
!= 0));
1503 /* Return the new priority */
1508 // Guarded Mutex Routines
1512 _KeInitializeGuardedMutex(OUT PKGUARDED_MUTEX GuardedMutex
)
1514 /* Setup the Initial Data */
1515 GuardedMutex
->Count
= GM_LOCK_BIT
;
1516 GuardedMutex
->Owner
= NULL
;
1517 GuardedMutex
->Contention
= 0;
1519 /* Initialize the Wait Gate */
1520 KeInitializeGate(&GuardedMutex
->Gate
);
1525 _KeAcquireGuardedMutexUnsafe(IN OUT PKGUARDED_MUTEX GuardedMutex
)
1527 PKTHREAD Thread
= KeGetCurrentThread();
1530 ASSERT((KeGetCurrentIrql() == APC_LEVEL
) ||
1531 (Thread
->SpecialApcDisable
< 0) ||
1532 (Thread
->Teb
== NULL
) ||
1533 (Thread
->Teb
>= (PTEB
)MM_SYSTEM_RANGE_START
));
1534 ASSERT(GuardedMutex
->Owner
!= Thread
);
1536 /* Remove the lock */
1537 if (!InterlockedBitTestAndReset(&GuardedMutex
->Count
, GM_LOCK_BIT_V
))
1539 /* The Guarded Mutex was already locked, enter contented case */
1540 KiAcquireGuardedMutex(GuardedMutex
);
1544 GuardedMutex
->Owner
= Thread
;
1549 _KeReleaseGuardedMutexUnsafe(IN OUT PKGUARDED_MUTEX GuardedMutex
)
1551 LONG OldValue
, NewValue
;
1554 ASSERT((KeGetCurrentIrql() == APC_LEVEL
) ||
1555 (KeGetCurrentThread()->SpecialApcDisable
< 0) ||
1556 (KeGetCurrentThread()->Teb
== NULL
) ||
1557 (KeGetCurrentThread()->Teb
>= (PTEB
)MM_SYSTEM_RANGE_START
));
1558 ASSERT(GuardedMutex
->Owner
== KeGetCurrentThread());
1560 /* Destroy the Owner */
1561 GuardedMutex
->Owner
= NULL
;
1563 /* Add the Lock Bit */
1564 OldValue
= InterlockedExchangeAdd(&GuardedMutex
->Count
, GM_LOCK_BIT
);
1565 ASSERT((OldValue
& GM_LOCK_BIT
) == 0);
1567 /* Check if it was already locked, but not woken */
1568 if ((OldValue
) && !(OldValue
& GM_LOCK_WAITER_WOKEN
))
1570 /* Update the Oldvalue to what it should be now */
1571 OldValue
+= GM_LOCK_BIT
;
1573 /* The mutex will be woken, minus one waiter */
1574 NewValue
= OldValue
+ GM_LOCK_WAITER_WOKEN
-
1577 /* Remove the Woken bit */
1578 if (InterlockedCompareExchange(&GuardedMutex
->Count
,
1580 OldValue
) == OldValue
)
1582 /* Signal the Gate */
1583 KeSignalGateBoostPriority(&GuardedMutex
->Gate
);
1590 _KeAcquireGuardedMutex(IN PKGUARDED_MUTEX GuardedMutex
)
1592 PKTHREAD Thread
= KeGetCurrentThread();
1595 ASSERT(KeGetCurrentIrql() <= APC_LEVEL
);
1596 ASSERT(GuardedMutex
->Owner
!= Thread
);
1598 /* Disable Special APCs */
1599 KeEnterGuardedRegion();
1601 /* Remove the lock */
1602 if (!InterlockedBitTestAndReset(&GuardedMutex
->Count
, GM_LOCK_BIT_V
))
1604 /* The Guarded Mutex was already locked, enter contented case */
1605 KiAcquireGuardedMutex(GuardedMutex
);
1608 /* Set the Owner and Special APC Disable state */
1609 GuardedMutex
->Owner
= Thread
;
1610 GuardedMutex
->SpecialApcDisable
= Thread
->SpecialApcDisable
;
1615 _KeReleaseGuardedMutex(IN OUT PKGUARDED_MUTEX GuardedMutex
)
1617 LONG OldValue
, NewValue
;
1620 ASSERT(KeGetCurrentIrql() <= APC_LEVEL
);
1621 ASSERT(GuardedMutex
->Owner
== KeGetCurrentThread());
1622 ASSERT(KeGetCurrentThread()->SpecialApcDisable
==
1623 GuardedMutex
->SpecialApcDisable
);
1625 /* Destroy the Owner */
1626 GuardedMutex
->Owner
= NULL
;
1628 /* Add the Lock Bit */
1629 OldValue
= InterlockedExchangeAdd(&GuardedMutex
->Count
, GM_LOCK_BIT
);
1630 ASSERT((OldValue
& GM_LOCK_BIT
) == 0);
1632 /* Check if it was already locked, but not woken */
1633 if ((OldValue
) && !(OldValue
& GM_LOCK_WAITER_WOKEN
))
1635 /* Update the Oldvalue to what it should be now */
1636 OldValue
+= GM_LOCK_BIT
;
1638 /* The mutex will be woken, minus one waiter */
1639 NewValue
= OldValue
+ GM_LOCK_WAITER_WOKEN
-
1642 /* Remove the Woken bit */
1643 if (InterlockedCompareExchange(&GuardedMutex
->Count
,
1645 OldValue
) == OldValue
)
1647 /* Signal the Gate */
1648 KeSignalGateBoostPriority(&GuardedMutex
->Gate
);
1652 /* Re-enable APCs */
1653 KeLeaveGuardedRegion();
1658 _KeTryToAcquireGuardedMutex(IN OUT PKGUARDED_MUTEX GuardedMutex
)
1660 PKTHREAD Thread
= KeGetCurrentThread();
1663 KeEnterGuardedRegion();
1665 /* Remove the lock */
1666 if (!InterlockedBitTestAndReset(&GuardedMutex
->Count
, GM_LOCK_BIT_V
))
1668 /* Re-enable APCs */
1669 KeLeaveGuardedRegion();
1672 /* Return failure */
1676 /* Set the Owner and APC State */
1677 GuardedMutex
->Owner
= Thread
;
1678 GuardedMutex
->SpecialApcDisable
= Thread
->SpecialApcDisable
;
1685 KiAcquireNmiListLock(OUT PKIRQL OldIrql
)
1687 KeAcquireSpinLock(&KiNmiCallbackListLock
, OldIrql
);
1692 KiReleaseNmiListLock(IN KIRQL OldIrql
)
1694 KeReleaseSpinLock(&KiNmiCallbackListLock
, OldIrql
);