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