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)
10 /* INCLUDES ******************************************************************/
14 #include <internal/debug.h>
16 /* GLOBALS ******************************************************************/
18 KSPIN_LOCK DispatcherDatabaseLock
;
20 /* PRIVATE FUNCTIONS *********************************************************/
24 KiWaitSatisfyAll(PKWAIT_BLOCK FirstBlock
)
26 PKWAIT_BLOCK WaitBlock
= FirstBlock
;
27 PKTHREAD WaitThread
= WaitBlock
->Thread
;
29 /* Loop through all the Wait Blocks, and wake each Object */
32 /* Make sure it hasn't timed out */
33 if (WaitBlock
->WaitKey
!= STATUS_TIMEOUT
)
36 KiSatisfyObjectWait((PKMUTANT
)WaitBlock
->Object
, WaitThread
);
39 /* Move to the next block */
40 WaitBlock
= WaitBlock
->NextWaitBlock
;
41 } while (WaitBlock
!= FirstBlock
);
46 KiWaitTest(IN PVOID ObjectPointer
,
47 IN KPRIORITY Increment
)
49 PLIST_ENTRY WaitEntry
;
51 PKWAIT_BLOCK CurrentWaitBlock
;
52 PKWAIT_BLOCK NextWaitBlock
;
54 PKMUTANT FirstObject
= ObjectPointer
, Object
;
56 /* Loop the Wait Entries */
57 WaitList
= &FirstObject
->Header
.WaitListHead
;
58 WaitEntry
= WaitList
->Flink
;
59 while ((FirstObject
->Header
.SignalState
> 0) &&
60 (WaitEntry
!= WaitList
))
62 /* Get the current wait block */
63 CurrentWaitBlock
= CONTAINING_RECORD(WaitEntry
,
66 WaitThread
= CurrentWaitBlock
->Thread
;
68 /* Check the current Wait Mode */
69 if (CurrentWaitBlock
->WaitType
== WaitAny
)
71 /* Easy case, satisfy only this wait */
72 WaitEntry
= WaitEntry
->Blink
;
73 KiSatisfyObjectWait(FirstObject
, WaitThread
);
77 /* Everything must be satisfied */
78 NextWaitBlock
= CurrentWaitBlock
->NextWaitBlock
;
80 /* Loop first to make sure they are valid */
81 while (NextWaitBlock
!= CurrentWaitBlock
)
83 /* Make sure this isn't a timeout block */
84 if (NextWaitBlock
->WaitKey
!= STATUS_TIMEOUT
)
87 Object
= NextWaitBlock
->Object
;
89 /* Check if this is a mutant */
90 if ((Object
->Header
.Type
== MutantObject
) &&
91 (Object
->Header
.SignalState
<= 0) &&
92 (WaitThread
== Object
->OwnerThread
))
94 /* It's a signaled mutant */
96 else if (Object
->Header
.SignalState
<= 0)
98 /* Skip the unwaiting */
103 /* Go to the next Wait block */
104 NextWaitBlock
= NextWaitBlock
->NextWaitBlock
;
107 /* All the objects are signaled, we can satisfy */
108 WaitEntry
= WaitEntry
->Blink
;
109 KiWaitSatisfyAll(CurrentWaitBlock
);
112 /* All waits satisfied, unwait the thread */
113 KiAbortWaitThread(WaitThread
, CurrentWaitBlock
->WaitKey
, Increment
);
117 WaitEntry
= WaitEntry
->Flink
;
121 /* Must be called with the dispatcher lock held */
124 KiAbortWaitThread(IN PKTHREAD Thread
,
125 IN NTSTATUS WaitStatus
,
126 IN KPRIORITY Increment
)
128 PKWAIT_BLOCK WaitBlock
;
132 /* Update wait status */
133 Thread
->WaitStatus
|= WaitStatus
;
135 /* Remove the Wait Blocks from the list */
136 WaitBlock
= Thread
->WaitBlockList
;
140 RemoveEntryList(&WaitBlock
->WaitListEntry
);
142 /* Go to the next one */
143 WaitBlock
= WaitBlock
->NextWaitBlock
;
144 } while (WaitBlock
!= Thread
->WaitBlockList
);
146 /* Remove the thread from the wait list! */
147 if (Thread
->WaitListEntry
.Flink
) RemoveEntryList(&Thread
->WaitListEntry
);
149 /* Check if there's a Thread Timer */
150 Timer
= &Thread
->Timer
;
151 if (Timer
->Header
.Inserted
)
153 /* Remove the timer */
154 Timer
->Header
.Inserted
= FALSE
;
155 RemoveEntryList(&Timer
->TimerListEntry
);
156 //KiRemoveTimer(Timer);
159 /* Increment the Queue's active threads */
160 if (Thread
->Queue
) Thread
->Queue
->CurrentCount
++;
162 /* Check if this is a non-RT thread */
163 if (Thread
->Priority
< LOW_REALTIME_PRIORITY
)
165 /* Check if boosting is enabled and we can boost */
166 if (!(Thread
->DisableBoost
) && !(Thread
->PriorityDecrement
))
168 /* We can boost, so calculate the new priority */
169 NewPriority
= Thread
->BasePriority
+ Increment
;
170 if (NewPriority
> Thread
->Priority
)
172 /* Make sure the new priority wouldn't push the thread to RT */
173 if (NewPriority
>= LOW_REALTIME_PRIORITY
)
175 /* Set it just before the RT zone */
176 Thread
->Priority
= LOW_REALTIME_PRIORITY
- 1;
180 /* Otherwise, set our calculated priority */
181 Thread
->Priority
= NewPriority
;
186 /* Check if this is a high-priority thread */
187 if (Thread
->BasePriority
>= 14)
189 /* It is, simply reset the quantum */
190 Thread
->Quantum
= Thread
->QuantumReset
;
194 /* Otherwise, decrease quantum */
196 if (Thread
->Quantum
<= 0)
198 /* We've went below 0, reset it */
199 Thread
->Quantum
= Thread
->QuantumReset
;
201 /* Apply per-quantum priority decrement */
202 Thread
->Priority
-= (Thread
->PriorityDecrement
+ 1);
203 if (Thread
->Priority
< Thread
->BasePriority
)
205 /* We've went too low, reset it */
206 Thread
->Priority
= Thread
->BasePriority
;
209 /* Delete per-quantum decrement */
210 Thread
->PriorityDecrement
= 0;
216 /* For real time threads, just reset the quantum */
217 Thread
->Quantum
= Thread
->QuantumReset
;
220 /* Reschedule the Thread */
221 KiReadyThread(Thread
);
226 KiAcquireFastMutex(IN PFAST_MUTEX FastMutex
)
228 /* Increase contention count */
229 FastMutex
->Contention
++;
231 /* Wait for the event */
232 KeWaitForSingleObject(&FastMutex
->Gate
,
240 // This routine exits the dispatcher after a compatible operation and
241 // swaps the context to the next scheduled thread on the current CPU if
244 // It does NOT attempt to scan for a new thread to schedule.
248 KiExitDispatcher(IN KIRQL OldIrql
)
250 PKPRCB Prcb
= KeGetCurrentPrcb();
251 PKTHREAD Thread
, NextThread
;
254 /* Make sure we're at synchronization level */
255 ASSERT_IRQL(SYNCH_LEVEL
);
257 /* Check if we have deferred threads */
258 KiCheckDeferredReadyList(Prcb
);
260 /* Check if we were called at dispatcher level or higher */
261 if (OldIrql
>= DISPATCH_LEVEL
)
263 /* Check if we have a thread to schedule, and that no DPC is active */
264 if ((Prcb
->NextThread
) && !(Prcb
->DpcRoutineActive
))
266 /* Request DPC interrupt */
267 HalRequestSoftwareInterrupt(DISPATCH_LEVEL
);
270 /* Lower IRQL and exit */
274 /* Make sure there's a new thread scheduled */
275 if (!Prcb
->NextThread
) goto Quickie
;
277 /* This shouldn't happen on ROS yet */
278 DPRINT1("The impossible happened - Tell Alex\n");
282 KiAcquirePrcbLock(Prcb
);
284 /* Get the next and current threads now */
285 NextThread
= Prcb
->NextThread
;
286 Thread
= Prcb
->CurrentThread
;
288 /* Set current thread's swap busy to true */
289 KiSetThreadSwapBusy(Thread
);
291 /* Switch threads in PRCB */
292 Prcb
->NextThread
= NULL
;
293 Prcb
->CurrentThread
= NextThread
;
295 /* Set thread to running */
296 NextThread
->State
= Running
;
298 /* Queue it on the ready lists */
299 KxQueueReadyThread(Thread
, Prcb
);
302 Thread
->WaitIrql
= OldIrql
;
304 /* Swap threads and check if APCs were pending */
305 PendingApc
= KiSwapContext(Thread
, NextThread
);
308 /* Lower only to APC */
309 KeLowerIrql(APC_LEVEL
);
312 KiDeliverApc(KernelMode
, NULL
, NULL
);
313 ASSERT(OldIrql
== PASSIVE_LEVEL
);
316 /* Lower IRQl back */
318 KeLowerIrql(OldIrql
);
321 /* PUBLIC FUNCTIONS **********************************************************/
328 KeDelayExecutionThread(IN KPROCESSOR_MODE WaitMode
,
329 IN BOOLEAN Alertable
,
330 IN PLARGE_INTEGER Interval OPTIONAL
)
332 PKWAIT_BLOCK TimerWaitBlock
;
334 PKTHREAD CurrentThread
= KeGetCurrentThread();
335 NTSTATUS WaitStatus
= STATUS_SUCCESS
;
337 PLARGE_INTEGER OriginalDueTime
= Interval
;
338 LARGE_INTEGER DueTime
, NewDueTime
;
340 /* Check if the lock is already held */
341 if (CurrentThread
->WaitNext
)
343 /* Lock is held, disable Wait Next */
344 CurrentThread
->WaitNext
= FALSE
;
348 /* Lock not held, acquire it */
349 CurrentThread
->WaitIrql
= KiAcquireDispatcherLock();
352 /* Use built-in Wait block */
353 TimerWaitBlock
= &CurrentThread
->WaitBlock
[TIMER_WAIT_BLOCK
];
355 /* Start Wait Loop */
358 /* Check if a kernel APC is pending and we're below APC_LEVEL */
359 if ((CurrentThread
->ApcState
.KernelApcPending
) &&
360 !(CurrentThread
->SpecialApcDisable
) &&
361 (CurrentThread
->WaitIrql
< APC_LEVEL
))
363 /* Unlock the dispatcher */
364 KiReleaseDispatcherLock(CurrentThread
->WaitIrql
);
368 /* Check if we can do an alertable wait, if requested */
369 KiCheckAlertability();
371 /* Check if we can swap the thread's stack */
372 CurrentThread
->WaitListEntry
.Flink
= NULL
;
373 KiCheckThreadStackSwap(WaitMode
, CurrentThread
, Swappable
);
376 CurrentThread
->WaitStatus
= STATUS_WAIT_0
;
379 ThreadTimer
= &CurrentThread
->Timer
;
381 /* Setup the Wait Block */
382 CurrentThread
->WaitBlockList
= TimerWaitBlock
;
383 TimerWaitBlock
->NextWaitBlock
= TimerWaitBlock
;
385 /* Link the timer to this Wait Block */
386 ThreadTimer
->Header
.WaitListHead
.Flink
=
387 &TimerWaitBlock
->WaitListEntry
;
388 ThreadTimer
->Header
.WaitListHead
.Blink
=
389 &TimerWaitBlock
->WaitListEntry
;
391 /* Insert the Timer into the Timer Lists and enable it */
392 if (!KiInsertTimer(ThreadTimer
, *Interval
))
394 /* FIXME: We should find a new ready thread */
395 WaitStatus
= STATUS_SUCCESS
;
400 DueTime
.QuadPart
= ThreadTimer
->DueTime
.QuadPart
;
402 /* Handle Kernel Queues */
403 if (CurrentThread
->Queue
) KiWakeQueue(CurrentThread
->Queue
);
405 /* Setup the wait information */
406 CurrentThread
->Alertable
= Alertable
;
407 CurrentThread
->WaitMode
= WaitMode
;
408 CurrentThread
->WaitReason
= DelayExecution
;
409 CurrentThread
->WaitTime
= ((PLARGE_INTEGER
)&KeTickCount
)->LowPart
;
410 CurrentThread
->State
= Waiting
;
412 /* Find a new thread to run */
413 KiAddThreadToWaitList(CurrentThread
, Swappable
);
414 WaitStatus
= KiSwapThread(CurrentThread
, KeGetCurrentPrcb());
415 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
417 /* Check if we were executing an APC or if we timed out */
418 if (WaitStatus
!= STATUS_KERNEL_APC
)
420 /* This is a good thing */
421 if (WaitStatus
== STATUS_TIMEOUT
) WaitStatus
= STATUS_SUCCESS
;
427 /* Recalculate due times */
428 Interval
= KiRecalculateDueTime(OriginalDueTime
,
433 /* Acquire again the lock */
434 CurrentThread
->WaitIrql
= KiAcquireDispatcherLock();
437 /* Release the Lock, we are done */
438 KiReleaseDispatcherLock(CurrentThread
->WaitIrql
);
447 KeWaitForSingleObject(IN PVOID Object
,
448 IN KWAIT_REASON WaitReason
,
449 IN KPROCESSOR_MODE WaitMode
,
450 IN BOOLEAN Alertable
,
451 IN PLARGE_INTEGER Timeout OPTIONAL
)
453 PKMUTANT CurrentObject
;
454 PKWAIT_BLOCK WaitBlock
;
455 PKWAIT_BLOCK TimerWaitBlock
;
457 PKTHREAD CurrentThread
= KeGetCurrentThread();
458 NTSTATUS WaitStatus
= STATUS_SUCCESS
;
460 LARGE_INTEGER DueTime
, NewDueTime
;
461 PLARGE_INTEGER OriginalDueTime
= Timeout
;
463 /* Check if the lock is already held */
464 if (CurrentThread
->WaitNext
)
466 /* Lock is held, disable Wait Next */
467 CurrentThread
->WaitNext
= FALSE
;
471 /* Lock not held, acquire it */
472 CurrentThread
->WaitIrql
= KiAcquireDispatcherLock();
475 /* Start the actual Loop */
476 WaitBlock
= &CurrentThread
->WaitBlock
[0];
479 /* Check if a kernel APC is pending and we're below APC_LEVEL */
480 if ((CurrentThread
->ApcState
.KernelApcPending
) &&
481 !(CurrentThread
->SpecialApcDisable
) &&
482 (CurrentThread
->WaitIrql
< APC_LEVEL
))
484 /* Unlock the dispatcher */
485 KiReleaseDispatcherLock(CurrentThread
->WaitIrql
);
489 /* Set default status */
490 CurrentThread
->WaitStatus
= STATUS_WAIT_0
;
492 /* Get the Current Object */
493 CurrentObject
= (PKMUTANT
)Object
;
495 /* Check if it's a mutant */
496 if (CurrentObject
->Header
.Type
== MutantObject
)
498 /* Check its signal state or if we own it */
499 if ((CurrentObject
->Header
.SignalState
> 0) ||
500 (CurrentThread
== CurrentObject
->OwnerThread
))
502 /* Just unwait this guy and exit */
503 if (CurrentObject
->Header
.SignalState
!= (LONG
)MINLONG
)
505 /* It has a normal signal state. Unwait and return */
506 KiSatisfyMutantWait(CurrentObject
, CurrentThread
);
507 WaitStatus
= CurrentThread
->WaitStatus
;
512 /* Raise an exception (see wasm.ru) */
513 KiReleaseDispatcherLock(CurrentThread
->
515 ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED
);
519 else if (CurrentObject
->Header
.SignalState
> 0)
521 /* Another satisfied object */
522 KiSatisfyNonMutantWait(CurrentObject
, CurrentThread
);
523 WaitStatus
= STATUS_WAIT_0
;
527 /* Append wait block to the KTHREAD wait block list */
528 CurrentThread
->WaitBlockList
= WaitBlock
;
530 /* Set up the Wait Block */
531 WaitBlock
->Object
= CurrentObject
;
532 WaitBlock
->WaitKey
= (USHORT
)(STATUS_SUCCESS
);
533 WaitBlock
->WaitType
= WaitAny
;
535 /* Make sure we can satisfy the Alertable request */
536 KiCheckAlertability();
538 /* Check if we can swap the thread's stack */
539 CurrentThread
->WaitListEntry
.Flink
= NULL
;
540 KiCheckThreadStackSwap(WaitMode
, CurrentThread
, Swappable
);
542 /* Enable the Timeout Timer if there was any specified */
545 /* Fail if the timeout interval is actually 0 */
546 if (!Timeout
->QuadPart
)
548 /* Return a timeout */
549 WaitStatus
= STATUS_TIMEOUT
;
553 /* Point to Timer Wait Block and Thread Timer */
554 TimerWaitBlock
= &CurrentThread
->WaitBlock
[TIMER_WAIT_BLOCK
];
555 ThreadTimer
= &CurrentThread
->Timer
;
557 /* Connect the Timer Wait Block */
558 WaitBlock
->NextWaitBlock
= TimerWaitBlock
;
560 /* Set up the Timer Wait Block */
561 TimerWaitBlock
->NextWaitBlock
= WaitBlock
;
563 /* Link the timer to this Wait Block */
564 ThreadTimer
->Header
.WaitListHead
.Flink
=
565 &TimerWaitBlock
->WaitListEntry
;
566 ThreadTimer
->Header
.WaitListHead
.Blink
=
567 &TimerWaitBlock
->WaitListEntry
;
569 /* Insert the Timer into the Timer Lists and enable it */
570 if (!KiInsertTimer(ThreadTimer
, *Timeout
))
572 /* Return a timeout if we couldn't insert the timer */
573 WaitStatus
= STATUS_TIMEOUT
;
577 /* Set the current due time */
578 DueTime
.QuadPart
= ThreadTimer
->DueTime
.QuadPart
;
582 /* No timer block, so just set our wait block as next */
583 WaitBlock
->NextWaitBlock
= WaitBlock
;
586 /* Link the Object to this Wait Block */
587 InsertTailList(&CurrentObject
->Header
.WaitListHead
,
588 &WaitBlock
->WaitListEntry
);
590 /* Handle Kernel Queues */
591 if (CurrentThread
->Queue
) KiWakeQueue(CurrentThread
->Queue
);
593 /* Setup the wait information */
594 CurrentThread
->Alertable
= Alertable
;
595 CurrentThread
->WaitMode
= WaitMode
;
596 CurrentThread
->WaitReason
= WaitReason
;
597 CurrentThread
->WaitTime
= ((PLARGE_INTEGER
)&KeTickCount
)->LowPart
;
598 CurrentThread
->State
= Waiting
;
600 /* Find a new thread to run */
601 KiAddThreadToWaitList(CurrentThread
, Swappable
);
602 WaitStatus
= KiSwapThread(CurrentThread
, KeGetCurrentPrcb());
603 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
605 /* Check if we were executing an APC */
606 if (WaitStatus
!= STATUS_KERNEL_APC
) return WaitStatus
;
608 /* Check if we had a timeout */
611 /* Recalculate due times */
612 Timeout
= KiRecalculateDueTime(OriginalDueTime
,
618 /* Acquire again the lock */
619 CurrentThread
->WaitIrql
= KiAcquireDispatcherLock();
622 /* Release the Lock, we are done */
623 KiReleaseDispatcherLock(CurrentThread
->WaitIrql
);
627 /* Adjust the Quantum */
628 KiAdjustQuantumThread(CurrentThread
);
630 /* Release & Return */
631 KiReleaseDispatcherLock(CurrentThread
->WaitIrql
);
640 KeWaitForMultipleObjects(IN ULONG Count
,
642 IN WAIT_TYPE WaitType
,
643 IN KWAIT_REASON WaitReason
,
644 IN KPROCESSOR_MODE WaitMode
,
645 IN BOOLEAN Alertable
,
646 IN PLARGE_INTEGER Timeout OPTIONAL
,
647 OUT PKWAIT_BLOCK WaitBlockArray OPTIONAL
)
649 PKMUTANT CurrentObject
;
650 PKWAIT_BLOCK WaitBlock
;
651 PKWAIT_BLOCK TimerWaitBlock
;
653 PKTHREAD CurrentThread
= KeGetCurrentThread();
654 ULONG AllObjectsSignaled
;
656 NTSTATUS WaitStatus
= STATUS_SUCCESS
;
658 PLARGE_INTEGER OriginalDueTime
= Timeout
;
659 LARGE_INTEGER DueTime
, NewDueTime
;
661 /* Set the Current Thread */
662 CurrentThread
= KeGetCurrentThread();
664 /* Check if the lock is already held */
665 if (CurrentThread
->WaitNext
)
667 /* Lock is held, disable Wait Next */
668 CurrentThread
->WaitNext
= FALSE
;
672 /* Lock not held, acquire it */
673 CurrentThread
->WaitIrql
= KiAcquireDispatcherLock();
676 /* Make sure the Wait Count is valid */
679 /* Check in regards to the Thread Object Limit */
680 if (Count
> THREAD_WAIT_OBJECTS
)
683 KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED
);
686 /* Use the Thread's Wait Block */
687 WaitBlockArray
= &CurrentThread
->WaitBlock
[0];
691 /* Using our own Block Array, so check with the System Object Limit */
692 if (Count
> MAXIMUM_WAIT_OBJECTS
)
695 KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED
);
699 /* Start the actual Loop */
702 /* Check if a kernel APC is pending and we're below APC_LEVEL */
703 if ((CurrentThread
->ApcState
.KernelApcPending
) &&
704 !(CurrentThread
->SpecialApcDisable
) &&
705 (CurrentThread
->WaitIrql
< APC_LEVEL
))
707 /* Unlock the dispatcher */
708 KiReleaseDispatcherLock(CurrentThread
->WaitIrql
);
712 /* Append wait block to the KTHREAD wait block list */
713 CurrentThread
->WaitBlockList
= WaitBlock
= WaitBlockArray
;
715 /* Set default wait status */
716 CurrentThread
->WaitStatus
= STATUS_WAIT_0
;
718 /* Check if the wait is (already) satisfied */
719 AllObjectsSignaled
= TRUE
;
721 /* First, we'll try to satisfy the wait directly */
722 for (WaitIndex
= 0; WaitIndex
< Count
; WaitIndex
++)
724 /* Get the Current Object */
725 CurrentObject
= (PKMUTANT
)Object
[WaitIndex
];
727 /* Check the type of wait */
728 if (WaitType
== WaitAny
)
730 /* Check if the Object is a mutant */
731 if (CurrentObject
->Header
.Type
== MutantObject
)
733 /* Check if it's signaled */
734 if ((CurrentObject
->Header
.SignalState
> 0) ||
735 (CurrentThread
== CurrentObject
->OwnerThread
))
737 /* This is a Wait Any, so unwait this and exit */
738 if (CurrentObject
->Header
.SignalState
!=
741 /* Normal signal state, unwait it and return */
742 KiSatisfyMutantWait(CurrentObject
,
744 WaitStatus
= CurrentThread
->WaitStatus
|
750 /* Raise an exception (see wasm.ru) */
751 KiReleaseDispatcherLock(CurrentThread
->
753 ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED
);
757 else if (CurrentObject
->Header
.SignalState
> 0)
759 /* Another signaled object, unwait and return */
760 KiSatisfyNonMutantWait(CurrentObject
, CurrentThread
);
761 WaitStatus
= WaitIndex
;
767 /* Check if we're dealing with a mutant again */
768 if (CurrentObject
->Header
.Type
== MutantObject
)
770 /* Check if it has an invalid count */
771 if ((CurrentThread
== CurrentObject
->OwnerThread
) &&
772 (CurrentObject
->Header
.SignalState
== MINLONG
))
774 /* Raise an exception */
775 KiReleaseDispatcherLock(CurrentThread
->
777 ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED
);
779 else if ((CurrentObject
->Header
.SignalState
<= 0) &&
780 (CurrentThread
!= CurrentObject
->OwnerThread
))
782 /* We don't own it, can't satisfy the wait */
783 AllObjectsSignaled
= FALSE
;
786 else if (CurrentObject
->Header
.SignalState
<= 0)
788 /* Not signaled, can't satisfy */
789 AllObjectsSignaled
= FALSE
;
793 /* Set up a Wait Block for this Object */
794 WaitBlock
->Object
= CurrentObject
;
795 WaitBlock
->Thread
= CurrentThread
;
796 WaitBlock
->WaitKey
= (USHORT
)WaitIndex
;
797 WaitBlock
->WaitType
= (USHORT
)WaitType
;
798 WaitBlock
->NextWaitBlock
= WaitBlock
+ 1;
800 /* Move to the next Wait Block */
801 WaitBlock
= WaitBlock
->NextWaitBlock
;
804 /* Return to the Root Wait Block */
806 WaitBlock
->NextWaitBlock
= WaitBlockArray
;
808 /* Check if this is a Wait All and all the objects are signaled */
809 if ((WaitType
== WaitAll
) && (AllObjectsSignaled
))
811 /* Return to the Root Wait Block */
812 WaitBlock
= CurrentThread
->WaitBlockList
;
814 /* Satisfy their Waits and return to the caller */
815 KiWaitSatisfyAll(WaitBlock
);
816 WaitStatus
= CurrentThread
->WaitStatus
;
820 /* Make sure we can satisfy the Alertable request */
821 KiCheckAlertability();
823 /* Check if we can swap the thread's stack */
824 CurrentThread
->WaitListEntry
.Flink
= NULL
;
825 KiCheckThreadStackSwap(WaitMode
, CurrentThread
, Swappable
);
827 /* Enable the Timeout Timer if there was any specified */
830 /* Make sure the timeout interval isn't actually 0 */
831 if (!Timeout
->QuadPart
)
833 /* Return a timeout */
834 WaitStatus
= STATUS_TIMEOUT
;
838 /* Point to Timer Wait Block and Thread Timer */
839 TimerWaitBlock
= &CurrentThread
->WaitBlock
[TIMER_WAIT_BLOCK
];
840 ThreadTimer
= &CurrentThread
->Timer
;
842 /* Connect the Timer Wait Block */
843 WaitBlock
->NextWaitBlock
= TimerWaitBlock
;
845 /* Set up the Timer Wait Block */
846 TimerWaitBlock
->NextWaitBlock
= WaitBlockArray
;
848 /* Initialize the list head */
849 InitializeListHead(&ThreadTimer
->Header
.WaitListHead
);
851 /* Insert the Timer into the Timer Lists and enable it */
852 if (!KiInsertTimer(ThreadTimer
, *Timeout
))
854 /* Return a timeout if we couldn't insert the timer */
855 WaitStatus
= STATUS_TIMEOUT
;
859 /* Set the current due time */
860 DueTime
.QuadPart
= ThreadTimer
->DueTime
.QuadPart
;
863 /* Insert into Object's Wait List*/
864 WaitBlock
= CurrentThread
->WaitBlockList
;
867 /* Get the Current Object */
868 CurrentObject
= WaitBlock
->Object
;
870 /* Link the Object to this Wait Block */
871 InsertTailList(&CurrentObject
->Header
.WaitListHead
,
872 &WaitBlock
->WaitListEntry
);
874 /* Move to the next Wait Block */
875 WaitBlock
= WaitBlock
->NextWaitBlock
;
876 } while (WaitBlock
!= WaitBlockArray
);
878 /* Handle Kernel Queues */
879 if (CurrentThread
->Queue
) KiWakeQueue(CurrentThread
->Queue
);
881 /* Setup the wait information */
882 CurrentThread
->Alertable
= Alertable
;
883 CurrentThread
->WaitMode
= WaitMode
;
884 CurrentThread
->WaitReason
= WaitReason
;
885 CurrentThread
->WaitTime
= ((PLARGE_INTEGER
)&KeTickCount
)->LowPart
;
886 CurrentThread
->State
= Waiting
;
888 /* Find a new thread to run */
889 KiAddThreadToWaitList(CurrentThread
, Swappable
);
890 WaitStatus
= KiSwapThread(CurrentThread
, KeGetCurrentPrcb());
891 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
893 /* Check if we were executing an APC */
894 if (WaitStatus
!= STATUS_KERNEL_APC
) return WaitStatus
;
896 /* Check if we had a timeout */
899 /* Recalculate due times */
900 Timeout
= KiRecalculateDueTime(OriginalDueTime
,
905 /* Acquire again the lock */
906 CurrentThread
->WaitIrql
= KiAcquireDispatcherLock();
910 /* Release the Lock, we are done */
911 KiReleaseDispatcherLock(CurrentThread
->WaitIrql
);
915 /* Adjust the Quantum */
916 KiAdjustQuantumThread(CurrentThread
);
918 /* Release & Return */
919 KiReleaseDispatcherLock(CurrentThread
->WaitIrql
);
925 NtDelayExecution(IN BOOLEAN Alertable
,
926 IN PLARGE_INTEGER DelayInterval
)
928 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
929 LARGE_INTEGER SafeInterval
;
930 NTSTATUS Status
= STATUS_SUCCESS
;
932 /* Check if parameters are valid */
933 if(PreviousMode
!= KernelMode
)
937 /* make a copy on the kernel stack and let DelayInterval point to it so
938 we don't need to wrap KeDelayExecutionThread in SEH! */
939 SafeInterval
= ProbeForReadLargeInteger(DelayInterval
);
940 DelayInterval
= &SafeInterval
;
944 Status
= _SEH_GetExceptionCode();
948 if (!NT_SUCCESS(Status
)) return Status
;
951 /* Call the Kernel Function */
952 Status
= KeDelayExecutionThread(PreviousMode
,