ReactOS 0.4.15-dev-7788-g1ad9096
wait.c File Reference
#include <ntoskrnl.h>
#include <debug.h>
Include dependency graph for wait.c:

Go to the source code of this file.

Macros

#define NDEBUG
 

Functions

VOID FASTCALL KiWaitTest (IN PVOID ObjectPointer, IN KPRIORITY Increment)
 
VOID FASTCALL KiUnlinkThread (IN PKTHREAD Thread, IN LONG_PTR WaitStatus)
 
VOID FASTCALL KiUnwaitThread (IN PKTHREAD Thread, IN LONG_PTR WaitStatus, IN KPRIORITY Increment)
 
VOID FASTCALL KiAcquireFastMutex (IN PFAST_MUTEX FastMutex)
 
VOID FASTCALL KiAcquireGuardedMutex (IN OUT PKGUARDED_MUTEX GuardedMutex)
 
VOID FASTCALL KiExitDispatcher (IN KIRQL OldIrql)
 
BOOLEAN NTAPI KeIsWaitListEmpty (IN PVOID Object)
 
NTSTATUS NTAPI KeDelayExecutionThread (IN KPROCESSOR_MODE WaitMode, IN BOOLEAN Alertable, IN PLARGE_INTEGER Interval OPTIONAL)
 
NTSTATUS NTAPI KeWaitForSingleObject (IN PVOID Object, IN KWAIT_REASON WaitReason, IN KPROCESSOR_MODE WaitMode, IN BOOLEAN Alertable, IN PLARGE_INTEGER Timeout OPTIONAL)
 
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)
 
NTSTATUS NTAPI NtDelayExecution (IN BOOLEAN Alertable, IN PLARGE_INTEGER DelayInterval)
 

Macro Definition Documentation

◆ NDEBUG

#define NDEBUG

Definition at line 13 of file wait.c.

Function Documentation

◆ KeDelayExecutionThread()

NTSTATUS NTAPI KeDelayExecutionThread ( IN KPROCESSOR_MODE  WaitMode,
IN BOOLEAN  Alertable,
IN PLARGE_INTEGER Interval  OPTIONAL 
)

Definition at line 283 of file wait.c.

