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 /* FIXME: Remove the thread from the wait list! */
147 //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
,
241 KiExitDispatcher(IN KIRQL OldIrql
)
243 /* Check if it's the idle thread */
244 if (!(KeIsExecutingDpc()) &&
245 (OldIrql
< DISPATCH_LEVEL
) &&
246 (KeGetCurrentThread()) &&
247 (KeGetCurrentThread() == KeGetCurrentPrcb()->IdleThread
))
249 /* Dispatch a new thread */
250 KiDispatchThreadNoLock(Ready
);
254 /* Otherwise just release the lock */
255 KeReleaseDispatcherDatabaseLockFromDpcLevel();
258 /* Lower irql back */
259 KeLowerIrql(OldIrql
);
262 /* PUBLIC FUNCTIONS **********************************************************/
269 KeDelayExecutionThread(IN KPROCESSOR_MODE WaitMode
,
270 IN BOOLEAN Alertable
,
271 IN PLARGE_INTEGER Interval OPTIONAL
)
273 PKWAIT_BLOCK TimerWaitBlock
;
275 PKTHREAD CurrentThread
= KeGetCurrentThread();
276 NTSTATUS WaitStatus
= STATUS_SUCCESS
;
278 /* Check if the lock is already held */
279 if (CurrentThread
->WaitNext
)
281 /* Lock is held, disable Wait Next */
282 CurrentThread
->WaitNext
= FALSE
;
286 /* Lock not held, acquire it */
287 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
290 /* Use built-in Wait block */
291 TimerWaitBlock
= &CurrentThread
->WaitBlock
[TIMER_WAIT_BLOCK
];
293 /* Start Wait Loop */
296 /* Check if a kernel APC is pending and we're below APC_LEVEL */
297 if ((CurrentThread
->ApcState
.KernelApcPending
) &&
298 !(CurrentThread
->SpecialApcDisable
) &&
299 (CurrentThread
->WaitIrql
< APC_LEVEL
))
301 /* Unlock the dispatcher */
302 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
306 /* Check if we can do an alertable wait, if requested */
307 KiCheckAlertability();
310 CurrentThread
->WaitStatus
= STATUS_WAIT_0
;
313 ThreadTimer
= &CurrentThread
->Timer
;
315 /* Setup the Wait Block */
316 CurrentThread
->WaitBlockList
= TimerWaitBlock
;
317 TimerWaitBlock
->NextWaitBlock
= TimerWaitBlock
;
319 /* Link the timer to this Wait Block */
320 ThreadTimer
->Header
.WaitListHead
.Flink
=
321 &TimerWaitBlock
->WaitListEntry
;
322 ThreadTimer
->Header
.WaitListHead
.Blink
=
323 &TimerWaitBlock
->WaitListEntry
;
325 /* Insert the Timer into the Timer Lists and enable it */
326 if (!KiInsertTimer(ThreadTimer
, *Interval
))
328 /* FIXME: We should find a new ready thread */
329 WaitStatus
= STATUS_SUCCESS
;
333 /* Handle Kernel Queues */
334 if (CurrentThread
->Queue
) KiWakeQueue(CurrentThread
->Queue
);
336 /* Setup the wait information */
337 CurrentThread
->Alertable
= Alertable
;
338 CurrentThread
->WaitMode
= WaitMode
;
339 CurrentThread
->WaitReason
= DelayExecution
;
340 CurrentThread
->WaitTime
= ((PLARGE_INTEGER
)&KeTickCount
)->LowPart
;
341 CurrentThread
->State
= Waiting
;
343 /* Find a new thread to run */
344 WaitStatus
= KiSwapThread();
345 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
347 /* Check if we were executing an APC or if we timed out */
348 if (WaitStatus
!= STATUS_KERNEL_APC
)
350 /* This is a good thing */
351 if (WaitStatus
== STATUS_TIMEOUT
) WaitStatus
= STATUS_SUCCESS
;
357 /* FIXME: Fixup interval */
360 /* Acquire again the lock */
361 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
364 /* Release the Lock, we are done */
365 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
374 KeWaitForSingleObject(PVOID Object
,
375 KWAIT_REASON WaitReason
,
376 KPROCESSOR_MODE WaitMode
,
378 PLARGE_INTEGER Timeout
)
380 PKMUTANT CurrentObject
;
381 PKWAIT_BLOCK WaitBlock
;
382 PKWAIT_BLOCK TimerWaitBlock
;
384 PKTHREAD CurrentThread
= KeGetCurrentThread();
385 NTSTATUS WaitStatus
= STATUS_SUCCESS
;
387 /* Check if the lock is already held */
388 if (CurrentThread
->WaitNext
)
390 /* Lock is held, disable Wait Next */
391 CurrentThread
->WaitNext
= FALSE
;
395 /* Lock not held, acquire it */
396 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
399 /* Start the actual Loop */
402 /* Check if a kernel APC is pending and we're below APC_LEVEL */
403 if ((CurrentThread
->ApcState
.KernelApcPending
) &&
404 !(CurrentThread
->SpecialApcDisable
) &&
405 (CurrentThread
->WaitIrql
< APC_LEVEL
))
407 /* Unlock the dispatcher */
408 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
412 /* Set default status */
413 CurrentThread
->WaitStatus
= STATUS_WAIT_0
;
415 /* Append wait block to the KTHREAD wait block list */
416 WaitBlock
= &CurrentThread
->WaitBlock
[0];
417 CurrentThread
->WaitBlockList
= WaitBlock
;
419 /* Get the Current Object */
420 CurrentObject
= (PKMUTANT
)Object
;
422 /* Check if it's a mutant */
423 if (CurrentObject
->Header
.Type
== MutantObject
)
425 /* Check its signal state or if we own it */
426 if ((CurrentObject
->Header
.SignalState
> 0) ||
427 (CurrentThread
== CurrentObject
->OwnerThread
))
429 /* Just unwait this guy and exit */
430 if (CurrentObject
->Header
.SignalState
!= (LONG
)MINLONG
)
432 /* It has a normal signal state. Unwait and return */
433 KiSatisfyMutantWait(CurrentObject
, CurrentThread
);
434 WaitStatus
= CurrentThread
->WaitStatus
;
439 /* Raise an exception (see wasm.ru) */
440 KeReleaseDispatcherDatabaseLock(CurrentThread
->
442 ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED
);
446 else if (CurrentObject
->Header
.SignalState
> 0)
448 /* Another satisfied object */
449 KiSatisfyNonMutantWait(CurrentObject
, CurrentThread
);
450 WaitStatus
= STATUS_WAIT_0
;
454 /* Set up the Wait Block */
455 WaitBlock
->Object
= CurrentObject
;
456 WaitBlock
->Thread
= CurrentThread
;
457 WaitBlock
->WaitKey
= (USHORT
)(STATUS_SUCCESS
);
458 WaitBlock
->WaitType
= WaitAny
;
459 WaitBlock
->NextWaitBlock
= WaitBlock
;
461 /* Make sure we can satisfy the Alertable request */
462 KiCheckAlertability();
464 /* Enable the Timeout Timer if there was any specified */
467 /* Fail if the timeout interval is actually 0 */
468 if (!Timeout
->QuadPart
)
470 /* Return a timeout */
471 WaitStatus
= STATUS_TIMEOUT
;
475 /* Point to Timer Wait Block and Thread Timer */
476 TimerWaitBlock
= &CurrentThread
->WaitBlock
[TIMER_WAIT_BLOCK
];
477 ThreadTimer
= &CurrentThread
->Timer
;
479 /* Connect the Timer Wait Block */
480 WaitBlock
->NextWaitBlock
= TimerWaitBlock
;
482 /* Set up the Timer Wait Block */
483 TimerWaitBlock
->NextWaitBlock
= WaitBlock
;
485 /* Link the timer to this Wait Block */
486 ThreadTimer
->Header
.WaitListHead
.Flink
=
487 &TimerWaitBlock
->WaitListEntry
;
488 ThreadTimer
->Header
.WaitListHead
.Blink
=
489 &TimerWaitBlock
->WaitListEntry
;
491 /* Insert the Timer into the Timer Lists and enable it */
492 if (!KiInsertTimer(ThreadTimer
, *Timeout
))
494 /* Return a timeout if we couldn't insert the timer */
495 WaitStatus
= STATUS_TIMEOUT
;
500 /* Link the Object to this Wait Block */
501 InsertTailList(&CurrentObject
->Header
.WaitListHead
,
502 &WaitBlock
->WaitListEntry
);
504 /* Handle Kernel Queues */
505 if (CurrentThread
->Queue
) KiWakeQueue(CurrentThread
->Queue
);
507 /* Setup the wait information */
508 CurrentThread
->Alertable
= Alertable
;
509 CurrentThread
->WaitMode
= WaitMode
;
510 CurrentThread
->WaitReason
= WaitReason
;
511 CurrentThread
->WaitTime
= ((PLARGE_INTEGER
)&KeTickCount
)->LowPart
;
512 CurrentThread
->State
= Waiting
;
514 /* Find a new thread to run */
515 WaitStatus
= KiSwapThread();
516 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
518 /* Check if we were executing an APC */
519 if (WaitStatus
!= STATUS_KERNEL_APC
) return WaitStatus
;
521 /* Check if we had a timeout */
524 /* FIXME: Fixup interval */
528 /* Acquire again the lock */
529 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
532 /* Release the Lock, we are done */
533 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
537 /* Adjust the Quantum */
538 KiAdjustQuantumThread(CurrentThread
);
540 /* Release & Return */
541 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
550 KeWaitForMultipleObjects(IN ULONG Count
,
552 IN WAIT_TYPE WaitType
,
553 IN KWAIT_REASON WaitReason
,
554 IN KPROCESSOR_MODE WaitMode
,
555 IN BOOLEAN Alertable
,
556 IN PLARGE_INTEGER Timeout OPTIONAL
,
557 OUT PKWAIT_BLOCK WaitBlockArray OPTIONAL
)
559 PKMUTANT CurrentObject
;
560 PKWAIT_BLOCK WaitBlock
;
561 PKWAIT_BLOCK TimerWaitBlock
;
563 PKTHREAD CurrentThread
= KeGetCurrentThread();
564 ULONG AllObjectsSignaled
;
566 NTSTATUS WaitStatus
= STATUS_SUCCESS
;
568 /* Set the Current Thread */
569 CurrentThread
= KeGetCurrentThread();
571 /* Check if the lock is already held */
572 if (CurrentThread
->WaitNext
)
574 /* Lock is held, disable Wait Next */
575 CurrentThread
->WaitNext
= FALSE
;
579 /* Lock not held, acquire it */
580 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
583 /* Make sure the Wait Count is valid */
586 /* Check in regards to the Thread Object Limit */
587 if (Count
> THREAD_WAIT_OBJECTS
)
590 KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED
);
593 /* Use the Thread's Wait Block */
594 WaitBlockArray
= &CurrentThread
->WaitBlock
[0];
598 /* Using our own Block Array, so check with the System Object Limit */
599 if (Count
> MAXIMUM_WAIT_OBJECTS
)
602 KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED
);
606 /* Start the actual Loop */
609 /* Check if a kernel APC is pending and we're below APC_LEVEL */
610 if ((CurrentThread
->ApcState
.KernelApcPending
) &&
611 !(CurrentThread
->SpecialApcDisable
) &&
612 (CurrentThread
->WaitIrql
< APC_LEVEL
))
614 /* Unlock the dispatcher */
615 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
619 /* Append wait block to the KTHREAD wait block list */
620 CurrentThread
->WaitBlockList
= WaitBlock
= WaitBlockArray
;
622 /* Set default wait status */
623 CurrentThread
->WaitStatus
= STATUS_WAIT_0
;
625 /* Check if the wait is (already) satisfied */
626 AllObjectsSignaled
= TRUE
;
628 /* First, we'll try to satisfy the wait directly */
629 for (WaitIndex
= 0; WaitIndex
< Count
; WaitIndex
++)
631 /* Get the Current Object */
632 CurrentObject
= (PKMUTANT
)Object
[WaitIndex
];
634 /* Check the type of wait */
635 if (WaitType
== WaitAny
)
637 /* Check if the Object is a mutant */
638 if (CurrentObject
->Header
.Type
== MutantObject
)
640 /* Check if it's signaled */
641 if ((CurrentObject
->Header
.SignalState
> 0) ||
642 (CurrentThread
== CurrentObject
->OwnerThread
))
644 /* This is a Wait Any, so unwait this and exit */
645 if (CurrentObject
->Header
.SignalState
!=
648 /* Normal signal state, unwait it and return */
649 KiSatisfyMutantWait(CurrentObject
,
651 WaitStatus
= CurrentThread
->WaitStatus
|
657 /* Raise an exception (see wasm.ru) */
658 KeReleaseDispatcherDatabaseLock(CurrentThread
->
660 ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED
);
664 else if (CurrentObject
->Header
.SignalState
> 0)
666 /* Another signaled object, unwait and return */
667 KiSatisfyNonMutantWait(CurrentObject
, CurrentThread
);
668 WaitStatus
= WaitIndex
;
674 /* Check if we're dealing with a mutant again */
675 if (CurrentObject
->Header
.Type
== MutantObject
)
677 /* Check if it has an invalid count */
678 if ((CurrentThread
== CurrentObject
->OwnerThread
) &&
679 (CurrentObject
->Header
.SignalState
== MINLONG
))
681 /* Raise an exception */
682 KeReleaseDispatcherDatabaseLock(CurrentThread
->
684 ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED
);
686 else if ((CurrentObject
->Header
.SignalState
<= 0) &&
687 (CurrentThread
!= CurrentObject
->OwnerThread
))
689 /* We don't own it, can't satisfy the wait */
690 AllObjectsSignaled
= FALSE
;
693 else if (CurrentObject
->Header
.SignalState
<= 0)
695 /* Not signaled, can't satisfy */
696 AllObjectsSignaled
= FALSE
;
700 /* Set up a Wait Block for this Object */
701 WaitBlock
->Object
= CurrentObject
;
702 WaitBlock
->Thread
= CurrentThread
;
703 WaitBlock
->WaitKey
= (USHORT
)WaitIndex
;
704 WaitBlock
->WaitType
= (USHORT
)WaitType
;
705 WaitBlock
->NextWaitBlock
= WaitBlock
+ 1;
707 /* Move to the next Wait Block */
708 WaitBlock
= WaitBlock
->NextWaitBlock
;
711 /* Return to the Root Wait Block */
713 WaitBlock
->NextWaitBlock
= WaitBlockArray
;
715 /* Check if this is a Wait All and all the objects are signaled */
716 if ((WaitType
== WaitAll
) && (AllObjectsSignaled
))
718 /* Return to the Root Wait Block */
719 WaitBlock
= CurrentThread
->WaitBlockList
;
721 /* Satisfy their Waits and return to the caller */
722 KiWaitSatisfyAll(WaitBlock
);
723 WaitStatus
= CurrentThread
->WaitStatus
;
727 /* Make sure we can satisfy the Alertable request */
728 KiCheckAlertability();
730 /* Enable the Timeout Timer if there was any specified */
733 /* Make sure the timeout interval isn't actually 0 */
734 if (!Timeout
->QuadPart
)
736 /* Return a timeout */
737 WaitStatus
= STATUS_TIMEOUT
;
741 /* Point to Timer Wait Block and Thread Timer */
742 TimerWaitBlock
= &CurrentThread
->WaitBlock
[TIMER_WAIT_BLOCK
];
743 ThreadTimer
= &CurrentThread
->Timer
;
745 /* Connect the Timer Wait Block */
746 WaitBlock
->NextWaitBlock
= TimerWaitBlock
;
748 /* Set up the Timer Wait Block */
749 TimerWaitBlock
->NextWaitBlock
= WaitBlockArray
;
751 /* Initialize the list head */
752 InitializeListHead(&ThreadTimer
->Header
.WaitListHead
);
754 /* Insert the Timer into the Timer Lists and enable it */
755 if (!KiInsertTimer(ThreadTimer
, *Timeout
))
757 /* Return a timeout if we couldn't insert the timer */
758 WaitStatus
= STATUS_TIMEOUT
;
763 /* Insert into Object's Wait List*/
764 WaitBlock
= CurrentThread
->WaitBlockList
;
767 /* Get the Current Object */
768 CurrentObject
= WaitBlock
->Object
;
770 /* Link the Object to this Wait Block */
771 InsertTailList(&CurrentObject
->Header
.WaitListHead
,
772 &WaitBlock
->WaitListEntry
);
774 /* Move to the next Wait Block */
775 WaitBlock
= WaitBlock
->NextWaitBlock
;
776 } while (WaitBlock
!= WaitBlockArray
);
778 /* Handle Kernel Queues */
779 if (CurrentThread
->Queue
) KiWakeQueue(CurrentThread
->Queue
);
781 /* Setup the wait information */
782 CurrentThread
->Alertable
= Alertable
;
783 CurrentThread
->WaitMode
= WaitMode
;
784 CurrentThread
->WaitReason
= WaitReason
;
785 CurrentThread
->WaitTime
= ((PLARGE_INTEGER
)&KeTickCount
)->LowPart
;
786 CurrentThread
->State
= Waiting
;
788 /* Find a new thread to run */
789 WaitStatus
= KiSwapThread();
790 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
792 /* Check if we were executing an APC */
793 if (WaitStatus
!= STATUS_KERNEL_APC
) return WaitStatus
;
795 /* Check if we had a timeout */
798 /* FIXME: Fixup interval */
801 /* Acquire again the lock */
802 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
806 /* Release the Lock, we are done */
807 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
811 /* Adjust the Quantum */
812 KiAdjustQuantumThread(CurrentThread
);
814 /* Release & Return */
815 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);