xref: /reactos/ntoskrnl/include/internal/ke_x.h (revision 748a2e16)
1c2c66affSColin Finck /*
2c2c66affSColin Finck * PROJECT:         ReactOS Kernel
3c2c66affSColin Finck * LICENSE:         GPL - See COPYING in the top level directory
4c2c66affSColin Finck * FILE:            ntoskrnl/include/internal/ke_x.h
5c2c66affSColin Finck * PURPOSE:         Internal Inlined Functions for the Kernel
6c2c66affSColin Finck * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
7c2c66affSColin Finck */
8c2c66affSColin Finck 
931afbf10SJérôme Gardou #ifdef __cplusplus
1031afbf10SJérôme Gardou extern "C"
1131afbf10SJérôme Gardou {
1231afbf10SJérôme Gardou #endif
1331afbf10SJérôme Gardou 
14c2c66affSColin Finck #ifndef _M_ARM
15c2c66affSColin Finck FORCEINLINE
16c2c66affSColin Finck KPROCESSOR_MODE
KeGetPreviousMode(VOID)17c2c66affSColin Finck KeGetPreviousMode(VOID)
18c2c66affSColin Finck {
19c2c66affSColin Finck     /* Return the current mode */
20c2c66affSColin Finck     return KeGetCurrentThread()->PreviousMode;
21c2c66affSColin Finck }
22c2c66affSColin Finck #endif
23c2c66affSColin Finck 
24c2c66affSColin Finck //
25c2c66affSColin Finck // Enters a Guarded Region
26c2c66affSColin Finck //
27c2c66affSColin Finck #define KeEnterGuardedRegionThread(_Thread)                                 \
28c2c66affSColin Finck {                                                                           \
29c2c66affSColin Finck     /* Sanity checks */                                                     \
30c2c66affSColin Finck     ASSERT(KeGetCurrentIrql() <= APC_LEVEL);                                \
312e76fb9fSThomas Faber     ASSERT((_Thread) == KeGetCurrentThread());                              \
322e76fb9fSThomas Faber     ASSERT(((_Thread)->SpecialApcDisable <= 0) &&                           \
332e76fb9fSThomas Faber            ((_Thread)->SpecialApcDisable != -32768));                       \
34c2c66affSColin Finck                                                                             \
35c2c66affSColin Finck     /* Disable Special APCs */                                              \
362e76fb9fSThomas Faber     (_Thread)->SpecialApcDisable--;                                         \
37c2c66affSColin Finck }
38c2c66affSColin Finck 
39c2c66affSColin Finck #define KeEnterGuardedRegion()                                              \
40c2c66affSColin Finck {                                                                           \
41c2c66affSColin Finck     PKTHREAD _Thread = KeGetCurrentThread();                                \
42c2c66affSColin Finck     KeEnterGuardedRegionThread(_Thread);                                    \
43c2c66affSColin Finck }
44c2c66affSColin Finck 
45c2c66affSColin Finck //
46c2c66affSColin Finck // Leaves a Guarded Region
47c2c66affSColin Finck //
48c2c66affSColin Finck #define KeLeaveGuardedRegionThread(_Thread)                                 \
49c2c66affSColin Finck {                                                                           \
50c2c66affSColin Finck     /* Sanity checks */                                                     \
51c2c66affSColin Finck     ASSERT(KeGetCurrentIrql() <= APC_LEVEL);                                \
522e76fb9fSThomas Faber     ASSERT((_Thread) == KeGetCurrentThread());                              \
532e76fb9fSThomas Faber     ASSERT((_Thread)->SpecialApcDisable < 0);                               \
54c2c66affSColin Finck                                                                             \
55c2c66affSColin Finck     /* Leave region and check if APCs are OK now */                         \
562e76fb9fSThomas Faber     if (!(++(_Thread)->SpecialApcDisable))                                  \
57c2c66affSColin Finck     {                                                                       \
58c2c66affSColin Finck         /* Check for Kernel APCs on the list */                             \
592e76fb9fSThomas Faber         if (!IsListEmpty(&(_Thread)->ApcState.                              \
60c2c66affSColin Finck                          ApcListHead[KernelMode]))                          \
61c2c66affSColin Finck         {                                                                   \
62c2c66affSColin Finck             /* Check for APC Delivery */                                    \
63c2c66affSColin Finck             KiCheckForKernelApcDelivery();                                  \
64c2c66affSColin Finck         }                                                                   \
65c2c66affSColin Finck     }                                                                       \
66c2c66affSColin Finck }
67c2c66affSColin Finck 
68c2c66affSColin Finck #define KeLeaveGuardedRegion()                                              \
69c2c66affSColin Finck {                                                                           \
70c2c66affSColin Finck     PKTHREAD _Thread = KeGetCurrentThread();                                \
71c2c66affSColin Finck     KeLeaveGuardedRegionThread(_Thread);                                    \
72c2c66affSColin Finck }
73c2c66affSColin Finck 
74c2c66affSColin Finck //
75c2c66affSColin Finck // Enters a Critical Region
76c2c66affSColin Finck //
77c2c66affSColin Finck #define KeEnterCriticalRegionThread(_Thread)                                \
78c2c66affSColin Finck {                                                                           \
79c2c66affSColin Finck     /* Sanity checks */                                                     \
802e76fb9fSThomas Faber     ASSERT((_Thread) == KeGetCurrentThread());                              \
812e76fb9fSThomas Faber     ASSERT(((_Thread)->KernelApcDisable <= 0) &&                            \
822e76fb9fSThomas Faber            ((_Thread)->KernelApcDisable != -32768));                        \
83c2c66affSColin Finck                                                                             \
84c2c66affSColin Finck     /* Disable Kernel APCs */                                               \
852e76fb9fSThomas Faber     (_Thread)->KernelApcDisable--;                                          \
86c2c66affSColin Finck }
87c2c66affSColin Finck 
88c2c66affSColin Finck #define KeEnterCriticalRegion()                                             \
89c2c66affSColin Finck {                                                                           \
90c2c66affSColin Finck     PKTHREAD _Thread = KeGetCurrentThread();                                \
91c2c66affSColin Finck     KeEnterCriticalRegionThread(_Thread);                                   \
92c2c66affSColin Finck }
93c2c66affSColin Finck 
94c2c66affSColin Finck //
95c2c66affSColin Finck // Leaves a Critical Region
96c2c66affSColin Finck //
97c2c66affSColin Finck #define KeLeaveCriticalRegionThread(_Thread)                                \
98c2c66affSColin Finck {                                                                           \
99c2c66affSColin Finck     /* Sanity checks */                                                     \
1002e76fb9fSThomas Faber     ASSERT((_Thread) == KeGetCurrentThread());                              \
1012e76fb9fSThomas Faber     ASSERT((_Thread)->KernelApcDisable < 0);                                \
102c2c66affSColin Finck                                                                             \
103c2c66affSColin Finck     /* Enable Kernel APCs */                                                \
1042e76fb9fSThomas Faber     (_Thread)->KernelApcDisable++;                                          \
105c2c66affSColin Finck                                                                             \
106c2c66affSColin Finck     /* Check if Kernel APCs are now enabled */                              \
1072e76fb9fSThomas Faber     if (!((_Thread)->KernelApcDisable))                                     \
108c2c66affSColin Finck     {                                                                       \
109c2c66affSColin Finck         /* Check if we need to request an APC Delivery */                   \
1102e76fb9fSThomas Faber         if (!(IsListEmpty(&(_Thread)->ApcState.ApcListHead[KernelMode])) && \
1112e76fb9fSThomas Faber             !((_Thread)->SpecialApcDisable))                                \
112c2c66affSColin Finck         {                                                                   \
113c2c66affSColin Finck             /* Check for the right environment */                           \
114c2c66affSColin Finck             KiCheckForKernelApcDelivery();                                  \
115c2c66affSColin Finck         }                                                                   \
116c2c66affSColin Finck     }                                                                       \
117c2c66affSColin Finck }
118c2c66affSColin Finck 
119c2c66affSColin Finck #define KeLeaveCriticalRegion()                                             \
120c2c66affSColin Finck {                                                                           \
121c2c66affSColin Finck     PKTHREAD _Thread = KeGetCurrentThread();                                \
122c2c66affSColin Finck     KeLeaveCriticalRegionThread(_Thread);                                   \
123c2c66affSColin Finck }
124c2c66affSColin Finck 
125c2c66affSColin Finck #ifndef CONFIG_SMP
126c2c66affSColin Finck 
127c2c66affSColin Finck //
128c2c66affSColin Finck // This routine protects against multiple CPU acquires, it's meaningless on UP.
129c2c66affSColin Finck //
130c2c66affSColin Finck FORCEINLINE
131c2c66affSColin Finck VOID
KiAcquireDispatcherObject(IN DISPATCHER_HEADER * Object)132c2c66affSColin Finck KiAcquireDispatcherObject(IN DISPATCHER_HEADER* Object)
133c2c66affSColin Finck {
134c2c66affSColin Finck     UNREFERENCED_PARAMETER(Object);
135c2c66affSColin Finck }
136c2c66affSColin Finck 
137c2c66affSColin Finck //
138c2c66affSColin Finck // This routine protects against multiple CPU acquires, it's meaningless on UP.
139c2c66affSColin Finck //
140c2c66affSColin Finck FORCEINLINE
141c2c66affSColin Finck VOID
KiReleaseDispatcherObject(IN DISPATCHER_HEADER * Object)142c2c66affSColin Finck KiReleaseDispatcherObject(IN DISPATCHER_HEADER* Object)
143c2c66affSColin Finck {
144c2c66affSColin Finck     UNREFERENCED_PARAMETER(Object);
145c2c66affSColin Finck }
146c2c66affSColin Finck 
147c2c66affSColin Finck FORCEINLINE
148c2c66affSColin Finck KIRQL
KiAcquireDispatcherLock(VOID)149c2c66affSColin Finck KiAcquireDispatcherLock(VOID)
150c2c66affSColin Finck {
151c2c66affSColin Finck     /* Raise to synch level */
152c2c66affSColin Finck     return KfRaiseIrql(SYNCH_LEVEL);
153c2c66affSColin Finck }
154c2c66affSColin Finck 
155c2c66affSColin Finck FORCEINLINE
156c2c66affSColin Finck VOID
KiReleaseDispatcherLock(IN KIRQL OldIrql)157c2c66affSColin Finck KiReleaseDispatcherLock(IN KIRQL OldIrql)
158c2c66affSColin Finck {
159c2c66affSColin Finck     /* Just exit the dispatcher */
160c2c66affSColin Finck     KiExitDispatcher(OldIrql);
161c2c66affSColin Finck }
162c2c66affSColin Finck 
163c2c66affSColin Finck FORCEINLINE
164c2c66affSColin Finck VOID
KiAcquireDispatcherLockAtSynchLevel(VOID)1657523a7b1STimo Kreuzer KiAcquireDispatcherLockAtSynchLevel(VOID)
166c2c66affSColin Finck {
1677523a7b1STimo Kreuzer     /* This is a no-op at SYNCH_LEVEL for UP systems */
1687523a7b1STimo Kreuzer     ASSERT(KeGetCurrentIrql() >= SYNCH_LEVEL);
169c2c66affSColin Finck     return;
170c2c66affSColin Finck }
171c2c66affSColin Finck 
172c2c66affSColin Finck FORCEINLINE
173c2c66affSColin Finck VOID
KiReleaseDispatcherLockFromSynchLevel(VOID)1747523a7b1STimo Kreuzer KiReleaseDispatcherLockFromSynchLevel(VOID)
175c2c66affSColin Finck {
1767523a7b1STimo Kreuzer     /* This is a no-op at SYNCH_LEVEL for UP systems */
177c2c66affSColin Finck     return;
178c2c66affSColin Finck }
179c2c66affSColin Finck 
180c2c66affSColin Finck //
181c2c66affSColin Finck // This routine makes the thread deferred ready on the boot CPU.
182c2c66affSColin Finck //
183c2c66affSColin Finck FORCEINLINE
184c2c66affSColin Finck VOID
KiInsertDeferredReadyList(IN PKTHREAD Thread)185c2c66affSColin Finck KiInsertDeferredReadyList(IN PKTHREAD Thread)
186c2c66affSColin Finck {
187c2c66affSColin Finck     /* Set the thread to deferred state and boot CPU */
188c2c66affSColin Finck     Thread->State = DeferredReady;
189c2c66affSColin Finck     Thread->DeferredProcessor = 0;
190c2c66affSColin Finck 
191c2c66affSColin Finck     /* Make the thread ready immediately */
192c2c66affSColin Finck     KiDeferredReadyThread(Thread);
193c2c66affSColin Finck }
194c2c66affSColin Finck 
195c2c66affSColin Finck FORCEINLINE
196c2c66affSColin Finck VOID
KiRescheduleThread(IN BOOLEAN NewThread,IN ULONG Cpu)197c2c66affSColin Finck KiRescheduleThread(IN BOOLEAN NewThread,
198c2c66affSColin Finck                    IN ULONG Cpu)
199c2c66affSColin Finck {
200c2c66affSColin Finck     /* This is meaningless on UP systems */
201c2c66affSColin Finck     UNREFERENCED_PARAMETER(NewThread);
202c2c66affSColin Finck     UNREFERENCED_PARAMETER(Cpu);
203c2c66affSColin Finck }
204c2c66affSColin Finck 
205c2c66affSColin Finck //
206c2c66affSColin Finck // This routine protects against multiple CPU acquires, it's meaningless on UP.
207c2c66affSColin Finck //
208c2c66affSColin Finck FORCEINLINE
209c2c66affSColin Finck VOID
KiSetThreadSwapBusy(IN PKTHREAD Thread)210c2c66affSColin Finck KiSetThreadSwapBusy(IN PKTHREAD Thread)
211c2c66affSColin Finck {
212c2c66affSColin Finck     UNREFERENCED_PARAMETER(Thread);
213c2c66affSColin Finck }
214c2c66affSColin Finck 
215c2c66affSColin Finck //
216c2c66affSColin Finck // This routine protects against multiple CPU acquires, it's meaningless on UP.
217c2c66affSColin Finck //
218c2c66affSColin Finck FORCEINLINE
219c2c66affSColin Finck VOID
KiAcquirePrcbLock(IN PKPRCB Prcb)220c2c66affSColin Finck KiAcquirePrcbLock(IN PKPRCB Prcb)
221c2c66affSColin Finck {
222c2c66affSColin Finck     UNREFERENCED_PARAMETER(Prcb);
223c2c66affSColin Finck }
224c2c66affSColin Finck 
225c2c66affSColin Finck //
226c2c66affSColin Finck // This routine protects against multiple CPU acquires, it's meaningless on UP.
227c2c66affSColin Finck //
228c2c66affSColin Finck FORCEINLINE
229c2c66affSColin Finck VOID
KiReleasePrcbLock(IN PKPRCB Prcb)230c2c66affSColin Finck KiReleasePrcbLock(IN PKPRCB Prcb)
231c2c66affSColin Finck {
232c2c66affSColin Finck     UNREFERENCED_PARAMETER(Prcb);
233c2c66affSColin Finck }
234c2c66affSColin Finck 
235c2c66affSColin Finck //
236c2c66affSColin Finck // This routine protects against multiple CPU acquires, it's meaningless on UP.
237c2c66affSColin Finck //
238c2c66affSColin Finck FORCEINLINE
239c2c66affSColin Finck VOID
KiAcquireThreadLock(IN PKTHREAD Thread)240c2c66affSColin Finck KiAcquireThreadLock(IN PKTHREAD Thread)
241c2c66affSColin Finck {
242c2c66affSColin Finck     UNREFERENCED_PARAMETER(Thread);
243c2c66affSColin Finck }
244c2c66affSColin Finck 
245c2c66affSColin Finck //
246c2c66affSColin Finck // This routine protects against multiple CPU acquires, it's meaningless on UP.
247c2c66affSColin Finck //
248c2c66affSColin Finck FORCEINLINE
249c2c66affSColin Finck VOID
KiReleaseThreadLock(IN PKTHREAD Thread)250c2c66affSColin Finck KiReleaseThreadLock(IN PKTHREAD Thread)
251c2c66affSColin Finck {
252c2c66affSColin Finck     UNREFERENCED_PARAMETER(Thread);
253c2c66affSColin Finck }
254c2c66affSColin Finck 
255c2c66affSColin Finck //
256c2c66affSColin Finck // This routine protects against multiple CPU acquires, it's meaningless on UP.
257c2c66affSColin Finck //
258c2c66affSColin Finck FORCEINLINE
259c2c66affSColin Finck BOOLEAN
KiTryThreadLock(IN PKTHREAD Thread)260c2c66affSColin Finck KiTryThreadLock(IN PKTHREAD Thread)
261c2c66affSColin Finck {
262c2c66affSColin Finck     UNREFERENCED_PARAMETER(Thread);
263c2c66affSColin Finck     return FALSE;
264c2c66affSColin Finck }
265c2c66affSColin Finck 
266c2c66affSColin Finck FORCEINLINE
267c2c66affSColin Finck VOID
KiCheckDeferredReadyList(IN PKPRCB Prcb)268c2c66affSColin Finck KiCheckDeferredReadyList(IN PKPRCB Prcb)
269c2c66affSColin Finck {
270c2c66affSColin Finck     /* There are no deferred ready lists on UP systems */
271c2c66affSColin Finck     UNREFERENCED_PARAMETER(Prcb);
272c2c66affSColin Finck }
273c2c66affSColin Finck 
274c2c66affSColin Finck FORCEINLINE
275c2c66affSColin Finck VOID
KiRequestApcInterrupt(IN BOOLEAN NeedApc,IN UCHAR Processor)276c2c66affSColin Finck KiRequestApcInterrupt(IN BOOLEAN NeedApc,
277c2c66affSColin Finck                       IN UCHAR Processor)
278c2c66affSColin Finck {
279c2c66affSColin Finck     /* We deliver instantly on UP */
280c2c66affSColin Finck     UNREFERENCED_PARAMETER(NeedApc);
281c2c66affSColin Finck     UNREFERENCED_PARAMETER(Processor);
282c2c66affSColin Finck }
283c2c66affSColin Finck 
284c2c66affSColin Finck FORCEINLINE
285c2c66affSColin Finck PKSPIN_LOCK_QUEUE
KiAcquireTimerLock(IN ULONG Hand)286c2c66affSColin Finck KiAcquireTimerLock(IN ULONG Hand)
287c2c66affSColin Finck {
288c2c66affSColin Finck     ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
289c2c66affSColin Finck 
290c2c66affSColin Finck     /* Nothing to do on UP */
291c2c66affSColin Finck     UNREFERENCED_PARAMETER(Hand);
292c2c66affSColin Finck     return NULL;
293c2c66affSColin Finck }
294c2c66affSColin Finck 
295c2c66affSColin Finck FORCEINLINE
296c2c66affSColin Finck VOID
KiReleaseTimerLock(IN PKSPIN_LOCK_QUEUE LockQueue)297c2c66affSColin Finck KiReleaseTimerLock(IN PKSPIN_LOCK_QUEUE LockQueue)
298c2c66affSColin Finck {
299c2c66affSColin Finck     ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
300c2c66affSColin Finck 
301c2c66affSColin Finck     /* Nothing to do on UP */
302c2c66affSColin Finck     UNREFERENCED_PARAMETER(LockQueue);
303c2c66affSColin Finck }
304c2c66affSColin Finck 
305c2c66affSColin Finck #else
306c2c66affSColin Finck 
307c2c66affSColin Finck FORCEINLINE
308c2c66affSColin Finck VOID
KiAcquireDispatcherObject(IN DISPATCHER_HEADER * Object)309c2c66affSColin Finck KiAcquireDispatcherObject(IN DISPATCHER_HEADER* Object)
310c2c66affSColin Finck {
311c2c66affSColin Finck     LONG OldValue;
312c2c66affSColin Finck 
313c2c66affSColin Finck     /* Make sure we're at a safe level to touch the lock */
314c2c66affSColin Finck     ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
315c2c66affSColin Finck 
316c2c66affSColin Finck     /* Start acquire loop */
317c2c66affSColin Finck     do
318c2c66affSColin Finck     {
319c2c66affSColin Finck         /* Loop until the other CPU releases it */
320c2c66affSColin Finck         while (TRUE)
321c2c66affSColin Finck         {
322c2c66affSColin Finck             /* Check if it got released */
323c2c66affSColin Finck             OldValue = Object->Lock;
324c2c66affSColin Finck             if ((OldValue & KOBJECT_LOCK_BIT) == 0) break;
325c2c66affSColin Finck 
326c2c66affSColin Finck             /* Let the CPU know that this is a loop */
327c2c66affSColin Finck             YieldProcessor();
328c2c66affSColin Finck         }
329c2c66affSColin Finck 
330c2c66affSColin Finck         /* Try acquiring the lock now */
331c2c66affSColin Finck     } while (InterlockedCompareExchange(&Object->Lock,
332c2c66affSColin Finck                                         OldValue | KOBJECT_LOCK_BIT,
333c2c66affSColin Finck                                         OldValue) != OldValue);
334c2c66affSColin Finck }
335c2c66affSColin Finck 
336c2c66affSColin Finck FORCEINLINE
337c2c66affSColin Finck VOID
KiReleaseDispatcherObject(IN DISPATCHER_HEADER * Object)338c2c66affSColin Finck KiReleaseDispatcherObject(IN DISPATCHER_HEADER* Object)
339c2c66affSColin Finck {
340c2c66affSColin Finck     /* Make sure we're at a safe level to touch the lock */
341c2c66affSColin Finck     ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
342c2c66affSColin Finck 
343c2c66affSColin Finck     /* Release it */
344c2c66affSColin Finck     InterlockedAnd(&Object->Lock, ~KOBJECT_LOCK_BIT);
345c2c66affSColin Finck }
346c2c66affSColin Finck 
347c2c66affSColin Finck FORCEINLINE
348c2c66affSColin Finck KIRQL
KiAcquireDispatcherLock(VOID)349c2c66affSColin Finck KiAcquireDispatcherLock(VOID)
350c2c66affSColin Finck {
351c2c66affSColin Finck     /* Raise to synchronization level and acquire the dispatcher lock */
352c2c66affSColin Finck     return KeAcquireQueuedSpinLockRaiseToSynch(LockQueueDispatcherLock);
353c2c66affSColin Finck }
354c2c66affSColin Finck 
355c2c66affSColin Finck FORCEINLINE
356c2c66affSColin Finck VOID
KiReleaseDispatcherLock(IN KIRQL OldIrql)357c2c66affSColin Finck KiReleaseDispatcherLock(IN KIRQL OldIrql)
358c2c66affSColin Finck {
359c2c66affSColin Finck     /* First release the lock */
360c2c66affSColin Finck     KeReleaseQueuedSpinLockFromDpcLevel(&KeGetCurrentPrcb()->
361c2c66affSColin Finck                                         LockQueue[LockQueueDispatcherLock]);
362c2c66affSColin Finck 
363c2c66affSColin Finck     /* Then exit the dispatcher */
364c2c66affSColin Finck     KiExitDispatcher(OldIrql);
365c2c66affSColin Finck }
366c2c66affSColin Finck 
367c2c66affSColin Finck FORCEINLINE
368c2c66affSColin Finck VOID
KiAcquireDispatcherLockAtSynchLevel(VOID)3697523a7b1STimo Kreuzer KiAcquireDispatcherLockAtSynchLevel(VOID)
370c2c66affSColin Finck {
371c2c66affSColin Finck     /* Acquire the dispatcher lock */
3727523a7b1STimo Kreuzer     ASSERT(KeGetCurrentIrql() >= SYNCH_LEVEL);
373c2c66affSColin Finck     KeAcquireQueuedSpinLockAtDpcLevel(&KeGetCurrentPrcb()->
374c2c66affSColin Finck                                       LockQueue[LockQueueDispatcherLock]);
375c2c66affSColin Finck }
376c2c66affSColin Finck 
377c2c66affSColin Finck FORCEINLINE
378c2c66affSColin Finck VOID
KiReleaseDispatcherLockFromSynchLevel(VOID)3797523a7b1STimo Kreuzer KiReleaseDispatcherLockFromSynchLevel(VOID)
380c2c66affSColin Finck {
381c2c66affSColin Finck     /* Release the dispatcher lock */
382c2c66affSColin Finck     KeReleaseQueuedSpinLockFromDpcLevel(&KeGetCurrentPrcb()->
383c2c66affSColin Finck                                         LockQueue[LockQueueDispatcherLock]);
384c2c66affSColin Finck }
385c2c66affSColin Finck 
386c2c66affSColin Finck //
387c2c66affSColin Finck // This routine inserts a thread into the deferred ready list of the current CPU
388c2c66affSColin Finck //
389c2c66affSColin Finck FORCEINLINE
390c2c66affSColin Finck VOID
KiInsertDeferredReadyList(IN PKTHREAD Thread)391c2c66affSColin Finck KiInsertDeferredReadyList(IN PKTHREAD Thread)
392c2c66affSColin Finck {
393c2c66affSColin Finck     PKPRCB Prcb = KeGetCurrentPrcb();
394c2c66affSColin Finck 
395c2c66affSColin Finck     /* Set the thread to deferred state and CPU */
396c2c66affSColin Finck     Thread->State = DeferredReady;
397c2c66affSColin Finck     Thread->DeferredProcessor = Prcb->Number;
398c2c66affSColin Finck 
399c2c66affSColin Finck     /* Add it on the list */
400c2c66affSColin Finck     PushEntryList(&Prcb->DeferredReadyListHead, &Thread->SwapListEntry);
401c2c66affSColin Finck }
402c2c66affSColin Finck 
403c2c66affSColin Finck FORCEINLINE
404c2c66affSColin Finck VOID
KiRescheduleThread(IN BOOLEAN NewThread,IN ULONG Cpu)405c2c66affSColin Finck KiRescheduleThread(IN BOOLEAN NewThread,
406c2c66affSColin Finck                    IN ULONG Cpu)
407c2c66affSColin Finck {
408c2c66affSColin Finck     /* Check if a new thread needs to be scheduled on a different CPU */
409c2c66affSColin Finck     if ((NewThread) && !(KeGetCurrentPrcb()->Number == Cpu))
410c2c66affSColin Finck     {
411c2c66affSColin Finck         /* Send an IPI to request delivery */
412c2c66affSColin Finck         KiIpiSend(AFFINITY_MASK(Cpu), IPI_DPC);
413c2c66affSColin Finck     }
414c2c66affSColin Finck }
415c2c66affSColin Finck 
416c2c66affSColin Finck //
417c2c66affSColin Finck // This routine sets the current thread in a swap busy state, which ensure that
418c2c66affSColin Finck // nobody else tries to swap it concurrently.
419c2c66affSColin Finck //
420c2c66affSColin Finck FORCEINLINE
421c2c66affSColin Finck VOID
KiSetThreadSwapBusy(IN PKTHREAD Thread)422c2c66affSColin Finck KiSetThreadSwapBusy(IN PKTHREAD Thread)
423c2c66affSColin Finck {
424c2c66affSColin Finck     /* Make sure nobody already set it */
425c2c66affSColin Finck     ASSERT(Thread->SwapBusy == FALSE);
426c2c66affSColin Finck 
427c2c66affSColin Finck     /* Set it ourselves */
428c2c66affSColin Finck     Thread->SwapBusy = TRUE;
429c2c66affSColin Finck }
430c2c66affSColin Finck 
431c2c66affSColin Finck //
432c2c66affSColin Finck // This routine acquires the PRCB lock so that only one caller can touch
433c2c66affSColin Finck // volatile PRCB data.
434c2c66affSColin Finck //
435c2c66affSColin Finck // Since this is a simple optimized spin-lock, it must only be acquired
436c2c66affSColin Finck // at dispatcher level or higher!
437c2c66affSColin Finck //
438c2c66affSColin Finck FORCEINLINE
439c2c66affSColin Finck VOID
KiAcquirePrcbLock(IN PKPRCB Prcb)440c2c66affSColin Finck KiAcquirePrcbLock(IN PKPRCB Prcb)
441c2c66affSColin Finck {
442c2c66affSColin Finck     /* Make sure we're at a safe level to touch the PRCB lock */
443c2c66affSColin Finck     ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
444c2c66affSColin Finck 
445c2c66affSColin Finck     /* Start acquire loop */
446c2c66affSColin Finck     for (;;)
447c2c66affSColin Finck     {
448c2c66affSColin Finck         /* Acquire the lock and break out if we acquired it first */
449c2c66affSColin Finck         if (!InterlockedExchange((PLONG)&Prcb->PrcbLock, 1)) break;
450c2c66affSColin Finck 
451c2c66affSColin Finck         /* Loop until the other CPU releases it */
452c2c66affSColin Finck         do
453c2c66affSColin Finck         {
454c2c66affSColin Finck             /* Let the CPU know that this is a loop */
455c2c66affSColin Finck             YieldProcessor();
456c2c66affSColin Finck         } while (Prcb->PrcbLock);
457c2c66affSColin Finck     }
458c2c66affSColin Finck }
459c2c66affSColin Finck 
460c2c66affSColin Finck //
461c2c66affSColin Finck // This routine releases the PRCB lock so that other callers can touch
462c2c66affSColin Finck // volatile PRCB data.
463c2c66affSColin Finck //
464c2c66affSColin Finck // Since this is a simple optimized spin-lock, it must be be only acquired
465c2c66affSColin Finck // at dispatcher level or higher!
466c2c66affSColin Finck //
467c2c66affSColin Finck FORCEINLINE
468c2c66affSColin Finck VOID
KiReleasePrcbLock(IN PKPRCB Prcb)469c2c66affSColin Finck KiReleasePrcbLock(IN PKPRCB Prcb)
470c2c66affSColin Finck {
471c2c66affSColin Finck     /* Make sure we are above dispatch and the lock is acquired! */
472c2c66affSColin Finck     ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
473c2c66affSColin Finck     ASSERT(Prcb->PrcbLock != 0);
474c2c66affSColin Finck 
475c2c66affSColin Finck     /* Release it */
476c2c66affSColin Finck     InterlockedAnd((PLONG)&Prcb->PrcbLock, 0);
477c2c66affSColin Finck }
478c2c66affSColin Finck 
479c2c66affSColin Finck //
480c2c66affSColin Finck // This routine acquires the thread lock so that only one caller can touch
481c2c66affSColin Finck // volatile thread data.
482c2c66affSColin Finck //
483c2c66affSColin Finck // Since this is a simple optimized spin-lock, it must be be only acquired
484c2c66affSColin Finck // at dispatcher level or higher!
485c2c66affSColin Finck //
486c2c66affSColin Finck FORCEINLINE
487c2c66affSColin Finck VOID
KiAcquireThreadLock(IN PKTHREAD Thread)488c2c66affSColin Finck KiAcquireThreadLock(IN PKTHREAD Thread)
489c2c66affSColin Finck {
490c2c66affSColin Finck     /* Make sure we're at a safe level to touch the thread lock */
491c2c66affSColin Finck     ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
492c2c66affSColin Finck 
493c2c66affSColin Finck     /* Start acquire loop */
494c2c66affSColin Finck     for (;;)
495c2c66affSColin Finck     {
496c2c66affSColin Finck         /* Acquire the lock and break out if we acquired it first */
497c2c66affSColin Finck         if (!InterlockedExchange((PLONG)&Thread->ThreadLock, 1)) break;
498c2c66affSColin Finck 
499c2c66affSColin Finck         /* Loop until the other CPU releases it */
500c2c66affSColin Finck         do
501c2c66affSColin Finck         {
502c2c66affSColin Finck             /* Let the CPU know that this is a loop */
503c2c66affSColin Finck             YieldProcessor();
504c2c66affSColin Finck         } while (Thread->ThreadLock);
505c2c66affSColin Finck     }
506c2c66affSColin Finck }
507c2c66affSColin Finck 
508c2c66affSColin Finck //
509c2c66affSColin Finck // This routine releases the thread lock so that other callers can touch
510c2c66affSColin Finck // volatile thread data.
511c2c66affSColin Finck //
512c2c66affSColin Finck // Since this is a simple optimized spin-lock, it must be be only acquired
513c2c66affSColin Finck // at dispatcher level or higher!
514c2c66affSColin Finck //
515c2c66affSColin Finck FORCEINLINE
516c2c66affSColin Finck VOID
KiReleaseThreadLock(IN PKTHREAD Thread)517c2c66affSColin Finck KiReleaseThreadLock(IN PKTHREAD Thread)
518c2c66affSColin Finck {
519c2c66affSColin Finck     /* Make sure we are still above dispatch */
520c2c66affSColin Finck     ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
521c2c66affSColin Finck 
522c2c66affSColin Finck     /* Release it */
523c2c66affSColin Finck     InterlockedAnd((PLONG)&Thread->ThreadLock, 0);
524c2c66affSColin Finck }
525c2c66affSColin Finck 
526c2c66affSColin Finck FORCEINLINE
527c2c66affSColin Finck BOOLEAN
KiTryThreadLock(IN PKTHREAD Thread)528c2c66affSColin Finck KiTryThreadLock(IN PKTHREAD Thread)
529c2c66affSColin Finck {
530c2c66affSColin Finck     LONG Value;
531c2c66affSColin Finck 
532c2c66affSColin Finck     /* If the lock isn't acquired, return false */
533c2c66affSColin Finck     if (!Thread->ThreadLock) return FALSE;
534c2c66affSColin Finck 
535c2c66affSColin Finck     /* Otherwise, try to acquire it and check the result */
536c2c66affSColin Finck     Value = 1;
537c2c66affSColin Finck     Value = InterlockedExchange((PLONG)&Thread->ThreadLock, Value);
538c2c66affSColin Finck 
539c2c66affSColin Finck     /* Return the lock state */
540c2c66affSColin Finck     return (Value == 1);
541c2c66affSColin Finck }
542c2c66affSColin Finck 
543c2c66affSColin Finck FORCEINLINE
544c2c66affSColin Finck VOID
KiCheckDeferredReadyList(IN PKPRCB Prcb)545c2c66affSColin Finck KiCheckDeferredReadyList(IN PKPRCB Prcb)
546c2c66affSColin Finck {
547c2c66affSColin Finck     /* Scan the deferred ready lists if required */
548c2c66affSColin Finck     if (Prcb->DeferredReadyListHead.Next) KiProcessDeferredReadyList(Prcb);
549c2c66affSColin Finck }
550c2c66affSColin Finck 
551c2c66affSColin Finck FORCEINLINE
552c2c66affSColin Finck VOID
KiRequestApcInterrupt(IN BOOLEAN NeedApc,IN UCHAR Processor)553c2c66affSColin Finck KiRequestApcInterrupt(IN BOOLEAN NeedApc,
554c2c66affSColin Finck                       IN UCHAR Processor)
555c2c66affSColin Finck {
556c2c66affSColin Finck     /* Check if we need to request APC delivery */
557c2c66affSColin Finck     if (NeedApc)
558c2c66affSColin Finck     {
559c2c66affSColin Finck         /* Check if it's on another CPU */
560c2c66affSColin Finck         if (KeGetCurrentPrcb()->Number != Processor)
561c2c66affSColin Finck         {
562c2c66affSColin Finck             /* Send an IPI to request delivery */
563c2c66affSColin Finck             KiIpiSend(AFFINITY_MASK(Processor), IPI_APC);
564c2c66affSColin Finck         }
565c2c66affSColin Finck         else
566c2c66affSColin Finck         {
567c2c66affSColin Finck             /* Request a software interrupt */
568c2c66affSColin Finck             HalRequestSoftwareInterrupt(APC_LEVEL);
569c2c66affSColin Finck         }
570c2c66affSColin Finck     }
571c2c66affSColin Finck }
572c2c66affSColin Finck 
573c2c66affSColin Finck FORCEINLINE
574c2c66affSColin Finck PKSPIN_LOCK_QUEUE
KiAcquireTimerLock(IN ULONG Hand)575c2c66affSColin Finck KiAcquireTimerLock(IN ULONG Hand)
576c2c66affSColin Finck {
577c2c66affSColin Finck     PKSPIN_LOCK_QUEUE LockQueue;
578c2c66affSColin Finck     ULONG LockIndex;
579c2c66affSColin Finck     ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
580c2c66affSColin Finck 
581c2c66affSColin Finck     /* Get the lock index */
582c2c66affSColin Finck     LockIndex = Hand >> LOCK_QUEUE_TIMER_LOCK_SHIFT;
583c2c66affSColin Finck     LockIndex &= (LOCK_QUEUE_TIMER_TABLE_LOCKS - 1);
584c2c66affSColin Finck 
585c2c66affSColin Finck     /* Now get the lock */
586c2c66affSColin Finck     LockQueue = &KeGetCurrentPrcb()->LockQueue[LockQueueTimerTableLock + LockIndex];
587c2c66affSColin Finck 
588c2c66affSColin Finck     /* Acquire it and return */
589c2c66affSColin Finck     KeAcquireQueuedSpinLockAtDpcLevel(LockQueue);
590c2c66affSColin Finck     return LockQueue;
591c2c66affSColin Finck }
592c2c66affSColin Finck 
593c2c66affSColin Finck FORCEINLINE
594c2c66affSColin Finck VOID
KiReleaseTimerLock(IN PKSPIN_LOCK_QUEUE LockQueue)595c2c66affSColin Finck KiReleaseTimerLock(IN PKSPIN_LOCK_QUEUE LockQueue)
596c2c66affSColin Finck {
597c2c66affSColin Finck     ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
598c2c66affSColin Finck 
599c2c66affSColin Finck     /* Release the lock */
600c2c66affSColin Finck     KeReleaseQueuedSpinLockFromDpcLevel(LockQueue);
601c2c66affSColin Finck }
602c2c66affSColin Finck 
603c2c66affSColin Finck #endif
604c2c66affSColin Finck 
605c2c66affSColin Finck FORCEINLINE
606c2c66affSColin Finck VOID
KiAcquireApcLockRaiseToSynch(IN PKTHREAD Thread,IN PKLOCK_QUEUE_HANDLE Handle)6077523a7b1STimo Kreuzer KiAcquireApcLockRaiseToSynch(IN PKTHREAD Thread,
608c2c66affSColin Finck                  IN PKLOCK_QUEUE_HANDLE Handle)
609c2c66affSColin Finck {
610c2c66affSColin Finck     /* Acquire the lock and raise to synchronization level */
611c2c66affSColin Finck     KeAcquireInStackQueuedSpinLockRaiseToSynch(&Thread->ApcQueueLock, Handle);
612c2c66affSColin Finck }
613c2c66affSColin Finck 
614c2c66affSColin Finck FORCEINLINE
615c2c66affSColin Finck VOID
KiAcquireApcLockAtSynchLevel(IN PKTHREAD Thread,IN PKLOCK_QUEUE_HANDLE Handle)6167523a7b1STimo Kreuzer KiAcquireApcLockAtSynchLevel(IN PKTHREAD Thread,
617c2c66affSColin Finck                            IN PKLOCK_QUEUE_HANDLE Handle)
618c2c66affSColin Finck {
619c2c66affSColin Finck     /* Acquire the lock */
6207523a7b1STimo Kreuzer     ASSERT(KeGetCurrentIrql() >= SYNCH_LEVEL);
621c2c66affSColin Finck     KeAcquireInStackQueuedSpinLockAtDpcLevel(&Thread->ApcQueueLock, Handle);
622c2c66affSColin Finck }
623c2c66affSColin Finck 
624c2c66affSColin Finck FORCEINLINE
625c2c66affSColin Finck VOID
KiAcquireApcLockRaiseToDpc(IN PKTHREAD Thread,IN PKLOCK_QUEUE_HANDLE Handle)6267523a7b1STimo Kreuzer KiAcquireApcLockRaiseToDpc(IN PKTHREAD Thread,
627c2c66affSColin Finck                            IN PKLOCK_QUEUE_HANDLE Handle)
628c2c66affSColin Finck {
629c2c66affSColin Finck     /* Acquire the lock */
630c2c66affSColin Finck     KeAcquireInStackQueuedSpinLock(&Thread->ApcQueueLock, Handle);
631c2c66affSColin Finck }
632c2c66affSColin Finck 
633c2c66affSColin Finck FORCEINLINE
634c2c66affSColin Finck VOID
KiReleaseApcLock(IN PKLOCK_QUEUE_HANDLE Handle)635c2c66affSColin Finck KiReleaseApcLock(IN PKLOCK_QUEUE_HANDLE Handle)
636c2c66affSColin Finck {
637c2c66affSColin Finck     /* Release the lock */
638c2c66affSColin Finck     KeReleaseInStackQueuedSpinLock(Handle);
639c2c66affSColin Finck }
640c2c66affSColin Finck 
641c2c66affSColin Finck FORCEINLINE
642c2c66affSColin Finck VOID
KiReleaseApcLockFromSynchLevel(IN PKLOCK_QUEUE_HANDLE Handle)6437523a7b1STimo Kreuzer KiReleaseApcLockFromSynchLevel(IN PKLOCK_QUEUE_HANDLE Handle)
644c2c66affSColin Finck {
645c2c66affSColin Finck     /* Release the lock */
646c2c66affSColin Finck     KeReleaseInStackQueuedSpinLockFromDpcLevel(Handle);
647c2c66affSColin Finck }
648c2c66affSColin Finck 
649c2c66affSColin Finck FORCEINLINE
650c2c66affSColin Finck VOID
KiAcquireProcessLockRaiseToSynch(IN PKPROCESS Process,IN PKLOCK_QUEUE_HANDLE Handle)6517523a7b1STimo Kreuzer KiAcquireProcessLockRaiseToSynch(IN PKPROCESS Process,
652c2c66affSColin Finck                      IN PKLOCK_QUEUE_HANDLE Handle)
653c2c66affSColin Finck {
654c2c66affSColin Finck     /* Acquire the lock and raise to synchronization level */
655c2c66affSColin Finck     KeAcquireInStackQueuedSpinLockRaiseToSynch(&Process->ProcessLock, Handle);
656c2c66affSColin Finck }
657c2c66affSColin Finck 
658c2c66affSColin Finck FORCEINLINE
659c2c66affSColin Finck VOID
KiReleaseProcessLock(IN PKLOCK_QUEUE_HANDLE Handle)660c2c66affSColin Finck KiReleaseProcessLock(IN PKLOCK_QUEUE_HANDLE Handle)
661c2c66affSColin Finck {
6627523a7b1STimo Kreuzer     /* Release the lock and restore previous IRQL */
663c2c66affSColin Finck     KeReleaseInStackQueuedSpinLock(Handle);
664c2c66affSColin Finck }
665c2c66affSColin Finck 
666c2c66affSColin Finck FORCEINLINE
667c2c66affSColin Finck VOID
KiReleaseProcessLockFromSynchLevel(IN PKLOCK_QUEUE_HANDLE Handle)6687523a7b1STimo Kreuzer KiReleaseProcessLockFromSynchLevel(IN PKLOCK_QUEUE_HANDLE Handle)
669c2c66affSColin Finck {
6707523a7b1STimo Kreuzer     /* Release the lock without lowering IRQL */
671c2c66affSColin Finck     KeReleaseInStackQueuedSpinLockFromDpcLevel(Handle);
672c2c66affSColin Finck }
673c2c66affSColin Finck 
674c2c66affSColin Finck FORCEINLINE
675c2c66affSColin Finck VOID
KiAcquireDeviceQueueLock(IN PKDEVICE_QUEUE DeviceQueue,IN PKLOCK_QUEUE_HANDLE DeviceLock)676c2c66affSColin Finck KiAcquireDeviceQueueLock(IN PKDEVICE_QUEUE DeviceQueue,
677c2c66affSColin Finck                          IN PKLOCK_QUEUE_HANDLE DeviceLock)
678c2c66affSColin Finck {
679c2c66affSColin Finck     /* Check if we were called from a threaded DPC */
680c2c66affSColin Finck     if (KeGetCurrentPrcb()->DpcThreadActive)
681c2c66affSColin Finck     {
682c2c66affSColin Finck         /* Lock the Queue, we're not at DPC level */
683c2c66affSColin Finck         KeAcquireInStackQueuedSpinLock(&DeviceQueue->Lock, DeviceLock);
684c2c66affSColin Finck     }
685c2c66affSColin Finck     else
686c2c66affSColin Finck     {
687c2c66affSColin Finck         /* We must be at DPC level, acquire the lock safely */
688c2c66affSColin Finck         ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
689c2c66affSColin Finck         KeAcquireInStackQueuedSpinLockAtDpcLevel(&DeviceQueue->Lock,
690c2c66affSColin Finck                                                  DeviceLock);
691c2c66affSColin Finck     }
692c2c66affSColin Finck }
693c2c66affSColin Finck 
694c2c66affSColin Finck FORCEINLINE
695c2c66affSColin Finck VOID
KiReleaseDeviceQueueLock(IN PKLOCK_QUEUE_HANDLE DeviceLock)696c2c66affSColin Finck KiReleaseDeviceQueueLock(IN PKLOCK_QUEUE_HANDLE DeviceLock)
697c2c66affSColin Finck {
698c2c66affSColin Finck     /* Check if we were called from a threaded DPC */
699c2c66affSColin Finck     if (KeGetCurrentPrcb()->DpcThreadActive)
700c2c66affSColin Finck     {
701c2c66affSColin Finck         /* Unlock the Queue, we're not at DPC level */
702c2c66affSColin Finck         KeReleaseInStackQueuedSpinLock(DeviceLock);
703c2c66affSColin Finck     }
704c2c66affSColin Finck     else
705c2c66affSColin Finck     {
706c2c66affSColin Finck         /* We must be at DPC level, release the lock safely */
707c2c66affSColin Finck         ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
708c2c66affSColin Finck         KeReleaseInStackQueuedSpinLockFromDpcLevel(DeviceLock);
709c2c66affSColin Finck     }
710c2c66affSColin Finck }
711c2c66affSColin Finck 
712c2c66affSColin Finck //
713c2c66affSColin Finck // Satisfies the wait of a mutant dispatcher object
714c2c66affSColin Finck //
715c2c66affSColin Finck #define KiSatisfyMutantWait(Object, Thread)                                 \
716c2c66affSColin Finck {                                                                           \
717c2c66affSColin Finck     /* Decrease the Signal State */                                         \
718c2c66affSColin Finck     (Object)->Header.SignalState--;                                         \
719c2c66affSColin Finck                                                                             \
720c2c66affSColin Finck     /* Check if it's now non-signaled */                                    \
721c2c66affSColin Finck     if (!(Object)->Header.SignalState)                                      \
722c2c66affSColin Finck     {                                                                       \
723c2c66affSColin Finck         /* Set the Owner Thread */                                          \
724c2c66affSColin Finck         (Object)->OwnerThread = Thread;                                     \
725c2c66affSColin Finck                                                                             \
726c2c66affSColin Finck         /* Disable APCs if needed */                                        \
727c2c66affSColin Finck         Thread->KernelApcDisable = Thread->KernelApcDisable -               \
728c2c66affSColin Finck                                    (Object)->ApcDisable;                    \
729c2c66affSColin Finck                                                                             \
730c2c66affSColin Finck         /* Check if it's abandoned */                                       \
731c2c66affSColin Finck         if ((Object)->Abandoned)                                            \
732c2c66affSColin Finck         {                                                                   \
733c2c66affSColin Finck             /* Unabandon it */                                              \
734c2c66affSColin Finck             (Object)->Abandoned = FALSE;                                    \
735c2c66affSColin Finck                                                                             \
736c2c66affSColin Finck             /* Return Status */                                             \
737c2c66affSColin Finck             Thread->WaitStatus = STATUS_ABANDONED;                          \
738c2c66affSColin Finck         }                                                                   \
739c2c66affSColin Finck                                                                             \
740c2c66affSColin Finck         /* Insert it into the Mutant List */                                \
741c2c66affSColin Finck         InsertHeadList(Thread->MutantListHead.Blink,                        \
742c2c66affSColin Finck                        &(Object)->MutantListEntry);                         \
743c2c66affSColin Finck     }                                                                       \
744c2c66affSColin Finck }
745c2c66affSColin Finck 
746c2c66affSColin Finck //
747c2c66affSColin Finck // Satisfies the wait of any nonmutant dispatcher object
748c2c66affSColin Finck //
749c2c66affSColin Finck #define KiSatisfyNonMutantWait(Object)                                      \
750c2c66affSColin Finck {                                                                           \
751c2c66affSColin Finck     if (((Object)->Header.Type & TIMER_OR_EVENT_TYPE) ==                    \
752c2c66affSColin Finck              EventSynchronizationObject)                                    \
753c2c66affSColin Finck     {                                                                       \
754c2c66affSColin Finck         /* Synchronization Timers and Events just get un-signaled */        \
755c2c66affSColin Finck         (Object)->Header.SignalState = 0;                                   \
756c2c66affSColin Finck     }                                                                       \
757c2c66affSColin Finck     else if ((Object)->Header.Type == SemaphoreObject)                      \
758c2c66affSColin Finck     {                                                                       \
759c2c66affSColin Finck         /* These ones can have multiple states, so we only decrease it */   \
760c2c66affSColin Finck         (Object)->Header.SignalState--;                                     \
761c2c66affSColin Finck     }                                                                       \
762c2c66affSColin Finck }
763c2c66affSColin Finck 
764c2c66affSColin Finck //
765c2c66affSColin Finck // Satisfies the wait of any dispatcher object
766c2c66affSColin Finck //
767c2c66affSColin Finck #define KiSatisfyObjectWait(Object, Thread)                                 \
768c2c66affSColin Finck {                                                                           \
769c2c66affSColin Finck     /* Special case for Mutants */                                          \
770c2c66affSColin Finck     if ((Object)->Header.Type == MutantObject)                              \
771c2c66affSColin Finck     {                                                                       \
772c2c66affSColin Finck         KiSatisfyMutantWait((Object), (Thread));                            \
773c2c66affSColin Finck     }                                                                       \
774c2c66affSColin Finck     else                                                                    \
775c2c66affSColin Finck     {                                                                       \
776c2c66affSColin Finck         KiSatisfyNonMutantWait(Object);                                     \
777c2c66affSColin Finck     }                                                                       \
778c2c66affSColin Finck }
779c2c66affSColin Finck 
780c2c66affSColin Finck //
781c2c66affSColin Finck // Recalculates the due time
782c2c66affSColin Finck //
783c2c66affSColin Finck FORCEINLINE
784c2c66affSColin Finck PLARGE_INTEGER
KiRecalculateDueTime(IN PLARGE_INTEGER OriginalDueTime,IN PLARGE_INTEGER DueTime,IN OUT PLARGE_INTEGER NewDueTime)785c2c66affSColin Finck KiRecalculateDueTime(IN PLARGE_INTEGER OriginalDueTime,
786c2c66affSColin Finck                      IN PLARGE_INTEGER DueTime,
787c2c66affSColin Finck                      IN OUT PLARGE_INTEGER NewDueTime)
788c2c66affSColin Finck {
789c2c66affSColin Finck     /* Don't do anything for absolute waits */
790c2c66affSColin Finck     if (OriginalDueTime->QuadPart >= 0) return OriginalDueTime;
791c2c66affSColin Finck 
792c2c66affSColin Finck     /* Otherwise, query the interrupt time and recalculate */
793c2c66affSColin Finck     NewDueTime->QuadPart = KeQueryInterruptTime();
794c2c66affSColin Finck     NewDueTime->QuadPart -= DueTime->QuadPart;
795c2c66affSColin Finck     return NewDueTime;
796c2c66affSColin Finck }
797c2c66affSColin Finck 
798c2c66affSColin Finck //
799c2c66affSColin Finck // Determines whether a thread should be added to the wait list
800c2c66affSColin Finck //
801c2c66affSColin Finck FORCEINLINE
802c2c66affSColin Finck BOOLEAN
KiCheckThreadStackSwap(IN PKTHREAD Thread,IN KPROCESSOR_MODE WaitMode)803c2c66affSColin Finck KiCheckThreadStackSwap(IN PKTHREAD Thread,
804c2c66affSColin Finck                        IN KPROCESSOR_MODE WaitMode)
805c2c66affSColin Finck {
806c2c66affSColin Finck     /* Check the required conditions */
807c2c66affSColin Finck     if ((WaitMode != KernelMode) &&
808c2c66affSColin Finck         (Thread->EnableStackSwap) &&
809c2c66affSColin Finck         (Thread->Priority >= (LOW_REALTIME_PRIORITY + 9)))
810c2c66affSColin Finck     {
811c2c66affSColin Finck         /* We are go for swap */
812c2c66affSColin Finck         return TRUE;
813c2c66affSColin Finck     }
814c2c66affSColin Finck     else
815c2c66affSColin Finck     {
816c2c66affSColin Finck         /* Don't swap the thread */
817c2c66affSColin Finck         return FALSE;
818c2c66affSColin Finck     }
819c2c66affSColin Finck }
820c2c66affSColin Finck 
821c2c66affSColin Finck //
822c2c66affSColin Finck // Adds a thread to the wait list
823c2c66affSColin Finck //
824c2c66affSColin Finck #define KiAddThreadToWaitList(Thread, Swappable)                            \
825c2c66affSColin Finck {                                                                           \
826c2c66affSColin Finck     /* Make sure it's swappable */                                          \
827c2c66affSColin Finck     if (Swappable)                                                          \
828c2c66affSColin Finck     {                                                                       \
829c2c66affSColin Finck         /* Insert it into the PRCB's List */                                \
830c2c66affSColin Finck         InsertTailList(&KeGetCurrentPrcb()->WaitListHead,                   \
831c2c66affSColin Finck                        &Thread->WaitListEntry);                             \
832c2c66affSColin Finck     }                                                                       \
833c2c66affSColin Finck }
834c2c66affSColin Finck 
835c2c66affSColin Finck //
836c2c66affSColin Finck // Checks if a wait in progress should be interrupted by APCs or an alertable
837c2c66affSColin Finck // state.
838c2c66affSColin Finck //
839c2c66affSColin Finck FORCEINLINE
840c2c66affSColin Finck NTSTATUS
KiCheckAlertability(IN PKTHREAD Thread,IN BOOLEAN Alertable,IN KPROCESSOR_MODE WaitMode)841c2c66affSColin Finck KiCheckAlertability(IN PKTHREAD Thread,
842c2c66affSColin Finck                     IN BOOLEAN Alertable,
843c2c66affSColin Finck                     IN KPROCESSOR_MODE WaitMode)
844c2c66affSColin Finck {
845c2c66affSColin Finck     /* Check if the wait is alertable */
846c2c66affSColin Finck     if (Alertable)
847c2c66affSColin Finck     {
848c2c66affSColin Finck         /* It is, first check if the thread is alerted in this mode */
849c2c66affSColin Finck         if (Thread->Alerted[WaitMode])
850c2c66affSColin Finck         {
851c2c66affSColin Finck             /* It is, so bail out of the wait */
852c2c66affSColin Finck             Thread->Alerted[WaitMode] = FALSE;
853c2c66affSColin Finck             return STATUS_ALERTED;
854c2c66affSColin Finck         }
855c2c66affSColin Finck         else if ((WaitMode != KernelMode) &&
856c2c66affSColin Finck                 (!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode])))
857c2c66affSColin Finck         {
858c2c66affSColin Finck             /* It's isn't, but this is a user wait with queued user APCs */
859c2c66affSColin Finck             Thread->ApcState.UserApcPending = TRUE;
860c2c66affSColin Finck             return STATUS_USER_APC;
861c2c66affSColin Finck         }
862c2c66affSColin Finck         else if (Thread->Alerted[KernelMode])
863c2c66affSColin Finck         {
864c2c66affSColin Finck             /* It isn't that either, but we're alered in kernel mode */
865c2c66affSColin Finck             Thread->Alerted[KernelMode] = FALSE;
866c2c66affSColin Finck             return STATUS_ALERTED;
867c2c66affSColin Finck         }
868c2c66affSColin Finck     }
869c2c66affSColin Finck     else if ((WaitMode != KernelMode) && (Thread->ApcState.UserApcPending))
870c2c66affSColin Finck     {
871c2c66affSColin Finck         /* Not alertable, but this is a user wait with pending user APCs */
872c2c66affSColin Finck         return STATUS_USER_APC;
873c2c66affSColin Finck     }
874c2c66affSColin Finck 
875c2c66affSColin Finck     /* Otherwise, we're fine */
876c2c66affSColin Finck     return STATUS_WAIT_0;
877c2c66affSColin Finck }
878c2c66affSColin Finck 
879c2c66affSColin Finck FORCEINLINE
880c2c66affSColin Finck ULONG
KiComputeTimerTableIndex(IN ULONGLONG DueTime)881c2c66affSColin Finck KiComputeTimerTableIndex(IN ULONGLONG DueTime)
882c2c66affSColin Finck {
883c2c66affSColin Finck     return (DueTime / KeMaximumIncrement) & (TIMER_TABLE_SIZE - 1);
884c2c66affSColin Finck }
885c2c66affSColin Finck 
886c2c66affSColin Finck //
887c2c66affSColin Finck // Called from KiCompleteTimer, KiInsertTreeTimer, KeSetSystemTime
888c2c66affSColin Finck // to remove timer entries
889c2c66affSColin Finck // See Windows HPI blog for more information.
890c2c66affSColin Finck FORCEINLINE
891c2c66affSColin Finck VOID
KiRemoveEntryTimer(IN PKTIMER Timer)892c2c66affSColin Finck KiRemoveEntryTimer(IN PKTIMER Timer)
893c2c66affSColin Finck {
894c2c66affSColin Finck     ULONG Hand;
895c2c66affSColin Finck     PKTIMER_TABLE_ENTRY TableEntry;
896c2c66affSColin Finck 
897c2c66affSColin Finck     /* Remove the timer from the timer list and check if it's empty */
898c2c66affSColin Finck     Hand = Timer->Header.Hand;
899c2c66affSColin Finck     if (RemoveEntryList(&Timer->TimerListEntry))
900c2c66affSColin Finck     {
901c2c66affSColin Finck         /* Get the respective timer table entry */
902c2c66affSColin Finck         TableEntry = &KiTimerTableListHead[Hand];
903c2c66affSColin Finck         if (&TableEntry->Entry == TableEntry->Entry.Flink)
904c2c66affSColin Finck         {
905c2c66affSColin Finck             /* Set the entry to an infinite absolute time */
906c2c66affSColin Finck             TableEntry->Time.HighPart = 0xFFFFFFFF;
907c2c66affSColin Finck         }
908c2c66affSColin Finck     }
909c2c66affSColin Finck 
910c2c66affSColin Finck     /* Clear the list entries on dbg builds so we can tell the timer is gone */
911c2c66affSColin Finck #if DBG
912c2c66affSColin Finck     Timer->TimerListEntry.Flink = NULL;
913c2c66affSColin Finck     Timer->TimerListEntry.Blink = NULL;
914c2c66affSColin Finck #endif
915c2c66affSColin Finck }
916c2c66affSColin Finck 
917c2c66affSColin Finck //
918c2c66affSColin Finck // Called by Wait and Queue code to insert a timer for dispatching.
919c2c66affSColin Finck // Also called by KeSetTimerEx to insert a timer from the caller.
920c2c66affSColin Finck //
921c2c66affSColin Finck FORCEINLINE
922c2c66affSColin Finck VOID
KxInsertTimer(IN PKTIMER Timer,IN ULONG Hand)923c2c66affSColin Finck KxInsertTimer(IN PKTIMER Timer,
924c2c66affSColin Finck               IN ULONG Hand)
925c2c66affSColin Finck {
926c2c66affSColin Finck     PKSPIN_LOCK_QUEUE LockQueue;
9277523a7b1STimo Kreuzer     ASSERT(KeGetCurrentIrql() >= SYNCH_LEVEL);
928c2c66affSColin Finck 
929c2c66affSColin Finck     /* Acquire the lock and release the dispatcher lock */
930c2c66affSColin Finck     LockQueue = KiAcquireTimerLock(Hand);
9317523a7b1STimo Kreuzer     KiReleaseDispatcherLockFromSynchLevel();
932c2c66affSColin Finck 
933c2c66affSColin Finck     /* Try to insert the timer */
934c2c66affSColin Finck     if (KiInsertTimerTable(Timer, Hand))
935c2c66affSColin Finck     {
936c2c66affSColin Finck         /* Complete it */
937c2c66affSColin Finck         KiCompleteTimer(Timer, LockQueue);
938c2c66affSColin Finck     }
939c2c66affSColin Finck     else
940c2c66affSColin Finck     {
941c2c66affSColin Finck         /* Do nothing, just release the lock */
942c2c66affSColin Finck         KiReleaseTimerLock(LockQueue);
943c2c66affSColin Finck     }
944c2c66affSColin Finck }
945c2c66affSColin Finck 
946c2c66affSColin Finck //
947c2c66affSColin Finck // Called by KeSetTimerEx and KiInsertTreeTimer to calculate Due Time
948c2c66affSColin Finck // See the Windows HPI Blog for more information
949c2c66affSColin Finck //
950c2c66affSColin Finck FORCEINLINE
951c2c66affSColin Finck BOOLEAN
KiComputeDueTime(IN PKTIMER Timer,IN LARGE_INTEGER DueTime,OUT PULONG Hand)952c2c66affSColin Finck KiComputeDueTime(IN PKTIMER Timer,
953c2c66affSColin Finck                  IN LARGE_INTEGER DueTime,
954c2c66affSColin Finck                  OUT PULONG Hand)
955c2c66affSColin Finck {
956c2c66affSColin Finck     LARGE_INTEGER InterruptTime, SystemTime, DifferenceTime;
957c2c66affSColin Finck 
958c2c66affSColin Finck     /* Convert to relative time if needed */
959c2c66affSColin Finck     Timer->Header.Absolute = FALSE;
960c2c66affSColin Finck     if (DueTime.HighPart >= 0)
961c2c66affSColin Finck     {
962c2c66affSColin Finck         /* Get System Time */
963c2c66affSColin Finck         KeQuerySystemTime(&SystemTime);
964c2c66affSColin Finck 
965c2c66affSColin Finck         /* Do the conversion */
966c2c66affSColin Finck         DifferenceTime.QuadPart = SystemTime.QuadPart - DueTime.QuadPart;
967c2c66affSColin Finck 
968c2c66affSColin Finck         /* Make sure it hasn't already expired */
969c2c66affSColin Finck         Timer->Header.Absolute = TRUE;
970c2c66affSColin Finck         if (DifferenceTime.HighPart >= 0)
971c2c66affSColin Finck         {
972c2c66affSColin Finck             /* Cancel everything */
973c2c66affSColin Finck             Timer->Header.SignalState = TRUE;
974c2c66affSColin Finck             Timer->Header.Hand = 0;
975c2c66affSColin Finck             Timer->DueTime.QuadPart = 0;
976c2c66affSColin Finck             *Hand = 0;
977c2c66affSColin Finck             return FALSE;
978c2c66affSColin Finck         }
979c2c66affSColin Finck 
980c2c66affSColin Finck         /* Set the time as Absolute */
981c2c66affSColin Finck         DueTime = DifferenceTime;
982c2c66affSColin Finck     }
983c2c66affSColin Finck 
984c2c66affSColin Finck     /* Get the Interrupt Time */
985c2c66affSColin Finck     InterruptTime.QuadPart = KeQueryInterruptTime();
986c2c66affSColin Finck 
987c2c66affSColin Finck     /* Recalculate due time */
988c2c66affSColin Finck     Timer->DueTime.QuadPart = InterruptTime.QuadPart - DueTime.QuadPart;
989c2c66affSColin Finck 
990c2c66affSColin Finck     /* Get the handle */
991c2c66affSColin Finck     *Hand = KiComputeTimerTableIndex(Timer->DueTime.QuadPart);
992c2c66affSColin Finck     Timer->Header.Hand = (UCHAR)*Hand;
993c2c66affSColin Finck     Timer->Header.Inserted = TRUE;
994c2c66affSColin Finck     return TRUE;
995c2c66affSColin Finck }
996c2c66affSColin Finck 
997c2c66affSColin Finck //
998c2c66affSColin Finck // Called from Unlink and Queue Insert Code.
999c2c66affSColin Finck // Also called by timer code when canceling an inserted timer.
1000c2c66affSColin Finck // Removes a timer from it's tree.
1001c2c66affSColin Finck //
1002c2c66affSColin Finck FORCEINLINE
1003c2c66affSColin Finck VOID
KxRemoveTreeTimer(IN PKTIMER Timer)1004c2c66affSColin Finck KxRemoveTreeTimer(IN PKTIMER Timer)
1005c2c66affSColin Finck {
1006c2c66affSColin Finck     ULONG Hand = Timer->Header.Hand;
1007c2c66affSColin Finck     PKSPIN_LOCK_QUEUE LockQueue;
1008c2c66affSColin Finck     PKTIMER_TABLE_ENTRY TimerEntry;
1009c2c66affSColin Finck 
1010c2c66affSColin Finck     /* Acquire timer lock */
1011c2c66affSColin Finck     LockQueue = KiAcquireTimerLock(Hand);
1012c2c66affSColin Finck 
1013c2c66affSColin Finck     /* Set the timer as non-inserted */
1014c2c66affSColin Finck     Timer->Header.Inserted = FALSE;
1015c2c66affSColin Finck 
1016c2c66affSColin Finck     /* Remove it from the timer list */
1017c2c66affSColin Finck     if (RemoveEntryList(&Timer->TimerListEntry))
1018c2c66affSColin Finck     {
1019c2c66affSColin Finck         /* Get the entry and check if it's empty */
1020c2c66affSColin Finck         TimerEntry = &KiTimerTableListHead[Hand];
1021c2c66affSColin Finck         if (IsListEmpty(&TimerEntry->Entry))
1022c2c66affSColin Finck         {
1023c2c66affSColin Finck             /* Clear the time then */
1024c2c66affSColin Finck             TimerEntry->Time.HighPart = 0xFFFFFFFF;
1025c2c66affSColin Finck         }
1026c2c66affSColin Finck     }
1027c2c66affSColin Finck 
1028c2c66affSColin Finck     /* Release the timer lock */
1029c2c66affSColin Finck     KiReleaseTimerLock(LockQueue);
1030c2c66affSColin Finck }
1031c2c66affSColin Finck 
1032c2c66affSColin Finck FORCEINLINE
1033c2c66affSColin Finck VOID
KxSetTimerForThreadWait(IN PKTIMER Timer,IN LARGE_INTEGER Interval,OUT PULONG Hand)1034c2c66affSColin Finck KxSetTimerForThreadWait(IN PKTIMER Timer,
1035c2c66affSColin Finck                         IN LARGE_INTEGER Interval,
1036c2c66affSColin Finck                         OUT PULONG Hand)
1037c2c66affSColin Finck {
1038c2c66affSColin Finck     ULONGLONG DueTime;
1039c2c66affSColin Finck     LARGE_INTEGER InterruptTime, SystemTime, TimeDifference;
1040c2c66affSColin Finck 
1041c2c66affSColin Finck     /* Check the timer's interval to see if it's absolute */
1042c2c66affSColin Finck     Timer->Header.Absolute = FALSE;
1043c2c66affSColin Finck     if (Interval.HighPart >= 0)
1044c2c66affSColin Finck     {
1045c2c66affSColin Finck         /* Get the system time and calculate the relative time */
1046c2c66affSColin Finck         KeQuerySystemTime(&SystemTime);
1047c2c66affSColin Finck         TimeDifference.QuadPart = SystemTime.QuadPart - Interval.QuadPart;
1048c2c66affSColin Finck         Timer->Header.Absolute = TRUE;
1049c2c66affSColin Finck 
1050c2c66affSColin Finck         /* Check if we've already expired */
1051c2c66affSColin Finck         if (TimeDifference.HighPart >= 0)
1052c2c66affSColin Finck         {
1053c2c66affSColin Finck             /* Reset everything */
1054c2c66affSColin Finck             Timer->DueTime.QuadPart = 0;
1055c2c66affSColin Finck             *Hand = 0;
1056c2c66affSColin Finck             Timer->Header.Hand = 0;
1057c2c66affSColin Finck             return;
1058c2c66affSColin Finck         }
1059c2c66affSColin Finck         else
1060c2c66affSColin Finck         {
1061c2c66affSColin Finck             /* Update the interval */
1062c2c66affSColin Finck             Interval = TimeDifference;
1063c2c66affSColin Finck         }
1064c2c66affSColin Finck     }
1065c2c66affSColin Finck 
1066c2c66affSColin Finck     /* Calculate the due time */
1067c2c66affSColin Finck     InterruptTime.QuadPart = KeQueryInterruptTime();
1068c2c66affSColin Finck     DueTime = InterruptTime.QuadPart - Interval.QuadPart;
1069c2c66affSColin Finck     Timer->DueTime.QuadPart = DueTime;
1070c2c66affSColin Finck 
1071c2c66affSColin Finck     /* Calculate the timer handle */
1072c2c66affSColin Finck     *Hand = KiComputeTimerTableIndex(DueTime);
1073c2c66affSColin Finck     Timer->Header.Hand = (UCHAR)*Hand;
1074c2c66affSColin Finck }
1075c2c66affSColin Finck 
1076c2c66affSColin Finck #define KxDelayThreadWait()                                                 \
1077c2c66affSColin Finck                                                                             \
1078c2c66affSColin Finck     /* Setup the Wait Block */                                              \
1079c2c66affSColin Finck     Thread->WaitBlockList = TimerBlock;                                     \
1080c2c66affSColin Finck                                                                             \
1081c2c66affSColin Finck     /* Setup the timer */                                                   \
1082c2c66affSColin Finck     KxSetTimerForThreadWait(Timer, *Interval, &Hand);                       \
1083c2c66affSColin Finck                                                                             \
1084c2c66affSColin Finck     /* Save the due time for the caller */                                  \
1085c2c66affSColin Finck     DueTime.QuadPart = Timer->DueTime.QuadPart;                             \
1086c2c66affSColin Finck                                                                             \
1087c2c66affSColin Finck     /* Link the timer to this Wait Block */                                 \
1088c2c66affSColin Finck     TimerBlock->NextWaitBlock = TimerBlock;                                 \
1089c2c66affSColin Finck     Timer->Header.WaitListHead.Flink = &TimerBlock->WaitListEntry;          \
1090c2c66affSColin Finck     Timer->Header.WaitListHead.Blink = &TimerBlock->WaitListEntry;          \
1091c2c66affSColin Finck                                                                             \
1092c2c66affSColin Finck     /* Clear wait status */                                                 \
1093c2c66affSColin Finck     Thread->WaitStatus = STATUS_SUCCESS;                                    \
1094c2c66affSColin Finck                                                                             \
1095c2c66affSColin Finck     /* Setup wait fields */                                                 \
1096c2c66affSColin Finck     Thread->Alertable = Alertable;                                          \
1097c2c66affSColin Finck     Thread->WaitReason = DelayExecution;                                    \
1098c2c66affSColin Finck     Thread->WaitMode = WaitMode;                                            \
1099c2c66affSColin Finck                                                                             \
1100c2c66affSColin Finck     /* Check if we can swap the thread's stack */                           \
1101c2c66affSColin Finck     Thread->WaitListEntry.Flink = NULL;                                     \
1102c2c66affSColin Finck     Swappable = KiCheckThreadStackSwap(Thread, WaitMode);                   \
1103c2c66affSColin Finck                                                                             \
1104c2c66affSColin Finck     /* Set the wait time */                                                 \
1105c2c66affSColin Finck     Thread->WaitTime = KeTickCount.LowPart;
1106c2c66affSColin Finck 
1107c2c66affSColin Finck #define KxMultiThreadWait()                                                 \
1108c2c66affSColin Finck     /* Link wait block array to the thread */                               \
1109c2c66affSColin Finck     Thread->WaitBlockList = WaitBlockArray;                                 \
1110c2c66affSColin Finck                                                                             \
1111c2c66affSColin Finck     /* Reset the index */                                                   \
1112c2c66affSColin Finck     Index = 0;                                                              \
1113c2c66affSColin Finck                                                                             \
1114c2c66affSColin Finck     /* Loop wait blocks */                                                  \
1115c2c66affSColin Finck     do                                                                      \
1116c2c66affSColin Finck     {                                                                       \
1117c2c66affSColin Finck         /* Fill out the wait block */                                       \
1118c2c66affSColin Finck         WaitBlock = &WaitBlockArray[Index];                                 \
1119c2c66affSColin Finck         WaitBlock->Object = Object[Index];                                  \
1120c2c66affSColin Finck         WaitBlock->WaitKey = (USHORT)Index;                                 \
1121c2c66affSColin Finck         WaitBlock->WaitType = WaitType;                                     \
1122c2c66affSColin Finck         WaitBlock->Thread = Thread;                                         \
1123c2c66affSColin Finck                                                                             \
1124c2c66affSColin Finck         /* Link to next block */                                            \
1125c2c66affSColin Finck         WaitBlock->NextWaitBlock = &WaitBlockArray[Index + 1];              \
1126c2c66affSColin Finck         Index++;                                                            \
1127c2c66affSColin Finck     } while (Index < Count);                                                \
1128c2c66affSColin Finck                                                                             \
1129c2c66affSColin Finck     /* Link the last block */                                               \
1130c2c66affSColin Finck     WaitBlock->NextWaitBlock = WaitBlockArray;                              \
1131c2c66affSColin Finck                                                                             \
1132c2c66affSColin Finck     /* Set default wait status */                                           \
1133c2c66affSColin Finck     Thread->WaitStatus = STATUS_WAIT_0;                                     \
1134c2c66affSColin Finck                                                                             \
1135c2c66affSColin Finck     /* Check if we have a timer */                                          \
1136c2c66affSColin Finck     if (Timeout)                                                            \
1137c2c66affSColin Finck     {                                                                       \
1138c2c66affSColin Finck         /* Link to the block */                                             \
1139c2c66affSColin Finck         TimerBlock->NextWaitBlock = WaitBlockArray;                         \
1140c2c66affSColin Finck                                                                             \
1141c2c66affSColin Finck         /* Setup the timer */                                               \
1142c2c66affSColin Finck         KxSetTimerForThreadWait(Timer, *Timeout, &Hand);                    \
1143c2c66affSColin Finck                                                                             \
1144c2c66affSColin Finck         /* Save the due time for the caller */                              \
1145c2c66affSColin Finck         DueTime.QuadPart = Timer->DueTime.QuadPart;                         \
1146c2c66affSColin Finck                                                                             \
1147c2c66affSColin Finck         /* Initialize the list */                                           \
1148c2c66affSColin Finck         InitializeListHead(&Timer->Header.WaitListHead);                    \
1149c2c66affSColin Finck     }                                                                       \
1150c2c66affSColin Finck                                                                             \
1151c2c66affSColin Finck     /* Set wait settings */                                                 \
1152c2c66affSColin Finck     Thread->Alertable = Alertable;                                          \
1153c2c66affSColin Finck     Thread->WaitMode = WaitMode;                                            \
1154c2c66affSColin Finck     Thread->WaitReason = WaitReason;                                        \
1155c2c66affSColin Finck                                                                             \
1156c2c66affSColin Finck     /* Check if we can swap the thread's stack */                           \
1157c2c66affSColin Finck     Thread->WaitListEntry.Flink = NULL;                                     \
1158c2c66affSColin Finck     Swappable = KiCheckThreadStackSwap(Thread, WaitMode);                   \
1159c2c66affSColin Finck                                                                             \
1160c2c66affSColin Finck     /* Set the wait time */                                                 \
1161c2c66affSColin Finck     Thread->WaitTime = KeTickCount.LowPart;
1162c2c66affSColin Finck 
1163c2c66affSColin Finck #define KxSingleThreadWait()                                                \
1164c2c66affSColin Finck     /* Setup the Wait Block */                                              \
1165c2c66affSColin Finck     Thread->WaitBlockList = WaitBlock;                                      \
1166c2c66affSColin Finck     WaitBlock->WaitKey = STATUS_SUCCESS;                                    \
1167c2c66affSColin Finck     WaitBlock->Object = Object;                                             \
1168c2c66affSColin Finck     WaitBlock->WaitType = WaitAny;                                          \
1169c2c66affSColin Finck                                                                             \
1170c2c66affSColin Finck     /* Clear wait status */                                                 \
1171c2c66affSColin Finck     Thread->WaitStatus = STATUS_SUCCESS;                                    \
1172c2c66affSColin Finck                                                                             \
1173c2c66affSColin Finck     /* Check if we have a timer */                                          \
1174c2c66affSColin Finck     if (Timeout)                                                            \
1175c2c66affSColin Finck     {                                                                       \
1176c2c66affSColin Finck         /* Setup the timer */                                               \
1177c2c66affSColin Finck         KxSetTimerForThreadWait(Timer, *Timeout, &Hand);                    \
1178c2c66affSColin Finck                                                                             \
1179c2c66affSColin Finck         /* Save the due time for the caller */                              \
1180c2c66affSColin Finck         DueTime.QuadPart = Timer->DueTime.QuadPart;                         \
1181c2c66affSColin Finck                                                                             \
1182c2c66affSColin Finck         /* Pointer to timer block */                                        \
1183c2c66affSColin Finck         WaitBlock->NextWaitBlock = TimerBlock;                              \
1184c2c66affSColin Finck         TimerBlock->NextWaitBlock = WaitBlock;                              \
1185c2c66affSColin Finck                                                                             \
1186c2c66affSColin Finck         /* Link the timer to this Wait Block */                             \
1187c2c66affSColin Finck         Timer->Header.WaitListHead.Flink = &TimerBlock->WaitListEntry;      \
1188c2c66affSColin Finck         Timer->Header.WaitListHead.Blink = &TimerBlock->WaitListEntry;      \
1189c2c66affSColin Finck     }                                                                       \
1190c2c66affSColin Finck     else                                                                    \
1191c2c66affSColin Finck     {                                                                       \
1192c2c66affSColin Finck         /* No timer block, just ourselves */                                \
1193c2c66affSColin Finck         WaitBlock->NextWaitBlock = WaitBlock;                               \
1194c2c66affSColin Finck     }                                                                       \
1195c2c66affSColin Finck                                                                             \
1196c2c66affSColin Finck     /* Set wait settings */                                                 \
1197c2c66affSColin Finck     Thread->Alertable = Alertable;                                          \
1198c2c66affSColin Finck     Thread->WaitMode = WaitMode;                                            \
1199c2c66affSColin Finck     Thread->WaitReason = WaitReason;                                        \
1200c2c66affSColin Finck                                                                             \
1201c2c66affSColin Finck     /* Check if we can swap the thread's stack */                           \
1202c2c66affSColin Finck     Thread->WaitListEntry.Flink = NULL;                                     \
1203c2c66affSColin Finck     Swappable = KiCheckThreadStackSwap(Thread, WaitMode);                   \
1204c2c66affSColin Finck                                                                             \
1205c2c66affSColin Finck     /* Set the wait time */                                                 \
1206c2c66affSColin Finck     Thread->WaitTime = KeTickCount.LowPart;
1207c2c66affSColin Finck 
1208c2c66affSColin Finck #define KxQueueThreadWait()                                                 \
1209c2c66affSColin Finck     /* Setup the Wait Block */                                              \
1210c2c66affSColin Finck     Thread->WaitBlockList = WaitBlock;                                      \
1211c2c66affSColin Finck     WaitBlock->WaitKey = STATUS_SUCCESS;                                    \
1212c2c66affSColin Finck     WaitBlock->Object = Queue;                                              \
1213c2c66affSColin Finck     WaitBlock->WaitType = WaitAny;                                          \
1214c2c66affSColin Finck     WaitBlock->Thread = Thread;                                             \
1215c2c66affSColin Finck                                                                             \
1216c2c66affSColin Finck     /* Clear wait status */                                                 \
1217c2c66affSColin Finck     Thread->WaitStatus = STATUS_SUCCESS;                                    \
1218c2c66affSColin Finck                                                                             \
1219c2c66affSColin Finck     /* Check if we have a timer */                                          \
1220c2c66affSColin Finck     if (Timeout)                                                            \
1221c2c66affSColin Finck     {                                                                       \
1222c2c66affSColin Finck         /* Setup the timer */                                               \
1223c2c66affSColin Finck         KxSetTimerForThreadWait(Timer, *Timeout, &Hand);                    \
1224c2c66affSColin Finck                                                                             \
1225c2c66affSColin Finck         /* Save the due time for the caller */                              \
1226c2c66affSColin Finck         DueTime.QuadPart = Timer->DueTime.QuadPart;                         \
1227c2c66affSColin Finck                                                                             \
1228c2c66affSColin Finck         /* Pointer to timer block */                                        \
1229c2c66affSColin Finck         WaitBlock->NextWaitBlock = TimerBlock;                              \
1230c2c66affSColin Finck         TimerBlock->NextWaitBlock = WaitBlock;                              \
1231c2c66affSColin Finck                                                                             \
1232c2c66affSColin Finck         /* Link the timer to this Wait Block */                             \
1233c2c66affSColin Finck         Timer->Header.WaitListHead.Flink = &TimerBlock->WaitListEntry;      \
1234c2c66affSColin Finck         Timer->Header.WaitListHead.Blink = &TimerBlock->WaitListEntry;      \
1235c2c66affSColin Finck     }                                                                       \
1236c2c66affSColin Finck     else                                                                    \
1237c2c66affSColin Finck     {                                                                       \
1238c2c66affSColin Finck         /* No timer block, just ourselves */                                \
1239c2c66affSColin Finck         WaitBlock->NextWaitBlock = WaitBlock;                               \
1240c2c66affSColin Finck     }                                                                       \
1241c2c66affSColin Finck                                                                             \
1242c2c66affSColin Finck     /* Set wait settings */                                                 \
1243c2c66affSColin Finck     Thread->Alertable = FALSE;                                              \
1244c2c66affSColin Finck     Thread->WaitMode = WaitMode;                                            \
1245c2c66affSColin Finck     Thread->WaitReason = WrQueue;                                           \
1246c2c66affSColin Finck                                                                             \
1247c2c66affSColin Finck     /* Check if we can swap the thread's stack */                           \
1248c2c66affSColin Finck     Thread->WaitListEntry.Flink = NULL;                                     \
1249c2c66affSColin Finck     Swappable = KiCheckThreadStackSwap(Thread, WaitMode);                   \
1250c2c66affSColin Finck                                                                             \
1251c2c66affSColin Finck     /* Set the wait time */                                                 \
1252c2c66affSColin Finck     Thread->WaitTime = KeTickCount.LowPart;
1253c2c66affSColin Finck 
1254c2c66affSColin Finck //
1255c2c66affSColin Finck // Unwaits a Thread
1256c2c66affSColin Finck //
1257c2c66affSColin Finck FORCEINLINE
1258c2c66affSColin Finck VOID
KxUnwaitThread(IN DISPATCHER_HEADER * Object,IN KPRIORITY Increment)1259c2c66affSColin Finck KxUnwaitThread(IN DISPATCHER_HEADER *Object,
1260c2c66affSColin Finck                IN KPRIORITY Increment)
1261c2c66affSColin Finck {
1262c2c66affSColin Finck     PLIST_ENTRY WaitEntry, WaitList;
1263c2c66affSColin Finck     PKWAIT_BLOCK WaitBlock;
1264c2c66affSColin Finck     PKTHREAD WaitThread;
1265c2c66affSColin Finck     ULONG WaitKey;
1266c2c66affSColin Finck 
1267c2c66affSColin Finck     /* Loop the Wait Entries */
1268c2c66affSColin Finck     WaitList = &Object->WaitListHead;
1269c2c66affSColin Finck     ASSERT(IsListEmpty(&Object->WaitListHead) == FALSE);
1270c2c66affSColin Finck     WaitEntry = WaitList->Flink;
1271c2c66affSColin Finck     do
1272c2c66affSColin Finck     {
1273c2c66affSColin Finck         /* Get the current wait block */
1274c2c66affSColin Finck         WaitBlock = CONTAINING_RECORD(WaitEntry, KWAIT_BLOCK, WaitListEntry);
1275c2c66affSColin Finck 
1276c2c66affSColin Finck         /* Get the waiting thread */
1277c2c66affSColin Finck         WaitThread = WaitBlock->Thread;
1278c2c66affSColin Finck 
1279c2c66affSColin Finck         /* Check the current Wait Mode */
1280c2c66affSColin Finck         if (WaitBlock->WaitType == WaitAny)
1281c2c66affSColin Finck         {
1282c2c66affSColin Finck             /* Use the actual wait key */
1283c2c66affSColin Finck             WaitKey = WaitBlock->WaitKey;
1284c2c66affSColin Finck         }
1285c2c66affSColin Finck         else
1286c2c66affSColin Finck         {
1287c2c66affSColin Finck             /* Otherwise, use STATUS_KERNEL_APC */
1288c2c66affSColin Finck             WaitKey = STATUS_KERNEL_APC;
1289c2c66affSColin Finck         }
1290c2c66affSColin Finck 
1291c2c66affSColin Finck         /* Unwait the thread */
1292c2c66affSColin Finck         KiUnwaitThread(WaitThread, WaitKey, Increment);
1293c2c66affSColin Finck 
1294c2c66affSColin Finck         /* Next entry */
1295c2c66affSColin Finck         WaitEntry = WaitList->Flink;
1296c2c66affSColin Finck     } while (WaitEntry != WaitList);
1297c2c66affSColin Finck }
1298c2c66affSColin Finck 
1299c2c66affSColin Finck //
1300c2c66affSColin Finck // Unwaits a Thread waiting on an event
1301c2c66affSColin Finck //
1302c2c66affSColin Finck FORCEINLINE
1303c2c66affSColin Finck VOID
KxUnwaitThreadForEvent(IN PKEVENT Event,IN KPRIORITY Increment)1304c2c66affSColin Finck KxUnwaitThreadForEvent(IN PKEVENT Event,
1305c2c66affSColin Finck                        IN KPRIORITY Increment)
1306c2c66affSColin Finck {
1307c2c66affSColin Finck     PLIST_ENTRY WaitEntry, WaitList;
1308c2c66affSColin Finck     PKWAIT_BLOCK WaitBlock;
1309c2c66affSColin Finck     PKTHREAD WaitThread;
1310c2c66affSColin Finck 
1311c2c66affSColin Finck     /* Loop the Wait Entries */
1312c2c66affSColin Finck     WaitList = &Event->Header.WaitListHead;
1313c2c66affSColin Finck     ASSERT(IsListEmpty(&Event->Header.WaitListHead) == FALSE);
1314c2c66affSColin Finck     WaitEntry = WaitList->Flink;
1315c2c66affSColin Finck     do
1316c2c66affSColin Finck     {
1317c2c66affSColin Finck         /* Get the current wait block */
1318c2c66affSColin Finck         WaitBlock = CONTAINING_RECORD(WaitEntry, KWAIT_BLOCK, WaitListEntry);
1319c2c66affSColin Finck 
1320c2c66affSColin Finck         /* Get the waiting thread */
1321c2c66affSColin Finck         WaitThread = WaitBlock->Thread;
1322c2c66affSColin Finck 
1323c2c66affSColin Finck         /* Check the current Wait Mode */
1324c2c66affSColin Finck         if (WaitBlock->WaitType == WaitAny)
1325c2c66affSColin Finck         {
1326c2c66affSColin Finck             /* Un-signal it */
1327c2c66affSColin Finck             Event->Header.SignalState = 0;
1328c2c66affSColin Finck 
1329c2c66affSColin Finck             /* Un-signal the event and unwait the thread */
1330c2c66affSColin Finck             KiUnwaitThread(WaitThread, WaitBlock->WaitKey, Increment);
1331c2c66affSColin Finck             break;
1332c2c66affSColin Finck         }
1333c2c66affSColin Finck 
1334c2c66affSColin Finck         /* Unwait the thread with STATUS_KERNEL_APC */
1335c2c66affSColin Finck         KiUnwaitThread(WaitThread, STATUS_KERNEL_APC, Increment);
1336c2c66affSColin Finck 
1337c2c66affSColin Finck         /* Next entry */
1338c2c66affSColin Finck         WaitEntry = WaitList->Flink;
1339c2c66affSColin Finck     } while (WaitEntry != WaitList);
1340c2c66affSColin Finck }
1341c2c66affSColin Finck 
1342c2c66affSColin Finck //
1343c2c66affSColin Finck // This routine queues a thread that is ready on the PRCB's ready lists.
1344c2c66affSColin Finck // If this thread cannot currently run on this CPU, then the thread is
1345c2c66affSColin Finck // added to the deferred ready list instead.
1346c2c66affSColin Finck //
1347c2c66affSColin Finck // This routine must be entered with the PRCB lock held and it will exit
1348c2c66affSColin Finck // with the PRCB lock released!
1349c2c66affSColin Finck //
1350a011d19eSTimo Kreuzer _Requires_lock_held_(Prcb->PrcbLock)
1351a011d19eSTimo Kreuzer _Releases_lock_(Prcb->PrcbLock)
1352c2c66affSColin Finck FORCEINLINE
1353c2c66affSColin Finck VOID
KxQueueReadyThread(IN PKTHREAD Thread,IN PKPRCB Prcb)1354c2c66affSColin Finck KxQueueReadyThread(IN PKTHREAD Thread,
1355c2c66affSColin Finck                    IN PKPRCB Prcb)
1356c2c66affSColin Finck {
1357c2c66affSColin Finck     BOOLEAN Preempted;
1358c2c66affSColin Finck     KPRIORITY Priority;
1359c2c66affSColin Finck 
1360c2c66affSColin Finck     /* Sanity checks */
1361c2c66affSColin Finck     ASSERT(Prcb == KeGetCurrentPrcb());
1362*748a2e16SJustin Miller #ifdef CONFIG_SMP
1363ab528ac6SOleg Dubinskiy     ASSERT(Prcb->PrcbLock != 0);
1364*748a2e16SJustin Miller #endif
1365c2c66affSColin Finck     ASSERT(Thread->State == Running);
1366c2c66affSColin Finck     ASSERT(Thread->NextProcessor == Prcb->Number);
1367c2c66affSColin Finck 
1368c2c66affSColin Finck     /* Check if this thread is allowed to run in this CPU */
1369c2c66affSColin Finck #ifdef CONFIG_SMP
1370c2c66affSColin Finck     if ((Thread->Affinity) & (Prcb->SetMember))
1371c2c66affSColin Finck #else
1372c2c66affSColin Finck     if (TRUE)
1373c2c66affSColin Finck #endif
1374c2c66affSColin Finck     {
1375c2c66affSColin Finck         /* Set thread ready for execution */
1376c2c66affSColin Finck         Thread->State = Ready;
1377c2c66affSColin Finck 
1378c2c66affSColin Finck         /* Save current priority and if someone had pre-empted it */
1379c2c66affSColin Finck         Priority = Thread->Priority;
1380c2c66affSColin Finck         Preempted = Thread->Preempted;
1381c2c66affSColin Finck 
1382c2c66affSColin Finck         /* We're not pre-empting now, and set the wait time */
1383c2c66affSColin Finck         Thread->Preempted = FALSE;
1384c2c66affSColin Finck         Thread->WaitTime = KeTickCount.LowPart;
1385c2c66affSColin Finck 
1386c2c66affSColin Finck         /* Sanity check */
1387c2c66affSColin Finck         ASSERT((Priority >= 0) && (Priority <= HIGH_PRIORITY));
1388c2c66affSColin Finck 
1389c2c66affSColin Finck         /* Insert this thread in the appropriate order */
1390c2c66affSColin Finck         Preempted ? InsertHeadList(&Prcb->DispatcherReadyListHead[Priority],
1391c2c66affSColin Finck                                    &Thread->WaitListEntry) :
1392c2c66affSColin Finck                     InsertTailList(&Prcb->DispatcherReadyListHead[Priority],
1393c2c66affSColin Finck                                    &Thread->WaitListEntry);
1394c2c66affSColin Finck 
1395c2c66affSColin Finck         /* Update the ready summary */
1396c2c66affSColin Finck         Prcb->ReadySummary |= PRIORITY_MASK(Priority);
1397c2c66affSColin Finck 
1398c2c66affSColin Finck         /* Sanity check */
1399c2c66affSColin Finck         ASSERT(Priority == Thread->Priority);
1400c2c66affSColin Finck 
1401c2c66affSColin Finck         /* Release the PRCB lock */
1402c2c66affSColin Finck         KiReleasePrcbLock(Prcb);
1403c2c66affSColin Finck     }
1404c2c66affSColin Finck     else
1405c2c66affSColin Finck     {
1406c2c66affSColin Finck         /* Otherwise, prepare this thread to be deferred */
1407c2c66affSColin Finck         Thread->State = DeferredReady;
1408c2c66affSColin Finck         Thread->DeferredProcessor = Prcb->Number;
1409c2c66affSColin Finck 
1410c2c66affSColin Finck         /* Release the lock and defer scheduling */
1411c2c66affSColin Finck         KiReleasePrcbLock(Prcb);
1412c2c66affSColin Finck         KiDeferredReadyThread(Thread);
1413c2c66affSColin Finck     }
1414c2c66affSColin Finck }
1415c2c66affSColin Finck 
1416c2c66affSColin Finck //
1417c2c66affSColin Finck // This routine scans for an appropriate ready thread to select at the
1418c2c66affSColin Finck // given priority and for the given CPU.
1419c2c66affSColin Finck //
1420c2c66affSColin Finck FORCEINLINE
1421c2c66affSColin Finck PKTHREAD
KiSelectReadyThread(IN KPRIORITY Priority,IN PKPRCB Prcb)1422c2c66affSColin Finck KiSelectReadyThread(IN KPRIORITY Priority,
1423c2c66affSColin Finck                     IN PKPRCB Prcb)
1424c2c66affSColin Finck {
1425c2c66affSColin Finck     ULONG PrioritySet;
1426c2c66affSColin Finck     LONG HighPriority;
1427c2c66affSColin Finck     PLIST_ENTRY ListEntry;
1428c2c66affSColin Finck     PKTHREAD Thread = NULL;
1429c2c66affSColin Finck 
1430c2c66affSColin Finck     /* Save the current mask and get the priority set for the CPU */
1431c2c66affSColin Finck     PrioritySet = Prcb->ReadySummary >> Priority;
1432c2c66affSColin Finck     if (!PrioritySet) goto Quickie;
1433c2c66affSColin Finck 
1434c2c66affSColin Finck     /* Get the highest priority possible */
1435c2c66affSColin Finck     BitScanReverse((PULONG)&HighPriority, PrioritySet);
1436c2c66affSColin Finck     ASSERT((PrioritySet & PRIORITY_MASK(HighPriority)) != 0);
1437c2c66affSColin Finck     HighPriority += Priority;
1438c2c66affSColin Finck 
1439c2c66affSColin Finck     /* Make sure the list isn't empty at the highest priority */
1440c2c66affSColin Finck     ASSERT(IsListEmpty(&Prcb->DispatcherReadyListHead[HighPriority]) == FALSE);
1441c2c66affSColin Finck 
1442c2c66affSColin Finck     /* Get the first thread on the list */
1443c2c66affSColin Finck     ListEntry = Prcb->DispatcherReadyListHead[HighPriority].Flink;
1444c2c66affSColin Finck     Thread = CONTAINING_RECORD(ListEntry, KTHREAD, WaitListEntry);
1445c2c66affSColin Finck 
1446c2c66affSColin Finck     /* Make sure this thread is here for a reason */
1447c2c66affSColin Finck     ASSERT(HighPriority == Thread->Priority);
1448c2c66affSColin Finck     ASSERT(Thread->Affinity & AFFINITY_MASK(Prcb->Number));
1449c2c66affSColin Finck     ASSERT(Thread->NextProcessor == Prcb->Number);
1450c2c66affSColin Finck 
1451c2c66affSColin Finck     /* Remove it from the list */
1452c2c66affSColin Finck     if (RemoveEntryList(&Thread->WaitListEntry))
1453c2c66affSColin Finck     {
1454c2c66affSColin Finck         /* The list is empty now, reset the ready summary */
1455c2c66affSColin Finck         Prcb->ReadySummary ^= PRIORITY_MASK(HighPriority);
1456c2c66affSColin Finck     }
1457c2c66affSColin Finck 
1458c2c66affSColin Finck     /* Sanity check and return the thread */
1459c2c66affSColin Finck Quickie:
1460c2c66affSColin Finck     ASSERT((Thread == NULL) ||
1461c2c66affSColin Finck            (Thread->BasePriority == 0) ||
1462c2c66affSColin Finck            (Thread->Priority != 0));
1463c2c66affSColin Finck     return Thread;
1464c2c66affSColin Finck }
1465c2c66affSColin Finck 
1466c2c66affSColin Finck //
1467c2c66affSColin Finck // This routine computes the new priority for a thread. It is only valid for
1468c2c66affSColin Finck // threads with priorities in the dynamic priority range.
1469c2c66affSColin Finck //
1470c2c66affSColin Finck FORCEINLINE
1471c2c66affSColin Finck SCHAR
KiComputeNewPriority(IN PKTHREAD Thread,IN SCHAR Adjustment)1472c2c66affSColin Finck KiComputeNewPriority(IN PKTHREAD Thread,
1473c2c66affSColin Finck                      IN SCHAR Adjustment)
1474c2c66affSColin Finck {
1475c2c66affSColin Finck     SCHAR Priority;
1476c2c66affSColin Finck 
1477c2c66affSColin Finck     /* Priority sanity checks */
1478c2c66affSColin Finck     ASSERT((Thread->PriorityDecrement >= 0) &&
1479c2c66affSColin Finck            (Thread->PriorityDecrement <= Thread->Priority));
1480c2c66affSColin Finck     ASSERT((Thread->Priority < LOW_REALTIME_PRIORITY) ?
1481c2c66affSColin Finck             TRUE : (Thread->PriorityDecrement == 0));
1482c2c66affSColin Finck 
1483c2c66affSColin Finck     /* Get the current priority */
1484c2c66affSColin Finck     Priority = Thread->Priority;
1485c2c66affSColin Finck     if (Priority < LOW_REALTIME_PRIORITY)
1486c2c66affSColin Finck     {
1487c2c66affSColin Finck         /* Decrease priority by the priority decrement */
1488c2c66affSColin Finck         Priority -= (Thread->PriorityDecrement + Adjustment);
1489c2c66affSColin Finck 
1490c2c66affSColin Finck         /* Don't go out of bounds */
1491c2c66affSColin Finck         if (Priority < Thread->BasePriority) Priority = Thread->BasePriority;
1492c2c66affSColin Finck 
1493c2c66affSColin Finck         /* Reset the priority decrement */
1494c2c66affSColin Finck         Thread->PriorityDecrement = 0;
1495c2c66affSColin Finck     }
1496c2c66affSColin Finck 
1497c2c66affSColin Finck     /* Sanity check */
1498c2c66affSColin Finck     ASSERT((Thread->BasePriority == 0) || (Priority != 0));
1499c2c66affSColin Finck 
1500c2c66affSColin Finck     /* Return the new priority */
1501c2c66affSColin Finck     return Priority;
1502c2c66affSColin Finck }
1503c2c66affSColin Finck 
1504c2c66affSColin Finck //
1505c2c66affSColin Finck // Guarded Mutex Routines
1506c2c66affSColin Finck //
1507c2c66affSColin Finck FORCEINLINE
1508c2c66affSColin Finck VOID
_KeInitializeGuardedMutex(OUT PKGUARDED_MUTEX GuardedMutex)1509c2c66affSColin Finck _KeInitializeGuardedMutex(OUT PKGUARDED_MUTEX GuardedMutex)
1510c2c66affSColin Finck {
1511c2c66affSColin Finck     /* Setup the Initial Data */
1512c2c66affSColin Finck     GuardedMutex->Count = GM_LOCK_BIT;
1513c2c66affSColin Finck     GuardedMutex->Owner = NULL;
1514c2c66affSColin Finck     GuardedMutex->Contention = 0;
1515c2c66affSColin Finck 
1516c2c66affSColin Finck     /* Initialize the Wait Gate */
1517c2c66affSColin Finck     KeInitializeGate(&GuardedMutex->Gate);
1518c2c66affSColin Finck }
1519c2c66affSColin Finck 
1520c2c66affSColin Finck FORCEINLINE
1521c2c66affSColin Finck VOID
_KeAcquireGuardedMutexUnsafe(IN OUT PKGUARDED_MUTEX GuardedMutex)1522c2c66affSColin Finck _KeAcquireGuardedMutexUnsafe(IN OUT PKGUARDED_MUTEX GuardedMutex)
1523c2c66affSColin Finck {
1524c2c66affSColin Finck     PKTHREAD Thread = KeGetCurrentThread();
1525c2c66affSColin Finck 
1526c2c66affSColin Finck     /* Sanity checks */
1527c2c66affSColin Finck     ASSERT((KeGetCurrentIrql() == APC_LEVEL) ||
1528c2c66affSColin Finck            (Thread->SpecialApcDisable < 0) ||
1529c2c66affSColin Finck            (Thread->Teb == NULL) ||
1530c2c66affSColin Finck            (Thread->Teb >= (PTEB)MM_SYSTEM_RANGE_START));
1531c2c66affSColin Finck     ASSERT(GuardedMutex->Owner != Thread);
1532c2c66affSColin Finck 
1533c2c66affSColin Finck     /* Remove the lock */
1534c2c66affSColin Finck     if (!InterlockedBitTestAndReset(&GuardedMutex->Count, GM_LOCK_BIT_V))
1535c2c66affSColin Finck     {
1536c2c66affSColin Finck         /* The Guarded Mutex was already locked, enter contented case */
1537c2c66affSColin Finck         KiAcquireGuardedMutex(GuardedMutex);
1538c2c66affSColin Finck     }
1539c2c66affSColin Finck 
1540c2c66affSColin Finck     /* Set the Owner */
1541c2c66affSColin Finck     GuardedMutex->Owner = Thread;
1542c2c66affSColin Finck }
1543c2c66affSColin Finck 
1544c2c66affSColin Finck FORCEINLINE
1545c2c66affSColin Finck VOID
_KeReleaseGuardedMutexUnsafe(IN OUT PKGUARDED_MUTEX GuardedMutex)1546c2c66affSColin Finck _KeReleaseGuardedMutexUnsafe(IN OUT PKGUARDED_MUTEX GuardedMutex)
1547c2c66affSColin Finck {
1548c2c66affSColin Finck     LONG OldValue, NewValue;
1549c2c66affSColin Finck 
1550c2c66affSColin Finck     /* Sanity checks */
1551c2c66affSColin Finck     ASSERT((KeGetCurrentIrql() == APC_LEVEL) ||
1552c2c66affSColin Finck            (KeGetCurrentThread()->SpecialApcDisable < 0) ||
1553c2c66affSColin Finck            (KeGetCurrentThread()->Teb == NULL) ||
1554c2c66affSColin Finck            (KeGetCurrentThread()->Teb >= (PTEB)MM_SYSTEM_RANGE_START));
1555c2c66affSColin Finck     ASSERT(GuardedMutex->Owner == KeGetCurrentThread());
1556c2c66affSColin Finck 
1557c2c66affSColin Finck     /* Destroy the Owner */
1558c2c66affSColin Finck     GuardedMutex->Owner = NULL;
1559c2c66affSColin Finck 
1560c2c66affSColin Finck     /* Add the Lock Bit */
1561c2c66affSColin Finck     OldValue = InterlockedExchangeAdd(&GuardedMutex->Count, GM_LOCK_BIT);
1562c2c66affSColin Finck     ASSERT((OldValue & GM_LOCK_BIT) == 0);
1563c2c66affSColin Finck 
1564c2c66affSColin Finck     /* Check if it was already locked, but not woken */
1565c2c66affSColin Finck     if ((OldValue) && !(OldValue & GM_LOCK_WAITER_WOKEN))
1566c2c66affSColin Finck     {
1567c2c66affSColin Finck         /* Update the Oldvalue to what it should be now */
1568c2c66affSColin Finck         OldValue += GM_LOCK_BIT;
1569c2c66affSColin Finck 
1570c2c66affSColin Finck         /* The mutex will be woken, minus one waiter */
1571c2c66affSColin Finck         NewValue = OldValue + GM_LOCK_WAITER_WOKEN -
1572c2c66affSColin Finck             GM_LOCK_WAITER_INC;
1573c2c66affSColin Finck 
1574c2c66affSColin Finck         /* Remove the Woken bit */
1575c2c66affSColin Finck         if (InterlockedCompareExchange(&GuardedMutex->Count,
1576c2c66affSColin Finck                                        NewValue,
1577c2c66affSColin Finck                                        OldValue) == OldValue)
1578c2c66affSColin Finck         {
1579c2c66affSColin Finck             /* Signal the Gate */
1580c2c66affSColin Finck             KeSignalGateBoostPriority(&GuardedMutex->Gate);
1581c2c66affSColin Finck         }
1582c2c66affSColin Finck     }
1583c2c66affSColin Finck }
1584c2c66affSColin Finck 
1585c2c66affSColin Finck FORCEINLINE
1586c2c66affSColin Finck VOID
_KeAcquireGuardedMutex(IN PKGUARDED_MUTEX GuardedMutex)1587c2c66affSColin Finck _KeAcquireGuardedMutex(IN PKGUARDED_MUTEX GuardedMutex)
1588c2c66affSColin Finck {
1589c2c66affSColin Finck     PKTHREAD Thread = KeGetCurrentThread();
1590c2c66affSColin Finck 
1591c2c66affSColin Finck     /* Sanity checks */
1592c2c66affSColin Finck     ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
1593c2c66affSColin Finck     ASSERT(GuardedMutex->Owner != Thread);
1594c2c66affSColin Finck 
1595c2c66affSColin Finck     /* Disable Special APCs */
1596c2c66affSColin Finck     KeEnterGuardedRegionThread(Thread);
1597c2c66affSColin Finck 
1598c2c66affSColin Finck     /* Remove the lock */
1599c2c66affSColin Finck     if (!InterlockedBitTestAndReset(&GuardedMutex->Count, GM_LOCK_BIT_V))
1600c2c66affSColin Finck     {
1601c2c66affSColin Finck         /* The Guarded Mutex was already locked, enter contented case */
1602c2c66affSColin Finck         KiAcquireGuardedMutex(GuardedMutex);
1603c2c66affSColin Finck     }
1604c2c66affSColin Finck 
1605c2c66affSColin Finck     /* Set the Owner and Special APC Disable state */
1606c2c66affSColin Finck     GuardedMutex->Owner = Thread;
1607c2c66affSColin Finck     GuardedMutex->SpecialApcDisable = Thread->SpecialApcDisable;
1608c2c66affSColin Finck }
1609c2c66affSColin Finck 
1610c2c66affSColin Finck FORCEINLINE
1611c2c66affSColin Finck VOID
_KeReleaseGuardedMutex(IN OUT PKGUARDED_MUTEX GuardedMutex)1612c2c66affSColin Finck _KeReleaseGuardedMutex(IN OUT PKGUARDED_MUTEX GuardedMutex)
1613c2c66affSColin Finck {
1614c2c66affSColin Finck     PKTHREAD Thread = KeGetCurrentThread();
1615c2c66affSColin Finck     LONG OldValue, NewValue;
1616c2c66affSColin Finck 
1617c2c66affSColin Finck     /* Sanity checks */
1618c2c66affSColin Finck     ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
1619c2c66affSColin Finck     ASSERT(GuardedMutex->Owner == Thread);
1620c2c66affSColin Finck     ASSERT(Thread->SpecialApcDisable == GuardedMutex->SpecialApcDisable);
1621c2c66affSColin Finck 
1622c2c66affSColin Finck     /* Destroy the Owner */
1623c2c66affSColin Finck     GuardedMutex->Owner = NULL;
1624c2c66affSColin Finck 
1625c2c66affSColin Finck     /* Add the Lock Bit */
1626c2c66affSColin Finck     OldValue = InterlockedExchangeAdd(&GuardedMutex->Count, GM_LOCK_BIT);
1627c2c66affSColin Finck     ASSERT((OldValue & GM_LOCK_BIT) == 0);
1628c2c66affSColin Finck 
1629c2c66affSColin Finck     /* Check if it was already locked, but not woken */
1630c2c66affSColin Finck     if ((OldValue) && !(OldValue & GM_LOCK_WAITER_WOKEN))
1631c2c66affSColin Finck     {
1632c2c66affSColin Finck         /* Update the Oldvalue to what it should be now */
1633c2c66affSColin Finck         OldValue += GM_LOCK_BIT;
1634c2c66affSColin Finck 
1635c2c66affSColin Finck         /* The mutex will be woken, minus one waiter */
1636c2c66affSColin Finck         NewValue = OldValue + GM_LOCK_WAITER_WOKEN -
1637c2c66affSColin Finck             GM_LOCK_WAITER_INC;
1638c2c66affSColin Finck 
1639c2c66affSColin Finck         /* Remove the Woken bit */
1640c2c66affSColin Finck         if (InterlockedCompareExchange(&GuardedMutex->Count,
1641c2c66affSColin Finck                                        NewValue,
1642c2c66affSColin Finck                                        OldValue) == OldValue)
1643c2c66affSColin Finck         {
1644c2c66affSColin Finck             /* Signal the Gate */
1645c2c66affSColin Finck             KeSignalGateBoostPriority(&GuardedMutex->Gate);
1646c2c66affSColin Finck         }
1647c2c66affSColin Finck     }
1648c2c66affSColin Finck 
1649c2c66affSColin Finck     /* Re-enable APCs */
1650c2c66affSColin Finck     KeLeaveGuardedRegionThread(Thread);
1651c2c66affSColin Finck }
1652c2c66affSColin Finck 
1653c2c66affSColin Finck FORCEINLINE
1654c2c66affSColin Finck BOOLEAN
_KeTryToAcquireGuardedMutex(IN OUT PKGUARDED_MUTEX GuardedMutex)1655c2c66affSColin Finck _KeTryToAcquireGuardedMutex(IN OUT PKGUARDED_MUTEX GuardedMutex)
1656c2c66affSColin Finck {
1657c2c66affSColin Finck     PKTHREAD Thread = KeGetCurrentThread();
1658c2c66affSColin Finck 
1659c2c66affSColin Finck     /* Block APCs */
1660c2c66affSColin Finck     KeEnterGuardedRegionThread(Thread);
1661c2c66affSColin Finck 
1662c2c66affSColin Finck     /* Remove the lock */
1663c2c66affSColin Finck     if (!InterlockedBitTestAndReset(&GuardedMutex->Count, GM_LOCK_BIT_V))
1664c2c66affSColin Finck     {
1665c2c66affSColin Finck         /* Re-enable APCs */
1666c2c66affSColin Finck         KeLeaveGuardedRegionThread(Thread);
1667c2c66affSColin Finck         YieldProcessor();
1668c2c66affSColin Finck 
1669c2c66affSColin Finck         /* Return failure */
1670c2c66affSColin Finck         return FALSE;
1671c2c66affSColin Finck     }
1672c2c66affSColin Finck 
1673c2c66affSColin Finck     /* Set the Owner and APC State */
1674c2c66affSColin Finck     GuardedMutex->Owner = Thread;
1675c2c66affSColin Finck     GuardedMutex->SpecialApcDisable = Thread->SpecialApcDisable;
1676c2c66affSColin Finck     return TRUE;
1677c2c66affSColin Finck }
1678c2c66affSColin Finck 
1679c2c66affSColin Finck 
1680c2c66affSColin Finck FORCEINLINE
1681c2c66affSColin Finck VOID
KiAcquireNmiListLock(OUT PKIRQL OldIrql)1682c2c66affSColin Finck KiAcquireNmiListLock(OUT PKIRQL OldIrql)
1683c2c66affSColin Finck {
1684c2c66affSColin Finck     KeAcquireSpinLock(&KiNmiCallbackListLock, OldIrql);
1685c2c66affSColin Finck }
1686c2c66affSColin Finck 
1687c2c66affSColin Finck FORCEINLINE
1688c2c66affSColin Finck VOID
KiReleaseNmiListLock(IN KIRQL OldIrql)1689c2c66affSColin Finck KiReleaseNmiListLock(IN KIRQL OldIrql)
1690c2c66affSColin Finck {
1691c2c66affSColin Finck     KeReleaseSpinLock(&KiNmiCallbackListLock, OldIrql);
1692c2c66affSColin Finck }
1693c2c66affSColin Finck 
1694c2c66affSColin Finck #if defined(_M_IX86) || defined(_M_AMD64)
1695c2c66affSColin Finck FORCEINLINE
1696c2c66affSColin Finck VOID
KiCpuId(PCPU_INFO CpuInfo,ULONG Function)1697c2c66affSColin Finck KiCpuId(
1698c2c66affSColin Finck     PCPU_INFO CpuInfo,
1699c2c66affSColin Finck     ULONG Function)
1700c2c66affSColin Finck {
1701c2c66affSColin Finck     __cpuid((INT*)CpuInfo->AsUINT32, Function);
1702c2c66affSColin Finck }
1703c2c66affSColin Finck 
1704c2c66affSColin Finck FORCEINLINE
1705c2c66affSColin Finck VOID
KiCpuIdEx(PCPU_INFO CpuInfo,ULONG Function,ULONG SubFunction)1706c2c66affSColin Finck KiCpuIdEx(
1707c2c66affSColin Finck     PCPU_INFO CpuInfo,
1708c2c66affSColin Finck     ULONG Function,
1709c2c66affSColin Finck     ULONG SubFunction)
1710c2c66affSColin Finck {
1711c2c66affSColin Finck     __cpuidex((INT*)CpuInfo->AsUINT32, Function, SubFunction);
1712c2c66affSColin Finck }
1713c2c66affSColin Finck #endif /* _M_IX86 || _M_AMD64 */
171431afbf10SJérôme Gardou 
171531afbf10SJérôme Gardou #ifdef __cplusplus
171631afbf10SJérôme Gardou } // extern "C"
171731afbf10SJérôme Gardou #endif
1718