286{
288 PKWAIT_BLOCK TimerBlock;
290 NTSTATUS WaitStatus;
291 BOOLEAN Swappable;
292 PLARGE_INTEGER OriginalDueTime;
293 LARGE_INTEGER DueTime, NewDueTime, InterruptTime;
294 ULONG Hand = 0;
295
296 if (Thread->WaitNext)
298 else
300
301 /* If this is a user-mode wait of 0 seconds, yield execution */
302 if (!(Interval->QuadPart) && (WaitMode != KernelMode))
303 {
304 /* Make sure the wait isn't alertable or interrupting an APC */
305 if (!(Alertable) && !(Thread->ApcState.UserApcPending))
306 {
307 /* Yield execution */
308 return NtYieldExecution();
309 }
310 }
311
312 /* Setup the original time and timer/wait blocks */
313 OriginalDueTime = Interval;
314 Timer = &Thread->Timer;
315 TimerBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
316
317 /* Check if the lock is already held */
318 if (!Thread->WaitNext) goto WaitStart;
319
320 /* Otherwise, we already have the lock, so initialize the wait */
321 Thread->WaitNext = FALSE;
323
324 /* Start wait loop */
325 for (;;)
326 {
327 /* Disable pre-emption */
328 Thread->Preempted = FALSE;
329
330 /* Check if a kernel APC is pending and we're below APC_LEVEL */
331 if ((Thread->ApcState.KernelApcPending) && !(Thread->SpecialApcDisable) &&
332 (Thread->WaitIrql < APC_LEVEL))
333 {
334 /* Unlock the dispatcher */
336 }
337 else
338 {
339 /* Check if we have to bail out due to an alerted state */
340 WaitStatus = KiCheckAlertability(Thread, Alertable, WaitMode);
341 if (WaitStatus != STATUS_WAIT_0) break;
342
343 /* Check if the timer expired */
344 InterruptTime.QuadPart = KeQueryInterruptTime();
345 if ((ULONGLONG)InterruptTime.QuadPart >= Timer->DueTime.QuadPart)
346 {
347 /* It did, so we don't need to wait */
348 goto NoWait;
349 }
350
351 /* It didn't, so activate it */
352 Timer->Header.Inserted = TRUE;
353
354 /* Handle Kernel Queues */
355 if (Thread->Queue) KiActivateWaiterQueue(Thread->Queue);
356
357 /* Setup the wait information */
358 Thread->State = Waiting;
359
360 /* Add the thread to the wait list */
361 KiAddThreadToWaitList(Thread, Swappable);
362
363 /* Insert the timer and swap the thread */
364 ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
366 KxInsertTimer(Timer, Hand);
368
369 /* Check if were swapped ok */
370 if (WaitStatus != STATUS_KERNEL_APC)
371 {
372 /* This is a good thing */
373 if (WaitStatus == STATUS_TIMEOUT) WaitStatus = STATUS_SUCCESS;
374
375 /* Return Status */
376 return WaitStatus;
377 }
378
379 /* Recalculate due times */
380 Interval = KiRecalculateDueTime(OriginalDueTime,
381 &DueTime,
382 &NewDueTime);
383 }
384
385WaitStart:
386 /* Setup a new wait */
387 Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
390 }
391
392 /* We're done! */
394 return WaitStatus;
395
396NoWait:
397 /* There was nothing to wait for. Did we have a wait interval? */
398 if (!Interval->QuadPart)
399 {
400 /* Unlock the dispatcher and do a yield */
402 return NtYieldExecution();
403 }
404
405 /* Unlock the dispatcher and adjust the quantum for a no-wait */
408 return STATUS_SUCCESS;
409}
unsigned char BOOLEAN
LONG NTSTATUS
Definition: precomp.h:26
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NTSTATUS
Definition: precomp.h:21
#define APC_LEVEL
Definition: env_spec_w32.h:695
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
KIRQL NTAPI KeRaiseIrqlToSynchLevel(VOID)
Definition: pic.c:156
#define KeGetCurrentThread
Definition: hal.h:55
NTSYSAPI NTSTATUS WINAPI NtYieldExecution(void)
Definition: thrdschd.c:744
FORCEINLINE VOID KiReleaseDispatcherLock(IN KIRQL OldIrql)
Definition: ke_x.h:157
FORCEINLINE VOID KiSetThreadSwapBusy(IN PKTHREAD Thread)
Definition: ke_x.h:210
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
FORCEINLINE VOID KiAcquireDispatcherLockAtSynchLevel(VOID)
Definition: ke_x.h:165
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
#define KernelMode
Definition: asm.h:34
FORCEINLINE struct _KPRCB * KeGetCurrentPrcb(VOID)
Definition: ketypes.h:1148
_In_ PVOID _In_ BOOLEAN Alertable
Definition: exfuncs.h:453
@ Waiting
Definition: ketypes.h:393
DWORD Interval
Definition: netstat.c:30
VOID NTAPI KiAdjustQuantumThread(IN PKTHREAD Thread)
Definition: thrdschd.c:461
LONG_PTR FASTCALL KiSwapThread(IN PKTHREAD Thread, IN PKPRCB Prcb)
Definition: thrdschd.c:355
#define TIMER_WAIT_BLOCK
Definition: ke.h:164
VOID FASTCALL KiActivateWaiterQueue(IN PKQUEUE Queue)
Definition: queue.c:24
#define STATUS_TIMEOUT
Definition: ntstatus.h:81
#define STATUS_WAIT_0
Definition: ntstatus.h:237
#define STATUS_KERNEL_APC
Definition: ntstatus.h:79
#define KeQueryInterruptTime()
Definition: ke.h:37
#define STATUS_SUCCESS
Definition: shellext.h:65
uint32_t ULONG
Definition: typedefs.h:59
uint64_t ULONGLONG
Definition: typedefs.h:67
LONGLONG QuadPart
Definition: typedefs.h:114
_In_ WDFTIMER _In_ LONGLONG DueTime
Definition: wdftimer.h:190

