2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel
4 * FILE: ntoskrnl/ke/wait.c
5 * PURPOSE: Manages dispatch level wait-related code
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
10 /* INCLUDES ******************************************************************/
15 #include <internal/debug.h>
17 /* GLOBALS ******************************************************************/
19 static KSPIN_LOCK DispatcherDatabaseLock
;
21 /* Tells us if the Timer or Event is a Syncronization or Notification Object */
22 #define TIMER_OR_EVENT_TYPE 0x7L
24 /* One of the Reserved Wait Blocks, this one is for the Thread's Timer */
25 #define TIMER_WAIT_BLOCK 0x3L
27 /* FUNCTIONS *****************************************************************/
32 KiCheckAlertability(BOOLEAN Alertable
,
33 PKTHREAD CurrentThread
,
34 KPROCESSOR_MODE WaitMode
,
37 /* At this point, we have to do a wait, so make sure we can make the thread Alertable if requested */
40 /* If the Thread is Alerted, set the Wait Status accordingly */
41 if (CurrentThread
->Alerted
[(int)WaitMode
]) {
43 CurrentThread
->Alerted
[(int)WaitMode
] = FALSE
;
44 DPRINT("Thread was Alerted\n");
45 *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
!= KernelMode
)) {
52 DPRINT("APCs are Pending\n");
53 CurrentThread
->ApcState
.UserApcPending
= TRUE
;
54 *Status
= STATUS_USER_APC
;
58 /* If there are User APCs Pending and we are waiting in usermode, then we must notify the caller */
59 } else if ((CurrentThread
->ApcState
.UserApcPending
) && (WaitMode
!= KernelMode
)) {
60 DPRINT("APCs are Pending\n");
61 *Status
= STATUS_USER_APC
;
71 * FUNCTION: Puts the current thread into an alertable or nonalertable
72 * wait state for a given internal
74 * WaitMode = Processor mode in which the caller is waiting
75 * Altertable = Specifies if the wait is alertable
76 * Interval = Specifies the interval to wait
81 KeDelayExecutionThread(KPROCESSOR_MODE WaitMode
,
83 PLARGE_INTEGER Interval
)
85 PKWAIT_BLOCK TimerWaitBlock
;
87 PKTHREAD CurrentThread
= KeGetCurrentThread();
90 DPRINT("Entering KeDelayExecutionThread\n");
92 /* Check if the lock is already held */
93 if (CurrentThread
->WaitNext
) {
95 /* Lock is held, disable Wait Next */
96 DPRINT("Lock is held\n");
97 CurrentThread
->WaitNext
= FALSE
;
101 /* Lock not held, acquire it */
102 DPRINT("Lock is not held, acquiring\n");
103 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
106 /* Use built-in Wait block */
107 TimerWaitBlock
= &CurrentThread
->WaitBlock
[TIMER_WAIT_BLOCK
];
109 /* Start Wait Loop */
112 /* We are going to wait no matter what (that's the point), so test Alertability */
113 if (KiCheckAlertability(Alertable
, CurrentThread
, WaitMode
, &Status
))
117 ThreadTimer
= &CurrentThread
->Timer
;
119 /* Setup the Wait Block */
120 CurrentThread
->WaitBlockList
= TimerWaitBlock
;
121 TimerWaitBlock
->Object
= (PVOID
)ThreadTimer
;
122 TimerWaitBlock
->Thread
= CurrentThread
;
123 TimerWaitBlock
->WaitKey
= (USHORT
)STATUS_TIMEOUT
;
124 TimerWaitBlock
->WaitType
= WaitAny
;
125 TimerWaitBlock
->NextWaitBlock
= TimerWaitBlock
;
127 /* Link the timer to this Wait Block */
128 InitializeListHead(&ThreadTimer
->Header
.WaitListHead
);
129 InsertTailList(&ThreadTimer
->Header
.WaitListHead
, &TimerWaitBlock
->WaitListEntry
);
131 /* Insert the Timer into the Timer Lists and enable it */
132 if (!KiInsertTimer(ThreadTimer
, *Interval
)) {
134 /* FIXME: The timer already expired, we should find a new ready thread */
135 Status
= STATUS_SUCCESS
;
139 /* Handle Kernel Queues */
140 if (CurrentThread
->Queue
) {
142 DPRINT("Waking Queue\n");
143 KiWakeQueue(CurrentThread
->Queue
);
146 /* Block the Thread */
147 DPRINT("Blocking the Thread: %d, %d, %x\n", Alertable
, WaitMode
, KeGetCurrentThread());
148 KiBlockThread(&Status
,
153 /* Check if we were executing an APC or if we timed out */
154 if (Status
!= STATUS_KERNEL_APC
) {
156 /* This is a good thing */
157 if (Status
== STATUS_TIMEOUT
) Status
= STATUS_SUCCESS
;
163 DPRINT("Looping Again\n");
164 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
168 /* Release the Lock, we are done */
169 DPRINT("Returning from KeDelayExecutionThread(), %x. Status: %d\n", KeGetCurrentThread(), Status
);
170 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
177 * FUNCTION: Puts the current thread into a wait state until the
178 * given dispatcher object is set to signalled
180 * Object = Object to wait on
181 * WaitReason = Reason for the wait (debugging aid)
182 * WaitMode = Can be KernelMode or UserMode, if UserMode then
183 * user-mode APCs can be delivered and the thread's
184 * stack can be paged out
185 * Altertable = Specifies if the wait is a alertable
186 * Timeout = Optional timeout value
191 KeWaitForSingleObject(PVOID Object
,
192 KWAIT_REASON WaitReason
,
193 KPROCESSOR_MODE WaitMode
,
195 PLARGE_INTEGER Timeout
)
197 PDISPATCHER_HEADER CurrentObject
;
198 PKWAIT_BLOCK WaitBlock
;
199 PKWAIT_BLOCK TimerWaitBlock
;
201 PKTHREAD CurrentThread
= KeGetCurrentThread();
205 DPRINT("Entering KeWaitForSingleObject\n");
207 /* Check if the lock is already held */
208 if (CurrentThread
->WaitNext
) {
210 /* Lock is held, disable Wait Next */
211 DPRINT("Lock is held\n");
212 CurrentThread
->WaitNext
= FALSE
;
216 /* Lock not held, acquire it */
217 DPRINT("Lock is not held, acquiring\n");
218 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
221 /* Start the actual Loop */
224 /* Get the current Wait Status */
225 WaitStatus
= CurrentThread
->WaitStatus
;
227 /* Append wait block to the KTHREAD wait block list */
228 CurrentThread
->WaitBlockList
= WaitBlock
= &CurrentThread
->WaitBlock
[0];
230 /* Get the Current Object */
231 CurrentObject
= (PDISPATCHER_HEADER
)Object
;
233 /* Check if the Object is Signaled */
234 if (KiIsObjectSignaled(CurrentObject
, CurrentThread
)) {
236 /* Just unwait this guy and exit */
237 if (CurrentObject
->SignalState
!= (LONG
)MINLONG
) {
239 /* It has a normal signal state, so unwait it and return */
240 KiSatisfyObjectWait(CurrentObject
, CurrentThread
);
241 Status
= STATUS_WAIT_0
;
246 /* Is this a Mutant? */
247 if (CurrentObject
->Type
== MutantObject
) {
249 /* According to wasm.ru, we must raise this exception (tested and true) */
250 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
251 ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED
);
256 /* Set up the Wait Block */
257 WaitBlock
->Object
= CurrentObject
;
258 WaitBlock
->Thread
= CurrentThread
;
259 WaitBlock
->WaitKey
= (USHORT
)(STATUS_WAIT_0
);
260 WaitBlock
->WaitType
= WaitAny
;
261 WaitBlock
->NextWaitBlock
= WaitBlock
;
263 /* Make sure we can satisfy the Alertable request */
264 if (KiCheckAlertability(Alertable
, CurrentThread
, WaitMode
, &Status
))
267 /* Set the Wait Status */
268 CurrentThread
->WaitStatus
= Status
;
270 /* Enable the Timeout Timer if there was any specified */
271 if (Timeout
!= NULL
) {
273 /* However if 0 timeout was specified, then we must fail since we need to peform a wait */
274 if (!Timeout
->QuadPart
) {
276 /* Return a timeout */
277 Status
= STATUS_TIMEOUT
;
281 /* Point to Timer Wait Block and Thread Timer */
282 TimerWaitBlock
= &CurrentThread
->WaitBlock
[TIMER_WAIT_BLOCK
];
283 ThreadTimer
= &CurrentThread
->Timer
;
285 /* Connect the Timer Wait Block */
286 WaitBlock
->NextWaitBlock
= TimerWaitBlock
;
288 /* Set up the Timer Wait Block */
289 TimerWaitBlock
->Object
= (PVOID
)ThreadTimer
;
290 TimerWaitBlock
->Thread
= CurrentThread
;
291 TimerWaitBlock
->WaitKey
= STATUS_TIMEOUT
;
292 TimerWaitBlock
->WaitType
= WaitAny
;
293 TimerWaitBlock
->NextWaitBlock
= WaitBlock
;
295 /* Link the timer to this Wait Block */
296 InitializeListHead(&ThreadTimer
->Header
.WaitListHead
);
297 InsertTailList(&ThreadTimer
->Header
.WaitListHead
, &TimerWaitBlock
->WaitListEntry
);
299 /* Insert the Timer into the Timer Lists and enable it */
300 if (!KiInsertTimer(ThreadTimer
, *Timeout
)) {
302 /* Return a timeout if we couldn't insert the timer for some reason */
303 Status
= STATUS_TIMEOUT
;
308 /* Link the Object to this Wait Block */
309 InsertTailList(&CurrentObject
->WaitListHead
, &WaitBlock
->WaitListEntry
);
311 /* Handle Kernel Queues */
312 if (CurrentThread
->Queue
) {
314 DPRINT("Waking Queue\n");
315 KiWakeQueue(CurrentThread
->Queue
);
318 /* Block the Thread */
319 DPRINT("Blocking the Thread: %d, %d, %d, %x\n", Alertable
, WaitMode
, WaitReason
, KeGetCurrentThread());
320 KiBlockThread(&Status
,
325 /* Check if we were executing an APC */
326 if (Status
!= STATUS_KERNEL_APC
) {
332 DPRINT("Looping Again\n");
333 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
337 /* Release the Lock, we are done */
338 DPRINT("Returning from KeWaitForMultipleObjects(), %x. Status: %d\n", KeGetCurrentThread(), Status
);
339 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
343 /* Adjust the Quantum */
344 KiAdjustQuantumThread(CurrentThread
);
346 /* Release & Return */
347 DPRINT("Returning from KeWaitForMultipleObjects(), %x. Status: %d\n. We did not wait.", KeGetCurrentThread(), Status
);
348 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
356 KeWaitForMultipleObjects(ULONG Count
,
359 KWAIT_REASON WaitReason
,
360 KPROCESSOR_MODE WaitMode
,
362 PLARGE_INTEGER Timeout
,
363 PKWAIT_BLOCK WaitBlockArray
)
365 PDISPATCHER_HEADER CurrentObject
;
366 PKWAIT_BLOCK WaitBlock
;
367 PKWAIT_BLOCK TimerWaitBlock
;
369 PKTHREAD CurrentThread
= KeGetCurrentThread();
370 ULONG AllObjectsSignaled
;
375 DPRINT("Entering KeWaitForMultipleObjects(Count %lu Object[] %p) "
376 "PsGetCurrentThread() %x, Timeout %x\n", Count
, Object
, PsGetCurrentThread(), Timeout
);
378 /* Set the Current Thread */
379 CurrentThread
= KeGetCurrentThread();
381 /* Check if the lock is already held */
382 if (CurrentThread
->WaitNext
) {
384 /* Lock is held, disable Wait Next */
385 DPRINT("Lock is held\n");
386 CurrentThread
->WaitNext
= FALSE
;
390 /* Lock not held, acquire it */
391 DPRINT("Lock is not held, acquiring\n");
392 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
395 /* Make sure the Wait Count is valid for the Thread and Maximum Wait Objects */
396 if (!WaitBlockArray
) {
398 /* Check in regards to the Thread Object Limit */
399 if (Count
> THREAD_WAIT_OBJECTS
) {
401 KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED
);
404 /* Use the Thread's Wait Block */
405 WaitBlockArray
= &CurrentThread
->WaitBlock
[0];
409 /* Using our own Block Array. Check in regards to System Object Limit */
410 if (Count
> MAXIMUM_WAIT_OBJECTS
) {
412 KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED
);
416 /* Start the actual Loop */
419 /* Get the current Wait Status */
420 WaitStatus
= CurrentThread
->WaitStatus
;
422 /* Append wait block to the KTHREAD wait block list */
423 CurrentThread
->WaitBlockList
= WaitBlock
= WaitBlockArray
;
425 /* Check if the wait is (already) satisfied */
426 AllObjectsSignaled
= TRUE
;
428 /* First, we'll try to satisfy the wait directly */
429 for (WaitIndex
= 0; WaitIndex
< Count
; WaitIndex
++) {
431 /* Get the Current Object */
432 CurrentObject
= (PDISPATCHER_HEADER
)Object
[WaitIndex
];
434 /* Check if the Object is Signaled */
435 if (KiIsObjectSignaled(CurrentObject
, CurrentThread
)) {
437 /* Check what kind of wait this is */
438 if (WaitType
== WaitAny
) {
440 /* This is a Wait Any, so just unwait this guy and exit */
441 if (CurrentObject
->SignalState
!= (LONG
)MINLONG
) {
443 /* It has a normal signal state, so unwait it and return */
444 KiSatisfyObjectWait(CurrentObject
, CurrentThread
);
445 Status
= STATUS_WAIT_0
| WaitIndex
;
450 /* Is this a Mutant? */
451 if (CurrentObject
->Type
== MutantObject
) {
453 /* According to wasm.ru, we must raise this exception (tested and true) */
454 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
455 ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED
);
462 /* One of the objects isn't signaled... if this is a WaitAll, we will fail later */
463 AllObjectsSignaled
= FALSE
;
466 /* Set up a Wait Block for this Object */
467 WaitBlock
->Object
= CurrentObject
;
468 WaitBlock
->Thread
= CurrentThread
;
469 WaitBlock
->WaitKey
= (USHORT
)(STATUS_WAIT_0
+ WaitIndex
);
470 WaitBlock
->WaitType
= (USHORT
)WaitType
;
471 WaitBlock
->NextWaitBlock
= WaitBlock
+ 1;
473 /* Move to the next Wait Block */
474 WaitBlock
= WaitBlock
->NextWaitBlock
;
477 /* Return to the Root Wait Block */
479 WaitBlock
->NextWaitBlock
= WaitBlockArray
;
481 /* Check if this is a Wait All and all the objects are signaled */
482 if ((WaitType
== WaitAll
) && (AllObjectsSignaled
)) {
484 /* Return to the Root Wait Block */
485 WaitBlock
= CurrentThread
->WaitBlockList
;
487 /* Satisfy their Waits and return to the caller */
488 KiSatisifyMultipleObjectWaits(WaitBlock
);
489 Status
= STATUS_WAIT_0
;
493 /* Make sure we can satisfy the Alertable request */
494 if (KiCheckAlertability(Alertable
, CurrentThread
, WaitMode
, &Status
))
497 /* Set the Wait Status */
498 CurrentThread
->WaitStatus
= Status
;
500 /* Enable the Timeout Timer if there was any specified */
501 if (Timeout
!= NULL
) {
503 /* However if 0 timeout was specified, then we must fail since we need to peform a wait */
504 if (!Timeout
->QuadPart
) {
506 /* Return a timeout */
507 Status
= STATUS_TIMEOUT
;
511 /* Point to Timer Wait Block and Thread Timer */
512 TimerWaitBlock
= &CurrentThread
->WaitBlock
[TIMER_WAIT_BLOCK
];
513 ThreadTimer
= &CurrentThread
->Timer
;
515 /* Connect the Timer Wait Block */
516 WaitBlock
->NextWaitBlock
= TimerWaitBlock
;
518 /* Set up the Timer Wait Block */
519 TimerWaitBlock
->Object
= (PVOID
)ThreadTimer
;
520 TimerWaitBlock
->Thread
= CurrentThread
;
521 TimerWaitBlock
->WaitKey
= STATUS_TIMEOUT
;
522 TimerWaitBlock
->WaitType
= WaitAny
;
523 TimerWaitBlock
->NextWaitBlock
= WaitBlockArray
;
525 /* Link the timer to this Wait Block */
526 InitializeListHead(&ThreadTimer
->Header
.WaitListHead
);
528 /* Insert the Timer into the Timer Lists and enable it */
529 if (!KiInsertTimer(ThreadTimer
, *Timeout
)) {
531 /* Return a timeout if we couldn't insert the timer for some reason */
532 Status
= STATUS_TIMEOUT
;
537 /* Insert into Object's Wait List*/
538 WaitBlock
= CurrentThread
->WaitBlockList
;
541 /* Get the Current Object */
542 CurrentObject
= WaitBlock
->Object
;
544 /* Link the Object to this Wait Block */
545 InsertTailList(&CurrentObject
->WaitListHead
, &WaitBlock
->WaitListEntry
);
547 /* Move to the next Wait Block */
548 WaitBlock
= WaitBlock
->NextWaitBlock
;
549 } while (WaitBlock
!= WaitBlockArray
);
551 /* Handle Kernel Queues */
552 if (CurrentThread
->Queue
) {
554 DPRINT("Waking Queue\n");
555 KiWakeQueue(CurrentThread
->Queue
);
558 /* Block the Thread */
559 DPRINT("Blocking the Thread: %d, %d, %d, %x\n", Alertable
, WaitMode
,
560 WaitReason
, KeGetCurrentThread());
561 KiBlockThread(&Status
,
566 /* Check if we were executing an APC */
567 DPRINT("Thread is back\n");
568 if (Status
!= STATUS_KERNEL_APC
) {
574 DPRINT("Looping Again\n");
575 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
579 /* Release the Lock, we are done */
580 DPRINT("Returning, %x. Status: %d\n", KeGetCurrentThread(), Status
);
581 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
585 /* Adjust the Quantum */
586 KiAdjustQuantumThread(CurrentThread
);
588 /* Release & Return */
589 DPRINT("Returning, %x. Status: %d\n. We did not wait.",
590 KeGetCurrentThread(), Status
);
591 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
597 KiSatisfyObjectWait(PDISPATCHER_HEADER Object
,
601 /* Special case for Mutants */
602 if (Object
->Type
== MutantObject
) {
604 /* Decrease the Signal State */
605 Object
->SignalState
--;
607 /* Check if it's now non-signaled */
608 if (Object
->SignalState
== 0) {
610 /* Set the Owner Thread */
611 ((PKMUTANT
)Object
)->OwnerThread
= Thread
;
613 /* Disable APCs if needed */
614 Thread
->KernelApcDisable
-= ((PKMUTANT
)Object
)->ApcDisable
;
616 /* Check if it's abandoned */
617 if (((PKMUTANT
)Object
)->Abandoned
) {
620 ((PKMUTANT
)Object
)->Abandoned
= FALSE
;
623 Thread
->WaitStatus
= STATUS_ABANDONED
;
626 /* Insert it into the Mutant List */
627 InsertHeadList(&Thread
->MutantListHead
, &((PKMUTANT
)Object
)->MutantListEntry
);
630 } else if ((Object
->Type
& TIMER_OR_EVENT_TYPE
) == EventSynchronizationObject
) {
632 /* These guys (Syncronization Timers and Events) just get un-signaled */
633 Object
->SignalState
= 0;
635 } else if (Object
->Type
== SemaphoreObject
) {
637 /* These ones can have multiple signalings, so we only decrease it */
638 Object
->SignalState
--;
644 KiWaitTest(PDISPATCHER_HEADER Object
,
647 PLIST_ENTRY WaitEntry
;
648 PLIST_ENTRY WaitList
;
649 PKWAIT_BLOCK CurrentWaitBlock
;
650 PKWAIT_BLOCK NextWaitBlock
;
653 /* Loop the Wait Entries */
654 DPRINT("KiWaitTest for Object: %x\n", Object
);
655 WaitList
= &Object
->WaitListHead
;
656 WaitEntry
= WaitList
->Flink
;
657 while ((WaitEntry
!= WaitList
) && (Object
->SignalState
> 0)) {
659 /* Get the current wait block */
660 CurrentWaitBlock
= CONTAINING_RECORD(WaitEntry
, KWAIT_BLOCK
, WaitListEntry
);
661 WaitThread
= CurrentWaitBlock
->Thread
;
663 /* Check the current Wait Mode */
664 if (CurrentWaitBlock
->WaitType
== WaitAny
) {
666 /* Easy case, satisfy only this wait */
667 DPRINT("Satisfiying a Wait any\n");
668 WaitEntry
= WaitEntry
->Blink
;
669 KiSatisfyObjectWait(Object
, WaitThread
);
673 /* Everything must be satisfied */
674 DPRINT("Checking for a Wait All\n");
675 NextWaitBlock
= CurrentWaitBlock
->NextWaitBlock
;
677 /* Loop first to make sure they are valid */
678 while (NextWaitBlock
!= CurrentWaitBlock
) {
680 /* Check if the object is signaled */
681 DPRINT("Checking: %x %d\n", NextWaitBlock
->Object
, Object
->SignalState
);
682 if (!KiIsObjectSignaled(NextWaitBlock
->Object
, WaitThread
)) {
684 /* It's not, move to the next one */
685 DPRINT("One of the object is non-signaled, sorry.\n");
689 /* Go to the next Wait block */
690 NextWaitBlock
= NextWaitBlock
->NextWaitBlock
;
693 /* All the objects are signaled, we can satisfy */
694 DPRINT("Satisfiying a Wait All\n");
695 WaitEntry
= WaitEntry
->Blink
;
696 KiSatisifyMultipleObjectWaits(CurrentWaitBlock
);
699 /* All waits satisfied, unwait the thread */
700 DPRINT("Unwaiting the Thread\n");
701 KiAbortWaitThread(WaitThread
, CurrentWaitBlock
->WaitKey
, Increment
);
705 WaitEntry
= WaitEntry
->Flink
;
711 /* Must be called with the dispatcher lock held */
714 KiAbortWaitThread(PKTHREAD Thread
,
718 PKWAIT_BLOCK WaitBlock
;
720 /* If we are blocked, we must be waiting on something also */
721 DPRINT("KiAbortWaitThread: %x, Status: %x, %x \n", Thread
, WaitStatus
, Thread
->WaitBlockList
);
722 ASSERT((Thread
->State
== Waiting
) == (Thread
->WaitBlockList
!= NULL
));
724 /* Remove the Wait Blocks from the list */
725 DPRINT("Removing waits\n");
726 WaitBlock
= Thread
->WaitBlockList
;
730 DPRINT("Removing Waitblock: %x, %x\n", WaitBlock
, WaitBlock
->NextWaitBlock
);
731 RemoveEntryList(&WaitBlock
->WaitListEntry
);
733 /* Go to the next one */
734 WaitBlock
= WaitBlock
->NextWaitBlock
;
735 } while (WaitBlock
!= Thread
->WaitBlockList
);
737 /* Check if there's a Thread Timer */
738 if (Thread
->Timer
.Header
.Inserted
) {
740 /* Cancel the Thread Timer with the no-lock fastpath */
741 DPRINT("Removing the Thread's Timer\n");
742 Thread
->Timer
.Header
.Inserted
= FALSE
;
743 RemoveEntryList(&Thread
->Timer
.TimerListEntry
);
746 /* Increment the Queue's active threads */
749 DPRINT("Incrementing Queue's active threads\n");
750 Thread
->Queue
->CurrentCount
++;
753 /* Reschedule the Thread */
754 DPRINT("Unblocking the Thread\n");
755 KiUnblockThread(Thread
, &WaitStatus
, 0);
760 KiAcquireFastMutex(IN PFAST_MUTEX FastMutex
)
762 /* Increase contention count */
763 FastMutex
->Contention
++;
765 /* Wait for the event */
766 KeWaitForSingleObject(&FastMutex
->Gate
,
776 KiIsObjectSignaled(PDISPATCHER_HEADER Object
,
779 /* Mutants are...well...mutants! */
780 if (Object
->Type
== MutantObject
) {
783 * Because Cutler hates mutants, they are actually signaled if the Signal State is <= 0
784 * Well, only if they are recursivly acquired (i.e if we own it right now).
785 * Of course, they are also signaled if their signal state is 1.
787 if ((Object
->SignalState
<= 0 && ((PKMUTANT
)Object
)->OwnerThread
== Thread
) ||
788 (Object
->SignalState
== 1)) {
790 /* Signaled Mutant */
795 /* Unsignaled Mutant */
800 /* Any other object is not a mutated freak, so let's use logic */
801 return (!Object
->SignalState
<= 0);
807 KiSatisifyMultipleObjectWaits(PKWAIT_BLOCK WaitBlock
)
809 PKWAIT_BLOCK FirstBlock
= WaitBlock
;
810 PKTHREAD WaitThread
= WaitBlock
->Thread
;
812 /* Loop through all the Wait Blocks, and wake each Object */
815 /* Wake the Object */
816 KiSatisfyObjectWait(WaitBlock
->Object
, WaitThread
);
817 WaitBlock
= WaitBlock
->NextWaitBlock
;
818 } while (WaitBlock
!= FirstBlock
);
824 KeInitializeDispatcherHeader(DISPATCHER_HEADER
* Header
,
829 Header
->Type
= (UCHAR
)Type
;
830 Header
->Absolute
= 0;
831 Header
->Inserted
= 0;
832 Header
->Size
= (UCHAR
)Size
;
833 Header
->SignalState
= SignalState
;
834 InitializeListHead(&(Header
->WaitListHead
));
840 KeAcquireDispatcherDatabaseLock(VOID
)
844 KeAcquireSpinLock (&DispatcherDatabaseLock
, &OldIrql
);
851 KeAcquireDispatcherDatabaseLockAtDpcLevel(VOID
)
853 KeAcquireSpinLockAtDpcLevel (&DispatcherDatabaseLock
);
859 KeInitializeDispatcher(VOID
)
861 /* Initialize the Dispatcher Lock */
862 KeInitializeSpinLock(&DispatcherDatabaseLock
);
868 KeReleaseDispatcherDatabaseLock(KIRQL OldIrql
)
870 /* If it's the idle thread, dispatch */
871 if (!KeIsExecutingDpc() && OldIrql
< DISPATCH_LEVEL
&& KeGetCurrentThread() != NULL
&&
872 KeGetCurrentThread() == KeGetCurrentPrcb()->IdleThread
) {
874 KiDispatchThreadNoLock(Ready
);
875 KeLowerIrql(OldIrql
);
879 /* Just release the spin lock */
880 KeReleaseSpinLock(&DispatcherDatabaseLock
, OldIrql
);
887 KeReleaseDispatcherDatabaseLockFromDpcLevel(VOID
)
889 KeReleaseSpinLockFromDpcLevel(&DispatcherDatabaseLock
);