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