◆ KeIsWaitListEmpty()

BOOLEAN NTAPI KeIsWaitListEmpty ( IN PVOID  Object)

Definition at line 272 of file wait.c.

273{
275 return FALSE;
276}
#define UNIMPLEMENTED
Definition: debug.h:115

◆ KeWaitForMultipleObjects()

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 at line 586 of file wait.c.

594{
595 PKMUTANT CurrentObject;
596 PKWAIT_BLOCK WaitBlock;
598 PKWAIT_BLOCK TimerBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
599 PKTIMER Timer = &Thread->Timer;
600 NTSTATUS WaitStatus = STATUS_SUCCESS;
601 BOOLEAN Swappable;
602 PLARGE_INTEGER OriginalDueTime = Timeout;
603 LARGE_INTEGER DueTime = {{0}}, NewDueTime, InterruptTime;
604 ULONG Index, Hand = 0;
605
606 if (Thread->WaitNext)
608 else if (!Timeout || (Timeout->QuadPart != 0))
609 {
611 }
612 else
614
615 /* Make sure the Wait Count is valid */
616 if (!WaitBlockArray)
617 {
618 /* Check in regards to the Thread Object Limit */
620 {
621 /* Bugcheck */
622 KeBugCheck(MAXIMUM_WAIT_OBJECTS_EXCEEDED);
623 }
624
625 /* Use the Thread's Wait Block */
626 WaitBlockArray = &Thread->WaitBlock[0];
627 }
628 else
629 {
630 /* Using our own Block Array, so check with the System Object Limit */
632 {
633 /* Bugcheck */
634 KeBugCheck(MAXIMUM_WAIT_OBJECTS_EXCEEDED);
635 }
636 }
637
638 /* Sanity check */
639 ASSERT(Count != 0);
640
641 /* Check if the lock is already held */
642 if (!Thread->WaitNext) goto WaitStart;
643
644 /* Otherwise, we already have the lock, so initialize the wait */
645 Thread->WaitNext = FALSE;
646 /* Note that KxMultiThreadWait is a macro, defined in ke_x.h, that */
647 /* uses (and modifies some of) the following local */
648 /* variables: */
649 /* Thread, Index, WaitBlock, Timer, Timeout, Hand and Swappable. */
650 /* If it looks like this code doesn't actually wait for any objects */
651 /* at all, it's because the setup is done by that macro. */
653
654 /* Start wait loop */
655 for (;;)
656 {
657 /* Disable pre-emption */
658 Thread->Preempted = FALSE;
659
660 /* Check if a kernel APC is pending and we're below APC_LEVEL */
661 if ((Thread->ApcState.KernelApcPending) && !(Thread->SpecialApcDisable) &&
662 (Thread->WaitIrql < APC_LEVEL))
663 {
664 /* Unlock the dispatcher */
666 }
667 else
668 {
669 /* Check what kind of wait this is */
670 Index = 0;
671 if (WaitType == WaitAny)
672 {
673 /* Loop blocks */
674 do
675 {
676 /* Get the Current Object */
677 CurrentObject = (PKMUTANT)Object[Index];
678 ASSERT(CurrentObject->Header.Type != QueueObject);
679
680 /* Check if the Object is a mutant */
681 if (CurrentObject->Header.Type == MutantObject)
682 {
683 /* Check if it's signaled */
684 if ((CurrentObject->Header.SignalState > 0) ||
685 (Thread == CurrentObject->OwnerThread))
686 {
687 /* This is a Wait Any, so unwait this and exit */
688 if (CurrentObject->Header.SignalState !=
689 (LONG)MINLONG)
690 {
691 /* Normal signal state, unwait it and return */
692 KiSatisfyMutantWait(CurrentObject, Thread);
693 WaitStatus = (NTSTATUS)Thread->WaitStatus | Index;
694 goto DontWait;
695 }
696 else
697 {
698 /* Raise an exception (see wasm.ru) */
701 }
702 }
703 }
704 else if (CurrentObject->Header.SignalState > 0)
705 {
706 /* Another signaled object, unwait and return */
707 KiSatisfyNonMutantWait(CurrentObject);
708 WaitStatus = Index;
709 goto DontWait;
710 }
711
712 /* Go to the next block */
713 Index++;
714 } while (Index < Count);
715 }
716 else
717 {
718 /* Loop blocks */
719 do
720 {
721 /* Get the Current Object */
722 CurrentObject = (PKMUTANT)Object[Index];
723 ASSERT(CurrentObject->Header.Type != QueueObject);
724
725 /* Check if we're dealing with a mutant again */
726 if (CurrentObject->Header.Type == MutantObject)
727 {
728 /* Check if it has an invalid count */
729 if ((Thread == CurrentObject->OwnerThread) &&
730 (CurrentObject->Header.SignalState == (LONG)MINLONG))
731 {
732 /* Raise an exception */
735 }
736 else if ((CurrentObject->Header.SignalState <= 0) &&
737 (Thread != CurrentObject->OwnerThread))
738 {
739 /* We don't own it, can't satisfy the wait */
740 break;
741 }
742 }
743 else if (CurrentObject->Header.SignalState <= 0)
744 {
745 /* Not signaled, can't satisfy */
746 break;
747 }
748
749 /* Go to the next block */
750 Index++;
751 } while (Index < Count);
752
753 /* Check if we've went through all the objects */
754 if (Index == Count)
755 {
756 /* Loop wait blocks */
757 WaitBlock = WaitBlockArray;
758 do
759 {
760 /* Get the object and satisfy it */
761 CurrentObject = (PKMUTANT)WaitBlock->Object;
762 KiSatisfyObjectWait(CurrentObject, Thread);
763
764 /* Go to the next block */
765 WaitBlock = WaitBlock->NextWaitBlock;
766 } while(WaitBlock != WaitBlockArray);
767
768 /* Set the wait status and get out */
769 WaitStatus = (NTSTATUS)Thread->WaitStatus;
770 goto DontWait;
771 }
772 }
773
774 /* Make sure we can satisfy the Alertable request */
775 WaitStatus = KiCheckAlertability(Thread, Alertable, WaitMode);
776 if (WaitStatus != STATUS_WAIT_0) break;
777
778 /* Enable the Timeout Timer if there was any specified */
779 if (Timeout)
780 {
781 /* Check if the timer expired */
782 InterruptTime.QuadPart = KeQueryInterruptTime();
783 if ((ULONGLONG)InterruptTime.QuadPart >=
784 Timer->DueTime.QuadPart)
785 {
786 /* It did, so we don't need to wait */
787 WaitStatus = STATUS_TIMEOUT;
788 goto DontWait;
789 }
790
791 /* It didn't, so activate it */
792 Timer->Header.Inserted = TRUE;
793
794 /* Link the wait blocks */
795 WaitBlock->NextWaitBlock = TimerBlock;
796 }
797
798 /* Insert into Object's Wait List*/
799 WaitBlock = WaitBlockArray;
800 do
801 {
802 /* Get the Current Object */
803 CurrentObject = WaitBlock->Object;
804
805 /* Link the Object to this Wait Block */
806 InsertTailList(&CurrentObject->Header.WaitListHead,
807 &WaitBlock->WaitListEntry);
808
809 /* Move to the next Wait Block */
810 WaitBlock = WaitBlock->NextWaitBlock;
811 } while (WaitBlock != WaitBlockArray);
812
813 /* Handle Kernel Queues */
814 if (Thread->Queue) KiActivateWaiterQueue(Thread->Queue);
815
816 /* Setup the wait information */
817 Thread->State = Waiting;
818
819 /* Add the thread to the wait list */
820 KiAddThreadToWaitList(Thread, Swappable);
821
822 /* Activate thread swap */
823 ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
825
826 /* Check if we have a timer */
827 if (Timeout)
828 {
829 /* Insert it */
830 KxInsertTimer(Timer, Hand);
831 }
832 else
833 {
834 /* Otherwise, unlock the dispatcher */
836 }
837
838 /* Swap the thread */
840
841 /* Check if we were executing an APC */
842 if (WaitStatus != STATUS_KERNEL_APC) return WaitStatus;
843
844 /* Check if we had a timeout */
845 if (Timeout)
846 {
847 /* Recalculate due times */
848 Timeout = KiRecalculateDueTime(OriginalDueTime,
849 &DueTime,
850 &NewDueTime);
851 }
852 }
853
854WaitStart:
855 /* Setup a new wait */
856 Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
859 }
860
861 /* We are done */
863 return WaitStatus;
864
865DontWait:
866 /* Release dispatcher lock but maintain high IRQL */
868
869 /* Adjust the Quantum and return the wait status */
871 return WaitStatus;
872}
DECLSPEC_NORETURN VOID NTAPI KeBugCheck(ULONG BugCheckCode)
Definition: bug.c:1431
#define InsertTailList(ListHead, Entry)
#define SYNCH_LEVEL
Definition: env_spec_w32.h:704
_Must_inspect_result_ _In_ WAIT_TYPE _In_opt_ PLARGE_INTEGER _In_opt_ PKWAIT_BLOCK WaitBlockArray
Definition: fsrtlfuncs.h:1153
#define KiSatisfyMutantWait(Object, Thread)
Definition: ke_x.h:715
#define KxMultiThreadWait()
Definition: ke_x.h:1107
#define KiSatisfyNonMutantWait(Object)
Definition: ke_x.h:749
#define KiSatisfyObjectWait(Object, Thread)
Definition: ke_x.h:767
@ QueueObject
Definition: ketypes.h:410
@ MutantObject
Definition: ketypes.h:408
int Count
Definition: noreturn.cpp:7
@ WaitAny
#define ExRaiseStatus
Definition: ntoskrnl.h:114
#define STATUS_MUTANT_LIMIT_EXCEEDED
Definition: ntstatus.h:634
long LONG
Definition: pedump.c:60
static ULONG Timeout
Definition: ping.c:61
WaitType
Definition: shlextdbg.cpp:18
LIST_ENTRY WaitListHead
Definition: ketypes.h:808
DISPATCHER_HEADER Header
Definition: ketypes.h:841
struct _KTHREAD *RESTRICTED_POINTER OwnerThread
Definition: ketypes.h:843
PVOID Object
Definition: ketypes.h:468
LIST_ENTRY WaitListEntry
Definition: ketypes.h:456
#define MINLONG
Definition: umtypes.h:115
_Must_inspect_result_ _In_ WDFCOLLECTION _In_ WDFOBJECT Object
_In_ WDFCOLLECTION _In_ ULONG Index
#define MAXIMUM_WAIT_OBJECTS
Definition: winbase.h:404
struct _KMUTANT * PKMUTANT
#define THREAD_WAIT_OBJECTS
Definition: ketypes.h:492

