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