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