Referenced by co_MsqSendMessage(), ExpWorkerThreadBalanceManager(), KeBalanceSetManager(), MiBalancerThread(), MmZeroPageThread(), NtUserWaitForInputIdle(), NtWaitForMultipleObjects(), PipeWorkerThread(), QueueThread(), RawInputThreadMain(), ReadBytes(), sys_arch_mbox_fetch(), sys_arch_sem_wait(), TdiCall(), TdiSendThread(), TestEventConcurrent(), and WaitForEventSafely().

◆ KeWaitForSingleObject()

NTSTATUS NTAPI KeWaitForSingleObject ( IN PVOID  Object,
IN KWAIT_REASON  WaitReason,
IN KPROCESSOR_MODE  WaitMode,
IN BOOLEAN  Alertable,
IN PLARGE_INTEGER Timeout  OPTIONAL 
)

Definition at line 416 of file wait.c.

421{
423 PKMUTANT CurrentObject = (PKMUTANT)Object;
424 PKWAIT_BLOCK WaitBlock = &Thread->WaitBlock[0];
425 PKWAIT_BLOCK TimerBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
426 PKTIMER Timer = &Thread->Timer;
427 NTSTATUS WaitStatus;
428 BOOLEAN Swappable;
429 LARGE_INTEGER DueTime = {{0}}, NewDueTime, InterruptTime;
430 PLARGE_INTEGER OriginalDueTime = Timeout;
431 ULONG Hand = 0;
432
433 if (Thread->WaitNext)
435 else
438 Timeout && Timeout->QuadPart == 0));
439
440 /* Check if the lock is already held */
441 if (!Thread->WaitNext) goto WaitStart;
442
443 /* Otherwise, we already have the lock, so initialize the wait */
444 Thread->WaitNext = FALSE;
446
447 /* Start wait loop */
448 for (;;)
449 {
450 /* Disable pre-emption */
451 Thread->Preempted = FALSE;
452
453 /* Check if a kernel APC is pending and we're below APC_LEVEL */
454 if ((Thread->ApcState.KernelApcPending) && !(Thread->SpecialApcDisable) &&
455 (Thread->WaitIrql < APC_LEVEL))
456 {
457 /* Unlock the dispatcher */
459 }
460 else
461 {
462 /* Sanity check */
463 ASSERT(CurrentObject->Header.Type != QueueObject);
464
465 /* Check if it's a mutant */
466 if (CurrentObject->Header.Type == MutantObject)
467 {
468 /* Check its signal state or if we own it */
469 if ((CurrentObject->Header.SignalState > 0) ||
470 (Thread == CurrentObject->OwnerThread))
471 {
472 /* Just unwait this guy and exit */
473 if (CurrentObject->Header.SignalState != MINLONG)
474 {
475 /* It has a normal signal state. Unwait and return */
476 KiSatisfyMutantWait(CurrentObject, Thread);
477 WaitStatus = (NTSTATUS)Thread->WaitStatus;
478 goto DontWait;
479 }
480 else
481 {
482 /* Raise an exception */
485 }
486 }
487 }
488 else if (CurrentObject->Header.SignalState > 0)
489 {
490 /* Another satisfied object */
491 KiSatisfyNonMutantWait(CurrentObject);
492 WaitStatus = STATUS_WAIT_0;
493 goto DontWait;
494 }
495
496 /* Make sure we can satisfy the Alertable request */
497 WaitStatus = KiCheckAlertability(Thread, Alertable, WaitMode);
498 if (WaitStatus != STATUS_WAIT_0) break;
499
500 /* Enable the Timeout Timer if there was any specified */
501 if (Timeout)
502 {
503 /* Check if the timer expired */
504 InterruptTime.QuadPart = KeQueryInterruptTime();
505 if ((ULONGLONG)InterruptTime.QuadPart >=
506 Timer->DueTime.QuadPart)
507 {
508 /* It did, so we don't need to wait */
509 WaitStatus = STATUS_TIMEOUT;
510 goto DontWait;
511 }
512
513 /* It didn't, so activate it */
514 Timer->Header.Inserted = TRUE;
515 }
516
517 /* Link the Object to this Wait Block */
518 InsertTailList(&CurrentObject->Header.WaitListHead,
519 &WaitBlock->WaitListEntry);
520
521 /* Handle Kernel Queues */
522 if (Thread->Queue) KiActivateWaiterQueue(Thread->Queue);
523
524 /* Setup the wait information */
525 Thread->State = Waiting;
526
527 /* Add the thread to the wait list */
528 KiAddThreadToWaitList(Thread, Swappable);
529
530 /* Activate thread swap */
531 ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
533
534 /* Check if we have a timer */
535 if (Timeout)
536 {
537 /* Insert it */
538 KxInsertTimer(Timer, Hand);
539 }
540 else
541 {
542 /* Otherwise, unlock the dispatcher */
544 }
545
546 /* Do the actual swap */
548
549 /* Check if we were executing an APC */
550 if (WaitStatus != STATUS_KERNEL_APC) return WaitStatus;
551
552 /* Check if we had a timeout */
553 if (Timeout)
554 {
555 /* Recalculate due times */
556 Timeout = KiRecalculateDueTime(OriginalDueTime,
557 &DueTime,
558 &NewDueTime);
559 }
560 }
561WaitStart:
562 /* Setup a new wait */
563 Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
566 }
567
568 /* Wait complete */
570 return WaitStatus;
571
572DontWait:
573 /* Release dispatcher lock but maintain high IRQL */
575
576 /* Adjust the Quantum and return the wait status */
578 return WaitStatus;
579}
#define KxSingleThreadWait()
Definition: ke_x.h:1163

