ReactOS 0.4.17-dev-966-gf06eace
wait.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ke/wait.c
5 * PURPOSE: Manages waiting for Dispatcher Objects
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Gunnar Dalsnes
8 */
9
10/* INCLUDES ******************************************************************/
11
12#include <ntoskrnl.h>
13#define NDEBUG
14#include <debug.h>
15
16/* PRIVATE FUNCTIONS *********************************************************/
17
18VOID
20KiWaitTest(IN PVOID ObjectPointer,
22{
23 PLIST_ENTRY WaitEntry, WaitList;
24 PKWAIT_BLOCK WaitBlock;
25 PKTHREAD WaitThread;
26 PKMUTANT FirstObject = ObjectPointer;
27 NTSTATUS WaitStatus;
28
29 /* Loop the Wait Entries */
30 WaitList = &FirstObject->Header.WaitListHead;
31 WaitEntry = WaitList->Flink;
32 while ((FirstObject->Header.SignalState > 0) && (WaitEntry != WaitList))
33 {
34 /* Get the current wait block */
35 WaitBlock = CONTAINING_RECORD(WaitEntry, KWAIT_BLOCK, WaitListEntry);
36 WaitThread = WaitBlock->Thread;
37 WaitStatus = STATUS_KERNEL_APC;
38
39 /* Check the current Wait Mode */
40 if (WaitBlock->WaitType == WaitAny)
41 {
42 /* Easy case, satisfy only this wait */
43 WaitStatus = (NTSTATUS)WaitBlock->WaitKey;
44 KiSatisfyObjectWait(FirstObject, WaitThread);
45 }
46
47 /* Now do the rest of the unwait */
48 KiUnwaitThread(WaitThread, WaitStatus, Increment);
49 WaitEntry = WaitList->Flink;
50 }
51}
52
53VOID
56 IN LONG_PTR WaitStatus)
57{
58 PKWAIT_BLOCK WaitBlock;
60
61 /* Update wait status */
62 Thread->WaitStatus |= WaitStatus;
63
64 /* Remove the Wait Blocks from the list */
65 WaitBlock = Thread->WaitBlockList;
66 do
67 {
68 /* Remove it */
69 RemoveEntryList(&WaitBlock->WaitListEntry);
70
71 /* Go to the next one */
72 WaitBlock = WaitBlock->NextWaitBlock;
73 } while (WaitBlock != Thread->WaitBlockList);
74
75 /* Remove the thread from the wait list! */
76 if (Thread->WaitListEntry.Flink) RemoveEntryList(&Thread->WaitListEntry);
77
78 /* Check if there's a Thread Timer */
79 Timer = &Thread->Timer;
80 if (Timer->Header.Inserted) KxRemoveTreeTimer(Timer);
81
82 /* Increment the Queue's active threads */
83 if (Thread->Queue) Thread->Queue->CurrentCount++;
84}
85
86/* Must be called with the dispatcher lock held */
87VOID
90 IN LONG_PTR WaitStatus,
92{
93 /* Unlink the thread */
94 KiUnlinkThread(Thread, WaitStatus);
95
96 /* Tell the scheduler do to the increment when it readies the thread */
97 ASSERT(Increment >= 0);
98 Thread->AdjustIncrement = (SCHAR)Increment;
99 Thread->AdjustReason = AdjustUnwait;
100
101 /* Reschedule the Thread */
103}
104
105VOID
108{
109 /* Increase contention count */
110 FastMutex->Contention++;
111
112 /* Wait for the event */
113 KeWaitForSingleObject(&FastMutex->Event,
114 WrMutex,
116 FALSE,
117 NULL);
118}
119
120VOID
123{
124 ULONG BitsToRemove, BitsToAdd;
125 LONG OldValue, NewValue;
126
127 /* We depend on these bits being just right */
129
130 /* Increase the contention count */
131 GuardedMutex->Contention++;
132
133 /* Start by unlocking the Guarded Mutex */
134 BitsToRemove = GM_LOCK_BIT;
135 BitsToAdd = GM_LOCK_WAITER_INC;
136
137 /* Start change loop */
138 for (;;)
139 {
140 /* Loop sanity checks */
141 ASSERT((BitsToRemove == GM_LOCK_BIT) ||
142 (BitsToRemove == (GM_LOCK_BIT | GM_LOCK_WAITER_WOKEN)));
143 ASSERT((BitsToAdd == GM_LOCK_WAITER_INC) ||
144 (BitsToAdd == GM_LOCK_WAITER_WOKEN));
145
146 /* Get the Count Bits */
147 OldValue = GuardedMutex->Count;
148
149 /* Start internal bit change loop */
150 for (;;)
151 {
152 /* Check if the Guarded Mutex is locked */
153 if (OldValue & GM_LOCK_BIT)
154 {
155 /* Sanity check */
156 ASSERT((BitsToRemove == GM_LOCK_BIT) ||
157 ((OldValue & GM_LOCK_WAITER_WOKEN) != 0));
158
159 /* Unlock it by removing the Lock Bit */
160 NewValue = OldValue ^ BitsToRemove;
161 NewValue = InterlockedCompareExchange(&GuardedMutex->Count,
162 NewValue,
163 OldValue);
164 if (NewValue == OldValue) return;
165 }
166 else
167 {
168 /* The Guarded Mutex isn't locked, so simply set the bits */
169 NewValue = OldValue + BitsToAdd;
170 NewValue = InterlockedCompareExchange(&GuardedMutex->Count,
171 NewValue,
172 OldValue);
173 if (NewValue == OldValue) break;
174 }
175
176 /* Old value changed, loop again */
177 OldValue = NewValue;
178 }
179
180 /* Now we have to wait for it */
181 KeWaitForGate(&GuardedMutex->Gate, WrGuardedMutex, KernelMode);
182 ASSERT((GuardedMutex->Count & GM_LOCK_WAITER_WOKEN) != 0);
183
184 /* Ok, the wait is done, so set the new bits */
185 BitsToRemove = GM_LOCK_BIT | GM_LOCK_WAITER_WOKEN;
186 BitsToAdd = GM_LOCK_WAITER_WOKEN;
187 }
188}
189
190//
191// This routine exits the dispatcher after a compatible operation and
192// swaps the context to the next scheduled thread on the current CPU if
193// one is available.
194//
195// It does NOT attempt to scan for a new thread to schedule.
196//
197VOID
200{
201 PKPRCB Prcb = KeGetCurrentPrcb();
202 PKTHREAD Thread, NextThread;
203 BOOLEAN PendingApc;
204
205 /* Make sure we're at synchronization level */
207
208 /* Check if we have deferred threads */
210
211 /* Check if we were called at dispatcher level or higher */
212 if (OldIrql >= DISPATCH_LEVEL)
213 {
214 /* Check if we have a thread to schedule, and that no DPC is active */
215 if ((Prcb->NextThread) && !(Prcb->DpcRoutineActive))
216 {
217 /* Request DPC interrupt */
219 }
220
221 /* Lower IRQL and exit */
222 goto Quickie;
223 }
224
225 /* Make sure there's a new thread scheduled */
226 if (!Prcb->NextThread) goto Quickie;
227
228 /* Lock the PRCB */
229 KiAcquirePrcbLock(Prcb);
230
231 /* Get the next and current threads now */
232 NextThread = Prcb->NextThread;
233 Thread = Prcb->CurrentThread;
234
235 /* Set current thread's swap busy to true */
237
238 /* Switch threads in PRCB */
239 Prcb->NextThread = NULL;
240 Prcb->CurrentThread = NextThread;
241
242 /* Set thread to running */
243 NextThread->State = Running;
244
245 /* Queue it on the ready lists */
246 KxQueueReadyThread(Thread, Prcb);
247
248 /* Set wait IRQL */
249 Thread->WaitIrql = OldIrql;
250
251 /* Swap threads and check if APCs were pending */
252 PendingApc = KiSwapContext(OldIrql, Thread);
253 if (PendingApc)
254 {
255 /* Lower only to APC */
257
258 /* Deliver APCs */
261 }
262
263 /* Lower IRQl back */
264Quickie:
266}
267
268/* PUBLIC FUNCTIONS **********************************************************/
269
282NTAPI
285{
286 /* Make sure we see a consistent snapshot of the list head */
288 return IsListEmpty(&((PDISPATCHER_HEADER)Object)->WaitListHead);
289}
290
291/*
292 * @implemented
293 */
295NTAPI
299{
301 PKWAIT_BLOCK TimerBlock;
303 NTSTATUS WaitStatus;
304 BOOLEAN Swappable;
305 PLARGE_INTEGER OriginalDueTime;
306 LARGE_INTEGER DueTime, NewDueTime, InterruptTime;
307 ULONG Hand = 0;
308
309 if (Thread->WaitNext)
311 else
313
314 /* If this is a user-mode wait of 0 seconds, yield execution */
315 if (!(Interval->QuadPart) && (WaitMode != KernelMode))
316 {
317 /* Make sure the wait isn't alertable or interrupting an APC */
318 if (!(Alertable) && !(Thread->ApcState.UserApcPending))
319 {
320 /* Yield execution */
321 return NtYieldExecution();
322 }
323 }
324
325 /* Setup the original time and timer/wait blocks */
326 OriginalDueTime = Interval;
327 Timer = &Thread->Timer;
328 TimerBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
329
330 /* Check if the lock is already held */
331 if (!Thread->WaitNext) goto WaitStart;
332
333 /* Otherwise, we already have the lock, so initialize the wait */
334 Thread->WaitNext = FALSE;
336
337 /* Start wait loop */
338 for (;;)
339 {
340 /* Disable pre-emption */
341 Thread->Preempted = FALSE;
342
343 /* Check if a kernel APC is pending and we're below APC_LEVEL */
344 if ((Thread->ApcState.KernelApcPending) && !(Thread->SpecialApcDisable) &&
345 (Thread->WaitIrql < APC_LEVEL))
346 {
347 /* Unlock the dispatcher */
349 }
350 else
351 {
352 /* Check if we have to bail out due to an alerted state */
353 WaitStatus = KiCheckAlertability(Thread, Alertable, WaitMode);
354 if (WaitStatus != STATUS_WAIT_0) break;
355
356 /* Check if the timer expired */
357 InterruptTime.QuadPart = KeQueryInterruptTime();
358 if ((ULONGLONG)InterruptTime.QuadPart >= Timer->DueTime.QuadPart)
359 {
360 /* It did, so we don't need to wait */
361 goto NoWait;
362 }
363
364 /* It didn't, so activate it */
365 Timer->Header.Inserted = TRUE;
366
367 /* Handle Kernel Queues */
368 if (Thread->Queue) KiActivateWaiterQueue(Thread->Queue);
369
370 /* Setup the wait information */
371 Thread->State = Waiting;
372
373 /* Add the thread to the wait list */
374 KiAddThreadToWaitList(Thread, Swappable);
375
376 /* Insert the timer and swap the thread */
377 ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
379 KxInsertTimer(Timer, Hand);
381
382 /* Check if were swapped ok */
383 if (WaitStatus != STATUS_KERNEL_APC)
384 {
385 /* This is a good thing */
386 if (WaitStatus == STATUS_TIMEOUT) WaitStatus = STATUS_SUCCESS;
387
388 /* Return Status */
389 return WaitStatus;
390 }
391
392 /* Recalculate due times */
393 Interval = KiRecalculateDueTime(OriginalDueTime,
394 &DueTime,
395 &NewDueTime);
396 }
397
398WaitStart:
399 /* Setup a new wait */
400 Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
403 }
404
405 /* We're done! */
407 return WaitStatus;
408
409NoWait:
410 /* There was nothing to wait for. Did we have a wait interval? */
411 if (!Interval->QuadPart)
412 {
413 /* Unlock the dispatcher and do a yield */
415 return NtYieldExecution();
416 }
417
418 /* Unlock the dispatcher and adjust the quantum for a no-wait */
421 return STATUS_SUCCESS;
422}
423
424/*
425 * @implemented
426 */
428NTAPI
430 IN KWAIT_REASON WaitReason,
431 IN KPROCESSOR_MODE WaitMode,
434{
436 PKMUTANT CurrentObject = (PKMUTANT)Object;
437 PKWAIT_BLOCK WaitBlock = &Thread->WaitBlock[0];
438 PKWAIT_BLOCK TimerBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
439 PKTIMER Timer = &Thread->Timer;
440 NTSTATUS WaitStatus;
441 BOOLEAN Swappable;
442 LARGE_INTEGER DueTime = {{0}}, NewDueTime, InterruptTime;
443 PLARGE_INTEGER OriginalDueTime = Timeout;
444 ULONG Hand = 0;
445
446 if (Thread->WaitNext)
448 else
451 Timeout && Timeout->QuadPart == 0));
452
453 /* Check if the lock is already held */
454 if (!Thread->WaitNext) goto WaitStart;
455
456 /* Otherwise, we already have the lock, so initialize the wait */
457 Thread->WaitNext = FALSE;
459
460 /* Start wait loop */
461 for (;;)
462 {
463 /* Disable pre-emption */
464 Thread->Preempted = FALSE;
465
466 /* Check if a kernel APC is pending and we're below APC_LEVEL */
467 if ((Thread->ApcState.KernelApcPending) && !(Thread->SpecialApcDisable) &&
468 (Thread->WaitIrql < APC_LEVEL))
469 {
470 /* Unlock the dispatcher */
472 }
473 else
474 {
475 /* Sanity check */
476 ASSERT(CurrentObject->Header.Type != QueueObject);
477
478 /* Check if it's a mutant */
479 if (CurrentObject->Header.Type == MutantObject)
480 {
481 /* Check its signal state or if we own it */
482 if ((CurrentObject->Header.SignalState > 0) ||
483 (Thread == CurrentObject->OwnerThread))
484 {
485 /* Just unwait this guy and exit */
486 if (CurrentObject->Header.SignalState != MINLONG)
487 {
488 /* It has a normal signal state. Unwait and return */
489 KiSatisfyMutantWait(CurrentObject, Thread);
490 WaitStatus = (NTSTATUS)Thread->WaitStatus;
491 goto DontWait;
492 }
493 else
494 {
495 /* Raise an exception */
498 }
499 }
500 }
501 else if (CurrentObject->Header.SignalState > 0)
502 {
503 /* Another satisfied object */
504 KiSatisfyNonMutantWait(CurrentObject);
505 WaitStatus = STATUS_WAIT_0;
506 goto DontWait;
507 }
508
509 /* Make sure we can satisfy the Alertable request */
510 WaitStatus = KiCheckAlertability(Thread, Alertable, WaitMode);
511 if (WaitStatus != STATUS_WAIT_0) break;
512
513 /* Enable the Timeout Timer if there was any specified */
514 if (Timeout)
515 {
516 /* Check if the timer expired */
517 InterruptTime.QuadPart = KeQueryInterruptTime();
518 if ((ULONGLONG)InterruptTime.QuadPart >=
519 Timer->DueTime.QuadPart)
520 {
521 /* It did, so we don't need to wait */
522 WaitStatus = STATUS_TIMEOUT;
523 goto DontWait;
524 }
525
526 /* It didn't, so activate it */
527 Timer->Header.Inserted = TRUE;
528 }
529
530 /* Link the Object to this Wait Block */
531 InsertTailList(&CurrentObject->Header.WaitListHead,
532 &WaitBlock->WaitListEntry);
533
534 /* Handle Kernel Queues */
535 if (Thread->Queue) KiActivateWaiterQueue(Thread->Queue);
536
537 /* Setup the wait information */
538 Thread->State = Waiting;
539
540 /* Add the thread to the wait list */
541 KiAddThreadToWaitList(Thread, Swappable);
542
543 /* Activate thread swap */
544 ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
546
547 /* Check if we have a timer */
548 if (Timeout)
549 {
550 /* Insert it */
551 KxInsertTimer(Timer, Hand);
552 }
553 else
554 {
555 /* Otherwise, unlock the dispatcher */
557 }
558
559 /* Do the actual swap */
561
562 /* Check if we were executing an APC */
563 if (WaitStatus != STATUS_KERNEL_APC) return WaitStatus;
564
565 /* Check if we had a timeout */
566 if (Timeout)
567 {
568 /* Recalculate due times */
569 Timeout = KiRecalculateDueTime(OriginalDueTime,
570 &DueTime,
571 &NewDueTime);
572 }
573 }
574WaitStart:
575 /* Setup a new wait */
576 Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
579 }
580
581 /* Wait complete */
583 return WaitStatus;
584
585DontWait:
586 /* Release dispatcher lock but maintain high IRQL */
588
589 /* Adjust the Quantum and return the wait status */
591 return WaitStatus;
592}
593
594/*
595 * @implemented
596 */
598NTAPI
600 IN PVOID Object[],
602 IN KWAIT_REASON WaitReason,
603 IN KPROCESSOR_MODE WaitMode,
607{
608 PKMUTANT CurrentObject;
609 PKWAIT_BLOCK WaitBlock;
611 PKWAIT_BLOCK TimerBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
612 PKTIMER Timer = &Thread->Timer;
613 NTSTATUS WaitStatus = STATUS_SUCCESS;
614 BOOLEAN Swappable;
615 PLARGE_INTEGER OriginalDueTime = Timeout;
616 LARGE_INTEGER DueTime = {{0}}, NewDueTime, InterruptTime;
617 ULONG Index, Hand = 0;
618
619 if (Thread->WaitNext)
621 else if (!Timeout || (Timeout->QuadPart != 0))
622 {
624 }
625 else
627
628 /* Make sure the Wait Count is valid */
629 if (!WaitBlockArray)
630 {
631 /* Check in regards to the Thread Object Limit */
633 {
634 /* Bugcheck */
635 KeBugCheck(MAXIMUM_WAIT_OBJECTS_EXCEEDED);
636 }
637
638 /* Use the Thread's Wait Block */
639 WaitBlockArray = &Thread->WaitBlock[0];
640 }
641 else
642 {
643 /* Using our own Block Array, so check with the System Object Limit */
645 {
646 /* Bugcheck */
647 KeBugCheck(MAXIMUM_WAIT_OBJECTS_EXCEEDED);
648 }
649 }
650
651 /* Sanity check */
652 ASSERT(Count != 0);
653
654 /* Check if the lock is already held */
655 if (!Thread->WaitNext) goto WaitStart;
656
657 /* Otherwise, we already have the lock, so initialize the wait */
658 Thread->WaitNext = FALSE;
659 /* Note that KxMultiThreadWait is a macro, defined in ke_x.h, that */
660 /* uses (and modifies some of) the following local */
661 /* variables: */
662 /* Thread, Index, WaitBlock, Timer, Timeout, Hand and Swappable. */
663 /* If it looks like this code doesn't actually wait for any objects */
664 /* at all, it's because the setup is done by that macro. */
666
667 /* Start wait loop */
668 for (;;)
669 {
670 /* Disable pre-emption */
671 Thread->Preempted = FALSE;
672
673 /* Check if a kernel APC is pending and we're below APC_LEVEL */
674 if ((Thread->ApcState.KernelApcPending) && !(Thread->SpecialApcDisable) &&
675 (Thread->WaitIrql < APC_LEVEL))
676 {
677 /* Unlock the dispatcher */
679 }
680 else
681 {
682 /* Check what kind of wait this is */
683 Index = 0;
684 if (WaitType == WaitAny)
685 {
686 /* Loop blocks */
687 do
688 {
689 /* Get the Current Object */
690 CurrentObject = (PKMUTANT)Object[Index];
691 ASSERT(CurrentObject->Header.Type != QueueObject);
692
693 /* Check if the Object is a mutant */
694 if (CurrentObject->Header.Type == MutantObject)
695 {
696 /* Check if it's signaled */
697 if ((CurrentObject->Header.SignalState > 0) ||
698 (Thread == CurrentObject->OwnerThread))
699 {
700 /* This is a Wait Any, so unwait this and exit */
701 if (CurrentObject->Header.SignalState !=
702 (LONG)MINLONG)
703 {
704 /* Normal signal state, unwait it and return */
705 KiSatisfyMutantWait(CurrentObject, Thread);
706 WaitStatus = (NTSTATUS)Thread->WaitStatus | Index;
707 goto DontWait;
708 }
709 else
710 {
711 /* Raise an exception (see wasm.ru) */
714 }
715 }
716 }
717 else if (CurrentObject->Header.SignalState > 0)
718 {
719 /* Another signaled object, unwait and return */
720 KiSatisfyNonMutantWait(CurrentObject);
721 WaitStatus = Index;
722 goto DontWait;
723 }
724
725 /* Go to the next block */
726 Index++;
727 } while (Index < Count);
728 }
729 else
730 {
731 /* Loop blocks */
732 do
733 {
734 /* Get the Current Object */
735 CurrentObject = (PKMUTANT)Object[Index];
736 ASSERT(CurrentObject->Header.Type != QueueObject);
737
738 /* Check if we're dealing with a mutant again */
739 if (CurrentObject->Header.Type == MutantObject)
740 {
741 /* Check if it has an invalid count */
742 if ((Thread == CurrentObject->OwnerThread) &&
743 (CurrentObject->Header.SignalState == (LONG)MINLONG))
744 {
745 /* Raise an exception */
748 }
749 else if ((CurrentObject->Header.SignalState <= 0) &&
750 (Thread != CurrentObject->OwnerThread))
751 {
752 /* We don't own it, can't satisfy the wait */
753 break;
754 }
755 }
756 else if (CurrentObject->Header.SignalState <= 0)
757 {
758 /* Not signaled, can't satisfy */
759 break;
760 }
761
762 /* Go to the next block */
763 Index++;
764 } while (Index < Count);
765
766 /* Check if we've went through all the objects */
767 if (Index == Count)
768 {
769 /* Loop wait blocks */
770 WaitBlock = WaitBlockArray;
771 do
772 {
773 /* Get the object and satisfy it */
774 CurrentObject = (PKMUTANT)WaitBlock->Object;
775 KiSatisfyObjectWait(CurrentObject, Thread);
776
777 /* Go to the next block */
778 WaitBlock = WaitBlock->NextWaitBlock;
779 } while(WaitBlock != WaitBlockArray);
780
781 /* Set the wait status and get out */
782 WaitStatus = (NTSTATUS)Thread->WaitStatus;
783 goto DontWait;
784 }
785 }
786
787 /* Make sure we can satisfy the Alertable request */
788 WaitStatus = KiCheckAlertability(Thread, Alertable, WaitMode);
789 if (WaitStatus != STATUS_WAIT_0) break;
790
791 /* Enable the Timeout Timer if there was any specified */
792 if (Timeout)
793 {
794 /* Check if the timer expired */
795 InterruptTime.QuadPart = KeQueryInterruptTime();
796 if ((ULONGLONG)InterruptTime.QuadPart >=
797 Timer->DueTime.QuadPart)
798 {
799 /* It did, so we don't need to wait */
800 WaitStatus = STATUS_TIMEOUT;
801 goto DontWait;
802 }
803
804 /* It didn't, so activate it */
805 Timer->Header.Inserted = TRUE;
806
807 /* Link the wait blocks */
808 WaitBlock->NextWaitBlock = TimerBlock;
809 }
810
811 /* Insert into Object's Wait List*/
812 WaitBlock = WaitBlockArray;
813 do
814 {
815 /* Get the Current Object */
816 CurrentObject = WaitBlock->Object;
817
818 /* Link the Object to this Wait Block */
819 InsertTailList(&CurrentObject->Header.WaitListHead,
820 &WaitBlock->WaitListEntry);
821
822 /* Move to the next Wait Block */
823 WaitBlock = WaitBlock->NextWaitBlock;
824 } while (WaitBlock != WaitBlockArray);
825
826 /* Handle Kernel Queues */
827 if (Thread->Queue) KiActivateWaiterQueue(Thread->Queue);
828
829 /* Setup the wait information */
830 Thread->State = Waiting;
831
832 /* Add the thread to the wait list */
833 KiAddThreadToWaitList(Thread, Swappable);
834
835 /* Activate thread swap */
836 ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
838
839 /* Check if we have a timer */
840 if (Timeout)
841 {
842 /* Insert it */
843 KxInsertTimer(Timer, Hand);
844 }
845 else
846 {
847 /* Otherwise, unlock the dispatcher */
849 }
850
851 /* Swap the thread */
853
854 /* Check if we were executing an APC */
855 if (WaitStatus != STATUS_KERNEL_APC) return WaitStatus;
856
857 /* Check if we had a timeout */
858 if (Timeout)
859 {
860 /* Recalculate due times */
861 Timeout = KiRecalculateDueTime(OriginalDueTime,
862 &DueTime,
863 &NewDueTime);
864 }
865 }
866
867WaitStart:
868 /* Setup a new wait */
869 Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
872 }
873
874 /* We are done */
876 return WaitStatus;
877
878DontWait:
879 /* Release dispatcher lock but maintain high IRQL */
881
882 /* Adjust the Quantum and return the wait status */
884 return WaitStatus;
885}
886
888NTAPI
890 IN PLARGE_INTEGER DelayInterval)
891{
893 LARGE_INTEGER SafeInterval;
895
896 /* Check the previous mode */
898 {
899 /* Enter SEH for probing */
901 {
902 /* Probe and capture the time out */
903 SafeInterval = ProbeForReadLargeInteger(DelayInterval);
904 DelayInterval = &SafeInterval;
905 }
907 {
908 /* Return the exception code */
910 }
911 _SEH2_END;
912 }
913
914 /* Call the Kernel Function */
916 Alertable,
917 DelayInterval);
918
919 /* Return Status */
920 return Status;
921}
922
923/* EOF */
_In_ PVOID _In_ ULONG _Out_ PVOID _In_ ULONG _Inout_ PULONG _In_ KPROCESSOR_MODE PreviousMode
unsigned char BOOLEAN
Definition: actypes.h:127
LONG NTSTATUS
Definition: precomp.h:26
DECLSPEC_NORETURN VOID NTAPI KeBugCheck(ULONG BugCheckCode)
Definition: bug.c:1434
#define STATUS_TIMEOUT
Definition: d3dkmdt.h:49
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NTSTATUS
Definition: precomp.h:19
LONG KPRIORITY
Definition: compat.h:803
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986
#define InsertTailList(ListHead, Entry)
#define SYNCH_LEVEL
Definition: env_spec_w32.h:704
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define KeWaitForSingleObject(pEvt, foo, a, b, c)
Definition: env_spec_w32.h:478
#define APC_LEVEL
Definition: env_spec_w32.h:695
#define KeLowerIrql(oldIrql)
Definition: env_spec_w32.h:602
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
#define KeDelayExecutionThread(mode, foo, t)
Definition: env_spec_w32.h:484
#define ExGetPreviousMode
Definition: ex.h:143
IN OUT PLONG IN OUT PLONG Addend IN OUT PLONG IN LONG Increment
Definition: CrNtStubs.h:46
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
_Must_inspect_result_ _In_ WAIT_TYPE _In_opt_ PLARGE_INTEGER _In_opt_ PKWAIT_BLOCK WaitBlockArray
Definition: fsrtlfuncs.h:1153
Status
Definition: gdiplustypes.h:24
VOID FASTCALL HalRequestSoftwareInterrupt(IN KIRQL Irql)
Definition: pic.c:271
KIRQL NTAPI KeRaiseIrqlToSynchLevel(VOID)
Definition: pic.c:156
#define KeGetCurrentThread
Definition: hal.h:55
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:90
#define InterlockedCompareExchange
Definition: interlocked.h:119
#define C_ASSERT(e)
Definition: intsafe.h:73
#define KiSatisfyMutantWait(Object, Thread)
Definition: ke_x.h:715
#define KxSingleThreadWait()
Definition: ke_x.h:1163
FORCEINLINE VOID KiReleaseDispatcherLock(IN KIRQL OldIrql)
Definition: ke_x.h:157
FORCEINLINE VOID KiCheckDeferredReadyList(IN PKPRCB Prcb)
Definition: ke_x.h:268
FORCEINLINE VOID KiSetThreadSwapBusy(IN PKTHREAD Thread)
Definition: ke_x.h:210
FORCEINLINE VOID KxRemoveTreeTimer(IN PKTIMER Timer)
Definition: ke_x.h:1004
FORCEINLINE PLARGE_INTEGER KiRecalculateDueTime(IN PLARGE_INTEGER OriginalDueTime, IN PLARGE_INTEGER DueTime, IN OUT PLARGE_INTEGER NewDueTime)
Definition: ke_x.h:785
#define KiAddThreadToWaitList(Thread, Swappable)
Definition: ke_x.h:824
FORCEINLINE VOID KiReleaseDispatcherLockFromSynchLevel(VOID)
Definition: ke_x.h:174
#define KxDelayThreadWait()
Definition: ke_x.h:1076
#define KxMultiThreadWait()
Definition: ke_x.h:1107
#define KiSatisfyNonMutantWait(Object)
Definition: ke_x.h:749
FORCEINLINE VOID KiAcquireDispatcherLockAtSynchLevel(VOID)
Definition: ke_x.h:165
FORCEINLINE VOID KiAcquirePrcbLock(IN PKPRCB Prcb)
Definition: ke_x.h:220
#define KiSatisfyObjectWait(Object, Thread)
Definition: ke_x.h:767
FORCEINLINE VOID KxInsertTimer(IN PKTIMER Timer, IN ULONG Hand)
Definition: ke_x.h:923
FORCEINLINE NTSTATUS KiCheckAlertability(IN PKTHREAD Thread, IN BOOLEAN Alertable, IN KPROCESSOR_MODE WaitMode)
Definition: ke_x.h:841
#define ASSERT(a)
Definition: mode.c:44
__int3264 LONG_PTR
Definition: mstsclib_h.h:276
FORCEINLINE struct _KPRCB * KeGetCurrentPrcb(VOID)
Definition: ketypes.h:1197
_In_ PVOID _In_ BOOLEAN Alertable
Definition: exfuncs.h:453
#define KernelMode
Definition: asm.h:38
@ QueueObject
Definition: ketypes.h:429
@ MutantObject
Definition: ketypes.h:427
@ Running
Definition: ketypes.h:409
@ Waiting
Definition: ketypes.h:412
@ AdjustUnwait
Definition: ketypes.h:459
DWORD Interval
Definition: netstat.c:28
#define _In_
Definition: no_sal2.h:158
int Count
Definition: noreturn.cpp:7
#define FASTCALL
Definition: nt_native.h:50
@ WaitAny
enum _WAIT_TYPE WAIT_TYPE
VOID FASTCALL KeWaitForGate(PKGATE Gate, KWAIT_REASON WaitReason, KPROCESSOR_MODE WaitMode)
VOID NTAPI KiReadyThread(IN PKTHREAD Thread)
Definition: thrdschd.c:502
BOOLEAN FASTCALL KiSwapContext(IN KIRQL WaitIrql, IN PKTHREAD CurrentThread)
VOID NTAPI KiAdjustQuantumThread(IN PKTHREAD Thread)
Definition: thrdschd.c:534
LONG_PTR FASTCALL KiSwapThread(IN PKTHREAD Thread, IN PKPRCB Prcb)
Definition: thrdschd.c:428
#define TIMER_WAIT_BLOCK
Definition: ke.h:169
VOID FASTCALL KiActivateWaiterQueue(IN PKQUEUE Queue)
Definition: queue.c:24
#define ExRaiseStatus
Definition: ntoskrnl.h:114
VOID NTAPI KiDeliverApc(IN KPROCESSOR_MODE DeliveryMode, IN PKEXCEPTION_FRAME ExceptionFrame, IN PKTRAP_FRAME TrapFrame)
Definition: apc.c:302
BOOLEAN NTAPI KeIsWaitListEmpty(_In_ PVOID Object)
Determines whether there are waiters waiting on the specified dispatcher object.
Definition: wait.c:283
VOID FASTCALL KiAcquireFastMutex(IN PFAST_MUTEX FastMutex)
Definition: wait.c:107
VOID FASTCALL KiAcquireGuardedMutex(IN OUT PKGUARDED_MUTEX GuardedMutex)
Definition: wait.c:122
NTSTATUS NTAPI KeWaitForMultipleObjects(IN ULONG Count, IN PVOID Object[], IN WAIT_TYPE WaitType, IN KWAIT_REASON WaitReason, IN KPROCESSOR_MODE WaitMode, IN BOOLEAN Alertable, IN PLARGE_INTEGER Timeout OPTIONAL, OUT PKWAIT_BLOCK WaitBlockArray OPTIONAL)
Definition: wait.c:599
VOID FASTCALL KiExitDispatcher(IN KIRQL OldIrql)
Definition: wait.c:199
NTSTATUS NTAPI NtDelayExecution(IN BOOLEAN Alertable, IN PLARGE_INTEGER DelayInterval)
Definition: wait.c:889
VOID FASTCALL KiUnwaitThread(IN PKTHREAD Thread, IN LONG_PTR WaitStatus, IN KPRIORITY Increment)
Definition: wait.c:89
VOID FASTCALL KiUnlinkThread(IN PKTHREAD Thread, IN LONG_PTR WaitStatus)
Definition: wait.c:55
VOID FASTCALL KiWaitTest(IN PVOID ObjectPointer, IN KPRIORITY Increment)
Definition: wait.c:20
#define STATUS_WAIT_0
Definition: ntstatus.h:330
#define STATUS_KERNEL_APC
Definition: ntstatus.h:132
#define STATUS_MUTANT_LIMIT_EXCEEDED
Definition: ntstatus.h:728
long LONG
Definition: pedump.c:60
static ULONG Timeout
Definition: ping.c:61
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:204
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:104
#define _SEH2_END
Definition: pseh2_64.h:194
#define _SEH2_TRY
Definition: pseh2_64.h:93
#define _SEH2_YIELD(__stmt)
Definition: pseh2_64.h:207
#define ProbeForReadLargeInteger(Ptr)
Definition: probe.h:75
#define KeQueryInterruptTime()
Definition: ke.h:37
FORCEINLINE VOID KeMemoryBarrier(VOID)
Definition: ke.h:58
#define STATUS_SUCCESS
Definition: shellext.h:65
WaitType
Definition: shlextdbg.cpp:568
signed char SCHAR
Definition: sqltypes.h:14
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
LIST_ENTRY WaitListHead
Definition: ketypes.h:876
DISPATCHER_HEADER Header
Definition: ketypes.h:909
struct _KTHREAD *RESTRICTED_POINTER OwnerThread
Definition: ketypes.h:911
struct _KTHREAD * CurrentThread
Definition: ketypes.h:670
struct _KTHREAD * NextThread
Definition: ketypes.h:671
UCHAR DpcRoutineActive
Definition: ketypes.h:792
volatile UCHAR State
Definition: ketypes.h:1936
struct _KTHREAD * Thread
Definition: ketypes.h:533
PVOID Object
Definition: ketypes.h:536
LIST_ENTRY WaitListEntry
Definition: ketypes.h:524
UCHAR WaitType
Definition: ketypes.h:526
USHORT WaitKey
Definition: ketypes.h:528
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
#define NTAPI
Definition: typedefs.h:36
uint64_t ULONGLONG
Definition: typedefs.h:67
#define IN
Definition: typedefs.h:39
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
#define MINLONG
Definition: umtypes.h:115
LONGLONG QuadPart
Definition: typedefs.h:114
_Must_inspect_result_ _In_ WDFCOLLECTION _In_ WDFOBJECT Object
_In_ WDFCOLLECTION _In_ ULONG Index
_In_ WDFTIMER _In_ LONGLONG DueTime
Definition: wdftimer.h:190
#define MAXIMUM_WAIT_OBJECTS
Definition: winbase.h:381
NTSYSAPI NTSTATUS WINAPI NtYieldExecution(void)
Definition: thrdschd.c:887
* PFAST_MUTEX
Definition: extypes.h:17
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:778
@ WrGuardedMutex
Definition: ketypes.h:502
@ WrMutex
Definition: ketypes.h:496
CCHAR KPROCESSOR_MODE
Definition: ketypes.h:7
#define GM_LOCK_WAITER_WOKEN
struct _KMUTANT * PKMUTANT
#define THREAD_WAIT_OBJECTS
Definition: ketypes.h:560
enum _KWAIT_REASON KWAIT_REASON
#define GM_LOCK_BIT
#define GM_LOCK_WAITER_INC