2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS project
4 * FILE: ntoskrnl/ke/wait.c
5 * PURPOSE: Manages non-busy waiting
7 * PROGRAMMERS: Alex Ionescu - Fixes and optimization.
8 * Gunnar Dalsnes - Implementation
11 /* INCLUDES ******************************************************************/
16 #include <internal/debug.h>
18 /* GLOBALS ******************************************************************/
20 static KSPIN_LOCK DispatcherDatabaseLock
;
22 /* Tells us if the Timer or Event is a Syncronization or Notification Object */
23 #define TIMER_OR_EVENT_TYPE 0x7L
25 /* One of the Reserved Wait Blocks, this one is for the Thread's Timer */
26 #define TIMER_WAIT_BLOCK 0x3L
28 /* FUNCTIONS *****************************************************************/
33 KiCheckAlertability(BOOLEAN Alertable
,
34 PKTHREAD CurrentThread
,
35 KPROCESSOR_MODE WaitMode
,
38 /* At this point, we have to do a wait, so make sure we can make the thread Alertable if requested */
41 /* If the Thread is Alerted, set the Wait Status accordingly */
42 if (CurrentThread
->Alerted
[(int)WaitMode
]) {
44 CurrentThread
->Alerted
[(int)WaitMode
] = FALSE
;
45 DPRINT("Thread was Alerted\n");
46 *Status
= STATUS_ALERTED
;
48 /* If there are User APCs Pending, then we can't really be alertable */
49 } else if ((!IsListEmpty(&CurrentThread
->ApcState
.ApcListHead
[UserMode
])) &&
50 (WaitMode
== UserMode
)) {
52 DPRINT("APCs are Pending\n");
53 CurrentThread
->ApcState
.UserApcPending
= TRUE
;
54 *Status
= STATUS_USER_APC
;
57 /* If there are User APCs Pending and we are waiting in usermode, then we must notify the caller */
58 } else if ((CurrentThread
->ApcState
.UserApcPending
) && (WaitMode
== UserMode
)) {
59 DPRINT("APCs are Pending\n");
60 *Status
= STATUS_USER_APC
;
67 * FUNCTION: Puts the current thread into an alertable or nonalertable
68 * wait state for a given internal
70 * WaitMode = Processor mode in which the caller is waiting
71 * Altertable = Specifies if the wait is alertable
72 * Interval = Specifies the interval to wait
77 KeDelayExecutionThread(KPROCESSOR_MODE WaitMode
,
79 PLARGE_INTEGER Interval
)
81 PKWAIT_BLOCK TimerWaitBlock
;
83 PKTHREAD CurrentThread
= KeGetCurrentThread();
86 DPRINT("Entering KeDelayExecutionThread\n");
88 /* Check if the lock is already held */
89 if (CurrentThread
->WaitNext
) {
91 /* Lock is held, disable Wait Next */
92 DPRINT("Lock is held\n");
93 CurrentThread
->WaitNext
= FALSE
;
97 /* Lock not held, acquire it */
98 DPRINT("Lock is not held, acquiring\n");
99 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
102 /* Use built-in Wait block */
103 TimerWaitBlock
= &CurrentThread
->WaitBlock
[TIMER_WAIT_BLOCK
];
105 /* Start Wait Loop */
108 /* We are going to wait no matter what (that's the point), so test Alertability */
109 KiCheckAlertability(Alertable
, CurrentThread
, KernelMode
, &Status
);
112 ThreadTimer
= &CurrentThread
->Timer
;
114 /* Setup the Wait Block */
115 CurrentThread
->WaitBlockList
= TimerWaitBlock
;
116 TimerWaitBlock
->Object
= (PVOID
)ThreadTimer
;
117 TimerWaitBlock
->Thread
= CurrentThread
;
118 TimerWaitBlock
->WaitKey
= (USHORT
)STATUS_TIMEOUT
;
119 TimerWaitBlock
->WaitType
= WaitAny
;
120 TimerWaitBlock
->NextWaitBlock
= TimerWaitBlock
;
122 /* Link the timer to this Wait Block */
123 InitializeListHead(&ThreadTimer
->Header
.WaitListHead
);
124 InsertTailList(&ThreadTimer
->Header
.WaitListHead
, &TimerWaitBlock
->WaitListEntry
);
126 /* Insert the Timer into the Timer Lists and enable it */
127 if (!KiInsertTimer(ThreadTimer
, *Interval
)) {
129 /* FIXME: The timer already expired, we should find a new ready thread */
130 Status
= STATUS_SUCCESS
;
134 /* Handle Kernel Queues */
135 if (CurrentThread
->Queue
) {
137 DPRINT("Waking Queue\n");
138 KiWakeQueue(CurrentThread
->Queue
);
141 /* Block the Thread */
142 DPRINT("Blocking the Thread: %d, %d, %x\n", Alertable
, WaitMode
, KeGetCurrentThread());
143 KiBlockThread(&Status
,
148 /* Check if we were executing an APC or if we timed out */
149 if (Status
!= STATUS_KERNEL_APC
) {
151 /* This is a good thing */
152 if (Status
== STATUS_TIMEOUT
) Status
= STATUS_SUCCESS
;
158 DPRINT("Looping Again\n");
159 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
163 /* Release the Lock, we are done */
164 DPRINT("Returning from KeDelayExecutionThread(), %x. Status: %d\n", KeGetCurrentThread(), Status
);
165 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
172 * FUNCTION: Puts the current thread into a wait state until the
173 * given dispatcher object is set to signalled
175 * Object = Object to wait on
176 * WaitReason = Reason for the wait (debugging aid)
177 * WaitMode = Can be KernelMode or UserMode, if UserMode then
178 * user-mode APCs can be delivered and the thread's
179 * stack can be paged out
180 * Altertable = Specifies if the wait is a alertable
181 * Timeout = Optional timeout value
186 KeWaitForSingleObject(PVOID Object
,
187 KWAIT_REASON WaitReason
,
188 KPROCESSOR_MODE WaitMode
,
190 PLARGE_INTEGER Timeout
)
192 PDISPATCHER_HEADER CurrentObject
;
193 PKWAIT_BLOCK WaitBlock
;
194 PKWAIT_BLOCK TimerWaitBlock
;
196 PKTHREAD CurrentThread
= KeGetCurrentThread();
200 DPRINT("Entering KeWaitForSingleObject\n");
202 /* Check if the lock is already held */
203 if (CurrentThread
->WaitNext
) {
205 /* Lock is held, disable Wait Next */
206 DPRINT("Lock is held\n");
207 CurrentThread
->WaitNext
= FALSE
;
211 /* Lock not held, acquire it */
212 DPRINT("Lock is not held, acquiring\n");
213 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
216 /* Start the actual Loop */
219 /* Get the current Wait Status */
220 WaitStatus
= CurrentThread
->WaitStatus
;
222 /* Append wait block to the KTHREAD wait block list */
223 CurrentThread
->WaitBlockList
= WaitBlock
= &CurrentThread
->WaitBlock
[0];
225 /* Get the Current Object */
226 CurrentObject
= (PDISPATCHER_HEADER
)Object
;
228 /* Check if the Object is Signaled */
229 if (KiIsObjectSignaled(CurrentObject
, CurrentThread
)) {
231 /* Just unwait this guy and exit */
232 if (CurrentObject
->SignalState
!= (LONG
)MINLONG
) {
234 /* It has a normal signal state, so unwait it and return */
235 KiSatisfyObjectWait(CurrentObject
, CurrentThread
);
236 Status
= STATUS_WAIT_0
;
241 /* Is this a Mutant? */
242 if (CurrentObject
->Type
== MutantObject
) {
244 /* According to wasm.ru, we must raise this exception (tested and true) */
245 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
246 ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED
);
251 /* Set up the Wait Block */
252 WaitBlock
->Object
= CurrentObject
;
253 WaitBlock
->Thread
= CurrentThread
;
254 WaitBlock
->WaitKey
= (USHORT
)(STATUS_WAIT_0
);
255 WaitBlock
->WaitType
= WaitAny
;
256 WaitBlock
->NextWaitBlock
= WaitBlock
;
258 /* Make sure we can satisfy the Alertable request */
259 KiCheckAlertability(Alertable
, CurrentThread
, WaitMode
, &Status
);
261 /* Set the Wait Status */
262 CurrentThread
->WaitStatus
= Status
;
264 /* Enable the Timeout Timer if there was any specified */
265 if (Timeout
!= NULL
) {
267 /* However if 0 timeout was specified, then we must fail since we need to peform a wait */
268 if (!Timeout
->QuadPart
) {
270 /* Return a timeout */
271 Status
= STATUS_TIMEOUT
;
275 /* Point to Timer Wait Block and Thread Timer */
276 TimerWaitBlock
= &CurrentThread
->WaitBlock
[TIMER_WAIT_BLOCK
];
277 ThreadTimer
= &CurrentThread
->Timer
;
279 /* Connect the Timer Wait Block */
280 WaitBlock
->NextWaitBlock
= TimerWaitBlock
;
282 /* Set up the Timer Wait Block */
283 TimerWaitBlock
->Object
= (PVOID
)ThreadTimer
;
284 TimerWaitBlock
->Thread
= CurrentThread
;
285 TimerWaitBlock
->WaitKey
= STATUS_TIMEOUT
;
286 TimerWaitBlock
->WaitType
= WaitAny
;
287 TimerWaitBlock
->NextWaitBlock
= WaitBlock
;
289 /* Link the timer to this Wait Block */
290 InitializeListHead(&ThreadTimer
->Header
.WaitListHead
);
291 InsertTailList(&ThreadTimer
->Header
.WaitListHead
, &TimerWaitBlock
->WaitListEntry
);
293 /* Insert the Timer into the Timer Lists and enable it */
294 if (!KiInsertTimer(ThreadTimer
, *Timeout
)) {
296 /* Return a timeout if we couldn't insert the timer for some reason */
297 Status
= STATUS_TIMEOUT
;
302 /* Link the Object to this Wait Block */
303 InsertTailList(&CurrentObject
->WaitListHead
, &WaitBlock
->WaitListEntry
);
305 /* Handle Kernel Queues */
306 if (CurrentThread
->Queue
) {
308 DPRINT("Waking Queue\n");
309 KiWakeQueue(CurrentThread
->Queue
);
312 /* Block the Thread */
313 DPRINT("Blocking the Thread: %d, %d, %d, %x\n", Alertable
, WaitMode
, WaitReason
, KeGetCurrentThread());
314 KiBlockThread(&Status
,
319 /* Check if we were executing an APC */
320 if (Status
!= STATUS_KERNEL_APC
) {
326 DPRINT("Looping Again\n");
327 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
331 /* Release the Lock, we are done */
332 DPRINT("Returning from KeWaitForMultipleObjects(), %x. Status: %d\n", KeGetCurrentThread(), Status
);
333 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
337 /* Adjust the Quantum */
338 KiAdjustQuantumThread(CurrentThread
);
340 /* Release & Return */
341 DPRINT("Returning from KeWaitForMultipleObjects(), %x. Status: %d\n. We did not wait.", KeGetCurrentThread(), Status
);
342 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
350 KeWaitForMultipleObjects(ULONG Count
,
353 KWAIT_REASON WaitReason
,
354 KPROCESSOR_MODE WaitMode
,
356 PLARGE_INTEGER Timeout
,
357 PKWAIT_BLOCK WaitBlockArray
)
359 PDISPATCHER_HEADER CurrentObject
;
360 PKWAIT_BLOCK WaitBlock
;
361 PKWAIT_BLOCK TimerWaitBlock
;
363 PKTHREAD CurrentThread
= KeGetCurrentThread();
364 ULONG AllObjectsSignaled
;
369 DPRINT("Entering KeWaitForMultipleObjects(Count %lu Object[] %p) "
370 "PsGetCurrentThread() %x, Timeout %x\n", Count
, Object
, PsGetCurrentThread(), Timeout
);
372 /* Set the Current Thread */
373 CurrentThread
= KeGetCurrentThread();
375 /* Check if the lock is already held */
376 if (CurrentThread
->WaitNext
) {
378 /* Lock is held, disable Wait Next */
379 DPRINT("Lock is held\n");
380 CurrentThread
->WaitNext
= FALSE
;
384 /* Lock not held, acquire it */
385 DPRINT("Lock is not held, acquiring\n");
386 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
389 /* Make sure the Wait Count is valid for the Thread and Maximum Wait Objects */
390 if (!WaitBlockArray
) {
392 /* Check in regards to the Thread Object Limit */
393 if (Count
> THREAD_WAIT_OBJECTS
) {
395 KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED
);
398 /* Use the Thread's Wait Block */
399 WaitBlockArray
= &CurrentThread
->WaitBlock
[0];
403 /* Using our own Block Array. Check in regards to System Object Limit */
404 if (Count
> MAXIMUM_WAIT_OBJECTS
) {
406 KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED
);
410 /* Start the actual Loop */
413 /* Get the current Wait Status */
414 WaitStatus
= CurrentThread
->WaitStatus
;
416 /* Append wait block to the KTHREAD wait block list */
417 CurrentThread
->WaitBlockList
= WaitBlock
= WaitBlockArray
;
419 /* Check if the wait is (already) satisfied */
420 AllObjectsSignaled
= TRUE
;
422 /* First, we'll try to satisfy the wait directly */
423 for (WaitIndex
= 0; WaitIndex
< Count
; WaitIndex
++) {
425 /* Get the Current Object */
426 CurrentObject
= (PDISPATCHER_HEADER
)Object
[WaitIndex
];
428 /* Check if the Object is Signaled */
429 if (KiIsObjectSignaled(CurrentObject
, CurrentThread
)) {
431 /* Check what kind of wait this is */
432 if (WaitType
== WaitAny
) {
434 /* This is a Wait Any, so just unwait this guy and exit */
435 if (CurrentObject
->SignalState
!= (LONG
)MINLONG
) {
437 /* It has a normal signal state, so unwait it and return */
438 KiSatisfyObjectWait(CurrentObject
, CurrentThread
);
439 Status
= STATUS_WAIT_0
| WaitIndex
;
444 /* Is this a Mutant? */
445 if (CurrentObject
->Type
== MutantObject
) {
447 /* According to wasm.ru, we must raise this exception (tested and true) */
448 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
449 ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED
);
456 /* One of the objects isn't signaled... if this is a WaitAll, we will fail later */
457 AllObjectsSignaled
= FALSE
;
460 /* Set up a Wait Block for this Object */
461 WaitBlock
->Object
= CurrentObject
;
462 WaitBlock
->Thread
= CurrentThread
;
463 WaitBlock
->WaitKey
= (USHORT
)(STATUS_WAIT_0
+ WaitIndex
);
464 WaitBlock
->WaitType
= (USHORT
)WaitType
;
465 WaitBlock
->NextWaitBlock
= WaitBlock
+ 1;
467 /* Move to the next Wait Block */
468 WaitBlock
= WaitBlock
->NextWaitBlock
;
471 /* Return to the Root Wait Block */
473 WaitBlock
->NextWaitBlock
= WaitBlockArray
;
475 /* Check if this is a Wait All and all the objects are signaled */
476 if ((WaitType
== WaitAll
) && (AllObjectsSignaled
)) {
478 /* Return to the Root Wait Block */
479 WaitBlock
= CurrentThread
->WaitBlockList
;
481 /* Satisfy their Waits and return to the caller */
482 KiSatisifyMultipleObjectWaits(WaitBlock
);
483 Status
= STATUS_WAIT_0
;
487 /* Make sure we can satisfy the Alertable request */
488 KiCheckAlertability(Alertable
, CurrentThread
, WaitMode
, &Status
);
490 /* Set the Wait Status */
491 CurrentThread
->WaitStatus
= Status
;
493 /* Enable the Timeout Timer if there was any specified */
494 if (Timeout
!= NULL
) {
496 /* However if 0 timeout was specified, then we must fail since we need to peform a wait */
497 if (!Timeout
->QuadPart
) {
499 /* Return a timeout */
500 Status
= STATUS_TIMEOUT
;
504 /* Point to Timer Wait Block and Thread Timer */
505 TimerWaitBlock
= &CurrentThread
->WaitBlock
[TIMER_WAIT_BLOCK
];
506 ThreadTimer
= &CurrentThread
->Timer
;
508 /* Connect the Timer Wait Block */
509 WaitBlock
->NextWaitBlock
= TimerWaitBlock
;
511 /* Set up the Timer Wait Block */
512 TimerWaitBlock
->Object
= (PVOID
)ThreadTimer
;
513 TimerWaitBlock
->Thread
= CurrentThread
;
514 TimerWaitBlock
->WaitKey
= STATUS_TIMEOUT
;
515 TimerWaitBlock
->WaitType
= WaitAny
;
516 TimerWaitBlock
->NextWaitBlock
= WaitBlockArray
;
518 /* Link the timer to this Wait Block */
519 InitializeListHead(&ThreadTimer
->Header
.WaitListHead
);
521 /* Insert the Timer into the Timer Lists and enable it */
522 if (!KiInsertTimer(ThreadTimer
, *Timeout
)) {
524 /* Return a timeout if we couldn't insert the timer for some reason */
525 Status
= STATUS_TIMEOUT
;
530 /* Insert into Object's Wait List*/
531 WaitBlock
= CurrentThread
->WaitBlockList
;
534 /* Get the Current Object */
535 CurrentObject
= WaitBlock
->Object
;
537 /* Link the Object to this Wait Block */
538 InsertTailList(&CurrentObject
->WaitListHead
, &WaitBlock
->WaitListEntry
);
540 /* Move to the next Wait Block */
541 WaitBlock
= WaitBlock
->NextWaitBlock
;
542 } while (WaitBlock
!= WaitBlockArray
);
544 /* Handle Kernel Queues */
545 if (CurrentThread
->Queue
) {
547 DPRINT("Waking Queue\n");
548 KiWakeQueue(CurrentThread
->Queue
);
551 /* Block the Thread */
552 DPRINT("Blocking the Thread: %d, %d, %d, %x\n", Alertable
, WaitMode
,
553 WaitReason
, KeGetCurrentThread());
554 KiBlockThread(&Status
,
559 /* Check if we were executing an APC */
560 DPRINT("Thread is back\n");
561 if (Status
!= STATUS_KERNEL_APC
) {
567 DPRINT("Looping Again\n");
568 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
572 /* Release the Lock, we are done */
573 DPRINT("Returning, %x. Status: %d\n", KeGetCurrentThread(), Status
);
574 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
578 /* Adjust the Quantum */
579 KiAdjustQuantumThread(CurrentThread
);
581 /* Release & Return */
582 DPRINT("Returning, %x. Status: %d\n. We did not wait.",
583 KeGetCurrentThread(), Status
);
584 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
590 KiSatisfyObjectWait(PDISPATCHER_HEADER Object
,
594 /* Special case for Mutants */
595 if (Object
->Type
== MutantObject
) {
597 /* Decrease the Signal State */
598 Object
->SignalState
--;
600 /* Check if it's now non-signaled */
601 if (Object
->SignalState
== 0) {
603 /* Set the Owner Thread */
604 ((PKMUTANT
)Object
)->OwnerThread
= Thread
;
606 /* Disable APCs if needed */
607 Thread
->KernelApcDisable
-= ((PKMUTANT
)Object
)->ApcDisable
;
609 /* Check if it's abandoned */
610 if (((PKMUTANT
)Object
)->Abandoned
) {
613 ((PKMUTANT
)Object
)->Abandoned
= FALSE
;
616 Thread
->WaitStatus
= STATUS_ABANDONED
;
619 /* Insert it into the Mutant List */
620 InsertHeadList(&Thread
->MutantListHead
, &((PKMUTANT
)Object
)->MutantListEntry
);
623 } else if ((Object
->Type
& TIMER_OR_EVENT_TYPE
) == EventSynchronizationObject
) {
625 /* These guys (Syncronization Timers and Events) just get un-signaled */
626 Object
->SignalState
= 0;
628 } else if (Object
->Type
== SemaphoreObject
) {
630 /* These ones can have multiple signalings, so we only decrease it */
631 Object
->SignalState
--;
637 KiWaitTest(PDISPATCHER_HEADER Object
,
640 PLIST_ENTRY WaitEntry
;
641 PLIST_ENTRY WaitList
;
642 PKWAIT_BLOCK CurrentWaitBlock
;
643 PKWAIT_BLOCK NextWaitBlock
;
646 /* Loop the Wait Entries */
647 DPRINT("KiWaitTest for Object: %x\n", Object
);
648 WaitList
= &Object
->WaitListHead
;
649 WaitEntry
= WaitList
->Flink
;
650 while ((WaitEntry
!= WaitList
) && (Object
->SignalState
> 0)) {
652 /* Get the current wait block */
653 CurrentWaitBlock
= CONTAINING_RECORD(WaitEntry
, KWAIT_BLOCK
, WaitListEntry
);
654 WaitThread
= CurrentWaitBlock
->Thread
;
656 /* Check the current Wait Mode */
657 if (CurrentWaitBlock
->WaitType
== WaitAny
) {
659 /* Easy case, satisfy only this wait */
660 DPRINT("Satisfiying a Wait any\n");
661 WaitEntry
= WaitEntry
->Blink
;
662 KiSatisfyObjectWait(Object
, WaitThread
);
666 /* Everything must be satisfied */
667 DPRINT("Checking for a Wait All\n");
668 NextWaitBlock
= CurrentWaitBlock
->NextWaitBlock
;
670 /* Loop first to make sure they are valid */
671 while (NextWaitBlock
!= CurrentWaitBlock
) {
673 /* Check if the object is signaled */
674 DPRINT("Checking: %x %d\n", NextWaitBlock
->Object
, Object
->SignalState
);
675 if (!KiIsObjectSignaled(NextWaitBlock
->Object
, WaitThread
)) {
677 /* It's not, move to the next one */
678 DPRINT("One of the object is non-signaled, sorry.\n");
682 /* Go to the next Wait block */
683 NextWaitBlock
= NextWaitBlock
->NextWaitBlock
;
686 /* All the objects are signaled, we can satisfy */
687 DPRINT("Satisfiying a Wait All\n");
688 WaitEntry
= WaitEntry
->Blink
;
689 KiSatisifyMultipleObjectWaits(CurrentWaitBlock
);
692 /* All waits satisfied, unwait the thread */
693 DPRINT("Unwaiting the Thread\n");
694 KiAbortWaitThread(WaitThread
, CurrentWaitBlock
->WaitKey
, Increment
);
698 WaitEntry
= WaitEntry
->Flink
;
704 /* Must be called with the dispatcher lock held */
707 KiAbortWaitThread(PKTHREAD Thread
,
711 PKWAIT_BLOCK WaitBlock
;
713 /* If we are blocked, we must be waiting on something also */
714 DPRINT("KiAbortWaitThread: %x, Status: %x, %x \n", Thread
, WaitStatus
, Thread
->WaitBlockList
);
715 ASSERT((Thread
->State
== Waiting
) == (Thread
->WaitBlockList
!= NULL
));
717 /* Remove the Wait Blocks from the list */
718 DPRINT("Removing waits\n");
719 WaitBlock
= Thread
->WaitBlockList
;
723 DPRINT("Removing Waitblock: %x, %x\n", WaitBlock
, WaitBlock
->NextWaitBlock
);
724 RemoveEntryList(&WaitBlock
->WaitListEntry
);
726 /* Go to the next one */
727 WaitBlock
= WaitBlock
->NextWaitBlock
;
728 } while (WaitBlock
!= Thread
->WaitBlockList
);
730 /* Check if there's a Thread Timer */
731 if (Thread
->Timer
.Header
.Inserted
) {
733 /* Cancel the Thread Timer with the no-lock fastpath */
734 DPRINT("Removing the Thread's Timer\n");
735 Thread
->Timer
.Header
.Inserted
= FALSE
;
736 RemoveEntryList(&Thread
->Timer
.TimerListEntry
);
739 /* Increment the Queue's active threads */
742 DPRINT("Incrementing Queue's active threads\n");
743 Thread
->Queue
->CurrentCount
++;
746 /* Reschedule the Thread */
747 DPRINT("Unblocking the Thread\n");
748 KiUnblockThread(Thread
, &WaitStatus
, 0);
754 KiIsObjectSignaled(PDISPATCHER_HEADER Object
,
757 /* Mutants are...well...mutants! */
758 if (Object
->Type
== MutantObject
) {
761 * Because Cutler hates mutants, they are actually signaled if the Signal State is <= 0
762 * Well, only if they are recursivly acquired (i.e if we own it right now).
763 * Of course, they are also signaled if their signal state is 1.
765 if ((Object
->SignalState
<= 0 && ((PKMUTANT
)Object
)->OwnerThread
== Thread
) ||
766 (Object
->SignalState
== 1)) {
768 /* Signaled Mutant */
773 /* Unsignaled Mutant */
778 /* Any other object is not a mutated freak, so let's use logic */
779 return (!Object
->SignalState
<= 0);
785 KiSatisifyMultipleObjectWaits(PKWAIT_BLOCK WaitBlock
)
787 PKWAIT_BLOCK FirstBlock
= WaitBlock
;
788 PKTHREAD WaitThread
= WaitBlock
->Thread
;
790 /* Loop through all the Wait Blocks, and wake each Object */
793 /* Wake the Object */
794 KiSatisfyObjectWait(WaitBlock
->Object
, WaitThread
);
795 WaitBlock
= WaitBlock
->NextWaitBlock
;
796 } while (WaitBlock
!= FirstBlock
);
802 KeInitializeDispatcherHeader(DISPATCHER_HEADER
* Header
,
807 Header
->Type
= (UCHAR
)Type
;
808 Header
->Absolute
= 0;
809 Header
->Inserted
= 0;
810 Header
->Size
= (UCHAR
)Size
;
811 Header
->SignalState
= SignalState
;
812 InitializeListHead(&(Header
->WaitListHead
));
818 KeAcquireDispatcherDatabaseLock(VOID
)
822 KeAcquireSpinLock (&DispatcherDatabaseLock
, &OldIrql
);
829 KeAcquireDispatcherDatabaseLockAtDpcLevel(VOID
)
831 KeAcquireSpinLockAtDpcLevel (&DispatcherDatabaseLock
);
837 KeInitializeDispatcher(VOID
)
839 /* Initialize the Dispatcher Lock */
840 KeInitializeSpinLock(&DispatcherDatabaseLock
);
846 KeReleaseDispatcherDatabaseLock(KIRQL OldIrql
)
848 /* If it's the idle thread, dispatch */
849 if (!KeIsExecutingDpc() && OldIrql
< DISPATCH_LEVEL
&& KeGetCurrentThread() != NULL
&&
850 KeGetCurrentThread() == KeGetCurrentPrcb()->IdleThread
) {
852 KiDispatchThreadNoLock(Ready
);
853 KeLowerIrql(OldIrql
);
857 /* Just release the spin lock */
858 KeReleaseSpinLock(&DispatcherDatabaseLock
, OldIrql
);
865 KeReleaseDispatcherDatabaseLockFromDpcLevel(VOID
)
867 KeReleaseSpinLockFromDpcLevel(&DispatcherDatabaseLock
);