◆ KiAcquireFastMutex()

VOID FASTCALL KiAcquireFastMutex ( IN PFAST_MUTEX  FastMutex)

Definition at line 107 of file wait.c.

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}
#define NULL
Definition: types.h:112
#define KeWaitForSingleObject(pEvt, foo, a, b, c)
Definition: env_spec_w32.h:478
@ WrMutex
Definition: ketypes.h:444

Referenced by _ExAcquireFastMutex(), and _ExAcquireFastMutexUnsafe().

◆ KiAcquireGuardedMutex()

VOID FASTCALL KiAcquireGuardedMutex ( IN OUT PKGUARDED_MUTEX  GuardedMutex)

Definition at line 122 of file wait.c.

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}
#define InterlockedCompareExchange
Definition: interlocked.h:104
#define C_ASSERT(e)
Definition: intsafe.h:73
VOID FASTCALL KeWaitForGate(PKGATE Gate, KWAIT_REASON WaitReason, KPROCESSOR_MODE WaitMode)
@ WrGuardedMutex
Definition: ketypes.h:450
#define GM_LOCK_WAITER_WOKEN
#define GM_LOCK_BIT
#define GM_LOCK_WAITER_INC

Referenced by _KeAcquireGuardedMutex(), and _KeAcquireGuardedMutexUnsafe().

◆ KiExitDispatcher()

VOID FASTCALL KiExitDispatcher ( IN KIRQL  OldIrql)

Definition at line 199 of file wait.c.

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}
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693
#define KeLowerIrql(oldIrql)
Definition: env_spec_w32.h:602
VOID FASTCALL HalRequestSoftwareInterrupt(IN KIRQL Irql)
Definition: pic.c:271
FORCEINLINE VOID KiCheckDeferredReadyList(IN PKPRCB Prcb)
Definition: ke_x.h:268
FORCEINLINE VOID KiAcquirePrcbLock(IN PKPRCB Prcb)
Definition: ke_x.h:220
@ Running
Definition: ketypes.h:390
BOOLEAN FASTCALL KiSwapContext(IN KIRQL WaitIrql, IN PKTHREAD CurrentThread)
VOID NTAPI KiDeliverApc(IN KPROCESSOR_MODE DeliveryMode, IN PKEXCEPTION_FRAME ExceptionFrame, IN PKTRAP_FRAME TrapFrame)
Definition: apc.c:302
UCHAR DpcRoutineActive
Definition: ketypes.h:758
struct _KTHREAD * CurrentThread
Definition: ketypes.h:636
struct _KTHREAD * NextThread
Definition: ketypes.h:637
volatile UCHAR State
Definition: ketypes.h:1789
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:778

◆ KiUnlinkThread()

VOID FASTCALL KiUnlinkThread ( IN PKTHREAD  Thread,
IN LONG_PTR  WaitStatus 
)

Definition at line 55 of file wait.c.

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}
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986
FORCEINLINE VOID KxRemoveTreeTimer(IN PKTIMER Timer)
Definition: ke_x.h:1004

Referenced by KeSetEventBoostPriority(), and KiUnwaitThread().

◆ KiUnwaitThread()

VOID FASTCALL KiUnwaitThread ( IN PKTHREAD  Thread,
IN LONG_PTR  WaitStatus,
IN KPRIORITY  Increment 
)

Definition at line 89 of file wait.c.

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}
IN OUT PLONG IN OUT PLONG Addend IN OUT PLONG IN LONG Increment
Definition: CrNtStubs.h:46
@ AdjustUnwait
Definition: ketypes.h:440
VOID NTAPI KiReadyThread(IN PKTHREAD Thread)
Definition: thrdschd.c:429
VOID FASTCALL KiUnlinkThread(IN PKTHREAD Thread, IN LONG_PTR WaitStatus)
Definition: wait.c:55
signed char SCHAR
Definition: sqltypes.h:14

Referenced by KeAlertResumeThread(), KeAlertThread(), KiActivateWaiterQueue(), KiInsertQueueApc(), KiWaitTest(), KxUnwaitThread(), and KxUnwaitThreadForEvent().

◆ KiWaitTest()

VOID FASTCALL KiWaitTest ( IN PVOID  ObjectPointer,
IN KPRIORITY  Increment 
)

Definition at line 20 of file wait.c.

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}
VOID FASTCALL KiUnwaitThread(IN PKTHREAD Thread, IN LONG_PTR WaitStatus, IN KPRIORITY Increment)
Definition: wait.c:89
struct _KTHREAD * Thread
Definition: ketypes.h:465
UCHAR WaitType
Definition: ketypes.h:458
USHORT WaitKey
Definition: ketypes.h:460
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260

◆ NtDelayExecution()

NTSTATUS NTAPI NtDelayExecution ( IN BOOLEAN  Alertable,
IN PLARGE_INTEGER  DelayInterval 
)

Definition at line 876 of file wait.c.

878{
880 LARGE_INTEGER SafeInterval;
882
883 /* Check the previous mode */
885 {
886 /* Enter SEH for probing */
888 {
889 /* Probe and capture the time out */
890 SafeInterval = ProbeForReadLargeInteger(DelayInterval);
891 DelayInterval = &SafeInterval;
892 }
894 {
895 /* Return the exception code */
897 }
898 _SEH2_END;
899 }
900
901 /* Call the Kernel Function */
903 Alertable,
904 DelayInterval);
905
906 /* Return Status */
907 return Status;
908}
#define KeDelayExecutionThread(mode, foo, t)
Definition: env_spec_w32.h:484
#define ExGetPreviousMode
Definition: ex.h:140
#define _SEH2_END
Definition: filesup.c:22
#define _SEH2_TRY
Definition: filesup.c:19
Status
Definition: gdiplustypes.h:25
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:159
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:34
#define _SEH2_YIELD(__stmt)
Definition: pseh2_64.h:162
#define ProbeForReadLargeInteger(Ptr)
Definition: probe.h:75
CCHAR KPROCESSOR_MODE
Definition: ketypes.h:7
_In_ KPROCESSOR_MODE PreviousMode
Definition: sefuncs.h:103

Referenced by CsrApiRequestThread(), NtProcessStartup(), RtlpInitializeThreadPool(), RtlpIoWorkerThreadProc(), RtlpStartWorkerThread(), SleepEx(), SmpApiLoop(), and SmpLoadSubSystemsForMuSession().