2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel
4 * FILE: ntoskrnl/ke/wait.c
5 * PURPOSE: Manages waiting for Dispatcher Objects
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
10 /* INCLUDES ******************************************************************/
15 #include <internal/debug.h>
17 /* GLOBALS ******************************************************************/
19 KSPIN_LOCK DispatcherDatabaseLock
;
21 /* PRIVATE FUNCTIONS *********************************************************/
24 * Rules for checking alertability:
25 * - For Alertable waits ONLY:
26 * * We don't wait and return STATUS_ALERTED if the thread is alerted
27 * in EITHER the specified wait mode OR in Kernel Mode.
28 * - For BOTH Alertable AND Non-Alertable waits:
29 * * We don't want and return STATUS_USER_APC if the User Mode APC list
30 * is not empty AND the wait mode is User Mode.
32 #define KiCheckAlertability() \
35 if (CurrentThread->Alerted[(int)WaitMode]) \
37 CurrentThread->Alerted[(int)WaitMode] = FALSE; \
38 WaitStatus = STATUS_ALERTED; \
41 else if ((WaitMode != KernelMode) && \
42 (!IsListEmpty(&CurrentThread->ApcState.ApcListHead[UserMode])))\
44 CurrentThread->ApcState.UserApcPending = TRUE; \
45 WaitStatus = STATUS_USER_APC; \
48 else if (CurrentThread->Alerted[KernelMode]) \
50 CurrentThread->Alerted[KernelMode] = FALSE; \
51 WaitStatus = STATUS_ALERTED; \
55 else if ((WaitMode != KernelMode) && \
56 (CurrentThread->ApcState.UserApcPending)) \
58 WaitStatus = STATUS_USER_APC; \
62 /* PUBLIC FUNCTIONS **********************************************************/
66 KiWaitSatisfyAll(PKWAIT_BLOCK FirstBlock
)
68 PKWAIT_BLOCK WaitBlock
= FirstBlock
;
69 PKTHREAD WaitThread
= WaitBlock
->Thread
;
71 /* Loop through all the Wait Blocks, and wake each Object */
74 /* Make sure it hasn't timed out */
75 if (WaitBlock
->WaitKey
!= STATUS_TIMEOUT
)
78 KiSatisfyObjectWait((PKMUTANT
)WaitBlock
->Object
, WaitThread
);
81 /* Move to the next block */
82 WaitBlock
= WaitBlock
->NextWaitBlock
;
84 while (WaitBlock
!= FirstBlock
);
90 * FUNCTION: Puts the current thread into an alertable or nonalertable
91 * wait state for a given internal
93 * WaitMode = Processor mode in which the caller is waiting
94 * Altertable = Specifies if the wait is alertable
95 * Interval = Specifies the interval to wait
100 KeDelayExecutionThread(KPROCESSOR_MODE WaitMode
,
102 PLARGE_INTEGER Interval
)
104 PKWAIT_BLOCK TimerWaitBlock
;
106 PKTHREAD CurrentThread
= KeGetCurrentThread();
107 NTSTATUS WaitStatus
= STATUS_SUCCESS
;
108 DPRINT("Entering KeDelayExecutionThread\n");
110 /* Check if the lock is already held */
111 if (CurrentThread
->WaitNext
)
113 /* Lock is held, disable Wait Next */
114 DPRINT("Lock is held\n");
115 CurrentThread
->WaitNext
= FALSE
;
119 /* Lock not held, acquire it */
120 DPRINT("Lock is not held, acquiring\n");
121 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
124 /* Use built-in Wait block */
125 TimerWaitBlock
= &CurrentThread
->WaitBlock
[TIMER_WAIT_BLOCK
];
127 /* Start Wait Loop */
130 /* Check if a kernel APC is pending and we were below APC_LEVEL */
131 if ((CurrentThread
->ApcState
.KernelApcPending
) &&
132 (CurrentThread
->WaitIrql
< APC_LEVEL
))
134 /* Unlock the dispatcher */
135 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
139 /* Check if we can do an alertable wait, if requested */
140 KiCheckAlertability();
143 CurrentThread
->WaitStatus
= STATUS_WAIT_0
;
146 ThreadTimer
= &CurrentThread
->Timer
;
148 /* Setup the Wait Block */
149 CurrentThread
->WaitBlockList
= TimerWaitBlock
;
150 TimerWaitBlock
->NextWaitBlock
= TimerWaitBlock
;
152 /* Link the timer to this Wait Block */
153 ThreadTimer
->Header
.WaitListHead
.Flink
= &TimerWaitBlock
->WaitListEntry
;
154 ThreadTimer
->Header
.WaitListHead
.Blink
= &TimerWaitBlock
->WaitListEntry
;
156 /* Insert the Timer into the Timer Lists and enable it */
157 if (!KiInsertTimer(ThreadTimer
, *Interval
))
159 /* FIXME: The timer already expired, we should find a new ready thread */
160 WaitStatus
= STATUS_SUCCESS
;
164 /* Handle Kernel Queues */
165 if (CurrentThread
->Queue
)
167 DPRINT("Waking Queue\n");
168 KiWakeQueue(CurrentThread
->Queue
);
171 /* Setup the wait information */
172 CurrentThread
->Alertable
= Alertable
;
173 CurrentThread
->WaitMode
= WaitMode
;
174 CurrentThread
->WaitReason
= DelayExecution
;
175 CurrentThread
->WaitTime
= ((PLARGE_INTEGER
)&KeTickCount
)->LowPart
;
176 CurrentThread
->State
= Waiting
;
178 /* Find a new thread to run */
179 DPRINT("Swapping threads\n");
180 WaitStatus
= KiSwapThread();
182 /* Check if we were executing an APC or if we timed out */
183 if (WaitStatus
!= STATUS_KERNEL_APC
)
185 /* This is a good thing */
186 if (WaitStatus
== STATUS_TIMEOUT
) WaitStatus
= STATUS_SUCCESS
;
192 /* FIXME: Fixup interval */
194 /* Acquire again the lock */
196 DPRINT("Looping again\n");
197 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
201 /* Release the Lock, we are done */
202 DPRINT("Returning from KeDelayExecutionThread(), %x. Status: %d\n",
203 KeGetCurrentThread(), Status
);
204 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
211 * FUNCTION: Puts the current thread into a wait state until the
212 * given dispatcher object is set to signalled
214 * Object = Object to wait on
215 * WaitReason = Reason for the wait (debugging aid)
216 * WaitMode = Can be KernelMode or UserMode, if UserMode then
217 * user-mode APCs can be delivered and the thread's
218 * stack can be paged out
219 * Altertable = Specifies if the wait is a alertable
220 * Timeout = Optional timeout value
225 KeWaitForSingleObject(PVOID Object
,
226 KWAIT_REASON WaitReason
,
227 KPROCESSOR_MODE WaitMode
,
229 PLARGE_INTEGER Timeout
)
231 PKMUTANT CurrentObject
;
232 PKWAIT_BLOCK WaitBlock
;
233 PKWAIT_BLOCK TimerWaitBlock
;
235 PKTHREAD CurrentThread
= KeGetCurrentThread();
236 NTSTATUS WaitStatus
= STATUS_SUCCESS
;
237 DPRINT("Entering KeWaitForSingleObject\n");
239 /* Check if the lock is already held */
240 if (CurrentThread
->WaitNext
)
242 /* Lock is held, disable Wait Next */
243 DPRINT("Lock is held\n");
244 CurrentThread
->WaitNext
= FALSE
;
248 /* Lock not held, acquire it */
249 DPRINT("Lock is not held, acquiring\n");
250 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
253 /* Start the actual Loop */
256 /* Check if a kernel APC is pending and we were below APC_LEVEL */
257 if ((CurrentThread
->ApcState
.KernelApcPending
) &&
258 (CurrentThread
->WaitIrql
< APC_LEVEL
))
260 /* Unlock the dispatcher */
261 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
265 /* Set default status */
266 CurrentThread
->WaitStatus
= STATUS_WAIT_0
;
268 /* Append wait block to the KTHREAD wait block list */
269 CurrentThread
->WaitBlockList
= WaitBlock
= &CurrentThread
->WaitBlock
[0];
271 /* Get the Current Object */
272 CurrentObject
= (PKMUTANT
)Object
;
274 /* Check if it's a mutant */
275 if (CurrentObject
->Header
.Type
== MutantObject
)
277 /* Check its signal state or if we own it */
278 if ((CurrentObject
->Header
.SignalState
> 0) ||
279 (CurrentThread
== CurrentObject
->OwnerThread
))
281 /* Just unwait this guy and exit */
282 if (CurrentObject
->Header
.SignalState
!= (LONG
)MINLONG
)
284 /* It has a normal signal state, so unwait it and return */
285 KiSatisfyMutantWait(CurrentObject
, CurrentThread
);
286 WaitStatus
= CurrentThread
->WaitStatus
;
291 /* According to wasm.ru, we must raise this exception (tested and true) */
292 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
293 ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED
);
297 else if (CurrentObject
->Header
.SignalState
> 0)
299 /* Another satisfied object */
300 KiSatisfyNonMutantWait(CurrentObject
, CurrentThread
);
301 WaitStatus
= STATUS_WAIT_0
;
305 /* Set up the Wait Block */
306 WaitBlock
->Object
= CurrentObject
;
307 WaitBlock
->Thread
= CurrentThread
;
308 WaitBlock
->WaitKey
= (USHORT
)(STATUS_SUCCESS
);
309 WaitBlock
->WaitType
= WaitAny
;
310 WaitBlock
->NextWaitBlock
= WaitBlock
;
312 /* Make sure we can satisfy the Alertable request */
313 KiCheckAlertability();
315 /* Enable the Timeout Timer if there was any specified */
318 /* Fail if the timeout interval is actually 0 */
319 if (!Timeout
->QuadPart
)
321 /* Return a timeout */
322 WaitStatus
= STATUS_TIMEOUT
;
326 /* Point to Timer Wait Block and Thread Timer */
327 TimerWaitBlock
= &CurrentThread
->WaitBlock
[TIMER_WAIT_BLOCK
];
328 ThreadTimer
= &CurrentThread
->Timer
;
330 /* Connect the Timer Wait Block */
331 WaitBlock
->NextWaitBlock
= TimerWaitBlock
;
333 /* Set up the Timer Wait Block */
334 TimerWaitBlock
->NextWaitBlock
= WaitBlock
;
336 /* Link the timer to this Wait Block */
337 ThreadTimer
->Header
.WaitListHead
.Flink
= &TimerWaitBlock
->WaitListEntry
;
338 ThreadTimer
->Header
.WaitListHead
.Blink
= &TimerWaitBlock
->WaitListEntry
;
340 /* Insert the Timer into the Timer Lists and enable it */
341 if (!KiInsertTimer(ThreadTimer
, *Timeout
))
343 /* Return a timeout if we couldn't insert the timer */
344 WaitStatus
= STATUS_TIMEOUT
;
349 /* Link the Object to this Wait Block */
350 InsertTailList(&CurrentObject
->Header
.WaitListHead
,
351 &WaitBlock
->WaitListEntry
);
353 /* Handle Kernel Queues */
354 if (CurrentThread
->Queue
)
356 DPRINT("Waking Queue\n");
357 KiWakeQueue(CurrentThread
->Queue
);
360 /* Setup the wait information */
361 CurrentThread
->Alertable
= Alertable
;
362 CurrentThread
->WaitMode
= WaitMode
;
363 CurrentThread
->WaitReason
= WaitReason
;
364 CurrentThread
->WaitTime
= ((PLARGE_INTEGER
)&KeTickCount
)->LowPart
;
365 CurrentThread
->State
= Waiting
;
367 /* Find a new thread to run */
368 DPRINT("Swapping threads\n");
369 WaitStatus
= KiSwapThread();
371 /* Check if we were executing an APC */
372 if (WaitStatus
!= STATUS_KERNEL_APC
)
378 /* Check if we had a timeout */
381 /* FIXME: Fixup interval */
384 /* Acquire again the lock */
386 DPRINT("Looping again\n");
387 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
391 /* Release the Lock, we are done */
392 DPRINT("Returning from KeWaitForMultipleObjects(), %x. Status: %d\n",
393 KeGetCurrentThread(), WaitStatus
);
394 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
398 /* Adjust the Quantum */
399 KiAdjustQuantumThread(CurrentThread
);
401 /* Release & Return */
402 DPRINT("Quick-return from KeWaitForMultipleObjects(), %x. Status: %d\n.",
403 KeGetCurrentThread(), WaitStatus
);
404 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
413 KeWaitForMultipleObjects(ULONG Count
,
416 KWAIT_REASON WaitReason
,
417 KPROCESSOR_MODE WaitMode
,
419 PLARGE_INTEGER Timeout
,
420 PKWAIT_BLOCK WaitBlockArray
)
422 PKMUTANT CurrentObject
;
423 PKWAIT_BLOCK WaitBlock
;
424 PKWAIT_BLOCK TimerWaitBlock
;
426 PKTHREAD CurrentThread
= KeGetCurrentThread();
427 ULONG AllObjectsSignaled
;
429 NTSTATUS WaitStatus
= STATUS_SUCCESS
;
430 DPRINT("Entering KeWaitForMultipleObjects(Count %lu Object[] %p) "
431 "PsGetCurrentThread() %x, Timeout %x\n",
432 Count
, Object
, PsGetCurrentThread(), Timeout
);
434 /* Set the Current Thread */
435 CurrentThread
= KeGetCurrentThread();
437 /* Check if the lock is already held */
438 if (CurrentThread
->WaitNext
)
440 /* Lock is held, disable Wait Next */
441 DPRINT("Lock is held\n");
442 CurrentThread
->WaitNext
= FALSE
;
446 /* Lock not held, acquire it */
447 DPRINT("Lock is not held, acquiring\n");
448 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
451 /* Make sure the Wait Count is valid for the Thread and Maximum Wait Objects */
454 /* Check in regards to the Thread Object Limit */
455 if (Count
> THREAD_WAIT_OBJECTS
) KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED
);
457 /* Use the Thread's Wait Block */
458 WaitBlockArray
= &CurrentThread
->WaitBlock
[0];
462 /* Using our own Block Array. Check in regards to System Object Limit */
463 if (Count
> MAXIMUM_WAIT_OBJECTS
) KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED
);
466 /* Start the actual Loop */
469 /* Check if a kernel APC is pending and we were below APC_LEVEL */
470 if ((CurrentThread
->ApcState
.KernelApcPending
) &&
471 (CurrentThread
->WaitIrql
< APC_LEVEL
))
473 /* Unlock the dispatcher */
474 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
478 /* Append wait block to the KTHREAD wait block list */
479 CurrentThread
->WaitBlockList
= WaitBlock
= WaitBlockArray
;
481 /* Set default wait status */
482 CurrentThread
->WaitStatus
= STATUS_WAIT_0
;
484 /* Check if the wait is (already) satisfied */
485 AllObjectsSignaled
= TRUE
;
487 /* First, we'll try to satisfy the wait directly */
488 for (WaitIndex
= 0; WaitIndex
< Count
; WaitIndex
++)
490 /* Get the Current Object */
491 CurrentObject
= (PKMUTANT
)Object
[WaitIndex
];
493 /* Check the type of wait */
494 if (WaitType
== WaitAny
)
496 /* Check if the Object is a mutant */
497 if (CurrentObject
->Header
.Type
== MutantObject
)
499 /* Check if it's signaled */
500 if ((CurrentObject
->Header
.SignalState
> 0) ||
501 (CurrentThread
== CurrentObject
->OwnerThread
))
503 /* This is a Wait Any, so just unwait this and exit */
504 if (CurrentObject
->Header
.SignalState
!= (LONG
)MINLONG
)
506 /* Normal signal state, so unwait it and return */
507 KiSatisfyMutantWait(CurrentObject
, CurrentThread
);
508 WaitStatus
= CurrentThread
->WaitStatus
| WaitIndex
;
513 /* According to wasm.ru, we must raise this exception (tested and true) */
514 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
515 ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED
);
519 else if (CurrentObject
->Header
.SignalState
> 0)
521 /* Another signaled object, unwait and return */
522 KiSatisfyNonMutantWait(CurrentObject
, CurrentThread
);
523 WaitStatus
= WaitIndex
;
529 /* Check if we're dealing with a mutant again */
530 if (CurrentObject
->Header
.Type
== MutantObject
)
532 /* Check if it has an invalid count */
533 if ((CurrentThread
== CurrentObject
->OwnerThread
) &&
534 (CurrentObject
->Header
.SignalState
== MINLONG
))
536 /* Raise an exception */
537 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
538 ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED
);
540 else if ((CurrentObject
->Header
.SignalState
<= 0) &&
541 (CurrentThread
!= CurrentObject
->OwnerThread
))
543 /* We don't own it, can't satisfy the wait */
544 AllObjectsSignaled
= FALSE
;
547 else if (CurrentObject
->Header
.SignalState
<= 0)
549 /* Not signaled, can't satisfy */
550 AllObjectsSignaled
= FALSE
;
554 /* Set up a Wait Block for this Object */
555 WaitBlock
->Object
= CurrentObject
;
556 WaitBlock
->Thread
= CurrentThread
;
557 WaitBlock
->WaitKey
= (USHORT
)WaitIndex
;
558 WaitBlock
->WaitType
= (USHORT
)WaitType
;
559 WaitBlock
->NextWaitBlock
= WaitBlock
+ 1;
561 /* Move to the next Wait Block */
562 WaitBlock
= WaitBlock
->NextWaitBlock
;
565 /* Return to the Root Wait Block */
567 WaitBlock
->NextWaitBlock
= WaitBlockArray
;
569 /* Check if this is a Wait All and all the objects are signaled */
570 if ((WaitType
== WaitAll
) && (AllObjectsSignaled
))
572 /* Return to the Root Wait Block */
573 WaitBlock
= CurrentThread
->WaitBlockList
;
575 /* Satisfy their Waits and return to the caller */
576 KiWaitSatisfyAll(WaitBlock
);
577 WaitStatus
= CurrentThread
->WaitStatus
;
581 /* Make sure we can satisfy the Alertable request */
582 KiCheckAlertability();
584 /* Enable the Timeout Timer if there was any specified */
587 /* Make sure the timeout interval isn't actually 0 */
588 if (!Timeout
->QuadPart
)
590 /* Return a timeout */
591 WaitStatus
= STATUS_TIMEOUT
;
595 /* Point to Timer Wait Block and Thread Timer */
596 TimerWaitBlock
= &CurrentThread
->WaitBlock
[TIMER_WAIT_BLOCK
];
597 ThreadTimer
= &CurrentThread
->Timer
;
599 /* Connect the Timer Wait Block */
600 WaitBlock
->NextWaitBlock
= TimerWaitBlock
;
602 /* Set up the Timer Wait Block */
603 TimerWaitBlock
->NextWaitBlock
= WaitBlockArray
;
605 /* Initialize the list head */
606 InitializeListHead(&ThreadTimer
->Header
.WaitListHead
);
608 /* Insert the Timer into the Timer Lists and enable it */
609 if (!KiInsertTimer(ThreadTimer
, *Timeout
))
611 /* Return a timeout if we couldn't insert the timer */
612 WaitStatus
= STATUS_TIMEOUT
;
617 /* Insert into Object's Wait List*/
618 WaitBlock
= CurrentThread
->WaitBlockList
;
621 /* Get the Current Object */
622 CurrentObject
= WaitBlock
->Object
;
624 /* Link the Object to this Wait Block */
625 InsertTailList(&CurrentObject
->Header
.WaitListHead
,
626 &WaitBlock
->WaitListEntry
);
628 /* Move to the next Wait Block */
629 WaitBlock
= WaitBlock
->NextWaitBlock
;
631 while (WaitBlock
!= WaitBlockArray
);
633 /* Handle Kernel Queues */
634 if (CurrentThread
->Queue
)
636 DPRINT("Waking Queue\n");
637 KiWakeQueue(CurrentThread
->Queue
);
640 /* Setup the wait information */
641 CurrentThread
->Alertable
= Alertable
;
642 CurrentThread
->WaitMode
= WaitMode
;
643 CurrentThread
->WaitReason
= WaitReason
;
644 CurrentThread
->WaitTime
= ((PLARGE_INTEGER
)&KeTickCount
)->LowPart
;
645 CurrentThread
->State
= Waiting
;
647 /* Find a new thread to run */
648 DPRINT("Swapping threads\n");
649 WaitStatus
= KiSwapThread();
651 /* Check if we were executing an APC */
652 DPRINT("Thread is back\n");
653 if (WaitStatus
!= STATUS_KERNEL_APC
)
659 /* Check if we had a timeout */
662 /* FIXME: Fixup interval */
665 /* Acquire again the lock */
667 DPRINT("Looping again\n");
668 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
672 /* Release the Lock, we are done */
673 DPRINT("Returning, %x. Status: %d\n", KeGetCurrentThread(), WaitStatus
);
674 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
678 /* Adjust the Quantum */
679 KiAdjustQuantumThread(CurrentThread
);
681 /* Release & Return */
682 DPRINT("Returning, %x. Status: %d\n. We did not wait.",
683 KeGetCurrentThread(), WaitStatus
);
684 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
690 KiWaitTest(PVOID ObjectPointer
,
693 PLIST_ENTRY WaitEntry
;
694 PLIST_ENTRY WaitList
;
695 PKWAIT_BLOCK CurrentWaitBlock
;
696 PKWAIT_BLOCK NextWaitBlock
;
698 PKMUTANT FirstObject
= ObjectPointer
, Object
;
700 /* Loop the Wait Entries */
701 DPRINT("KiWaitTest for Object: %x\n", FirstObject
);
702 WaitList
= &FirstObject
->Header
.WaitListHead
;
703 WaitEntry
= WaitList
->Flink
;
704 while ((FirstObject
->Header
.SignalState
> 0) && (WaitEntry
!= WaitList
))
706 /* Get the current wait block */
707 CurrentWaitBlock
= CONTAINING_RECORD(WaitEntry
,
710 WaitThread
= CurrentWaitBlock
->Thread
;
712 /* Check the current Wait Mode */
713 if (CurrentWaitBlock
->WaitType
== WaitAny
)
715 /* Easy case, satisfy only this wait */
716 DPRINT("Satisfiying a Wait any\n");
717 WaitEntry
= WaitEntry
->Blink
;
718 KiSatisfyObjectWait(FirstObject
, WaitThread
);
722 /* Everything must be satisfied */
723 DPRINT("Checking for a Wait All\n");
724 NextWaitBlock
= CurrentWaitBlock
->NextWaitBlock
;
726 /* Loop first to make sure they are valid */
727 while (NextWaitBlock
!= CurrentWaitBlock
)
729 /* Check if the object is signaled */
730 Object
= NextWaitBlock
->Object
;
731 DPRINT("Checking: %p %d\n",
732 Object
, Object
->Header
.SignalState
);
733 if (NextWaitBlock
->WaitKey
!= STATUS_TIMEOUT
)
735 /* Check if this is a mutant */
736 if ((Object
->Header
.Type
== MutantObject
) &&
737 (Object
->Header
.SignalState
<= 0) &&
738 (WaitThread
== Object
->OwnerThread
))
740 /* It's a signaled mutant */
742 else if (Object
->Header
.SignalState
<= 0)
744 /* Skip the unwaiting */
749 /* Go to the next Wait block */
750 NextWaitBlock
= NextWaitBlock
->NextWaitBlock
;
753 /* All the objects are signaled, we can satisfy */
754 DPRINT("Satisfiying a Wait All\n");
755 WaitEntry
= WaitEntry
->Blink
;
756 KiWaitSatisfyAll(CurrentWaitBlock
);
759 /* All waits satisfied, unwait the thread */
760 DPRINT("Unwaiting the Thread\n");
761 KiAbortWaitThread(WaitThread
, CurrentWaitBlock
->WaitKey
, Increment
);
765 WaitEntry
= WaitEntry
->Flink
;
771 /* Must be called with the dispatcher lock held */
774 KiAbortWaitThread(PKTHREAD Thread
,
778 PKWAIT_BLOCK WaitBlock
;
780 /* If we are blocked, we must be waiting on something also */
781 DPRINT("KiAbortWaitThread: %x, Status: %x, %x \n",
782 Thread
, WaitStatus
, Thread
->WaitBlockList
);
784 /* Remove the Wait Blocks from the list */
785 DPRINT("Removing waits\n");
786 WaitBlock
= Thread
->WaitBlockList
;
790 DPRINT("Removing Waitblock: %x, %x\n",
791 WaitBlock
, WaitBlock
->NextWaitBlock
);
792 RemoveEntryList(&WaitBlock
->WaitListEntry
);
794 /* Go to the next one */
795 WaitBlock
= WaitBlock
->NextWaitBlock
;
796 } while (WaitBlock
!= Thread
->WaitBlockList
);
798 /* Check if there's a Thread Timer */
799 if (Thread
->Timer
.Header
.Inserted
)
801 /* Cancel the Thread Timer with the no-lock fastpath */
802 DPRINT("Removing the Thread's Timer\n");
803 Thread
->Timer
.Header
.Inserted
= FALSE
;
804 RemoveEntryList(&Thread
->Timer
.TimerListEntry
);
807 /* Increment the Queue's active threads */
810 DPRINT("Incrementing Queue's active threads\n");
811 Thread
->Queue
->CurrentCount
++;
814 /* Reschedule the Thread */
815 DPRINT("Unblocking the Thread\n");
816 KiUnblockThread(Thread
, &WaitStatus
, 0);
821 KiAcquireFastMutex(IN PFAST_MUTEX FastMutex
)
823 /* Increase contention count */
824 FastMutex
->Contention
++;
826 /* Wait for the event */
827 KeWaitForSingleObject(&FastMutex
->Gate
,
836 KiExitDispatcher(KIRQL OldIrql
)
838 /* If it's the idle thread, dispatch */
839 if (!(KeIsExecutingDpc()) &&
840 (OldIrql
< DISPATCH_LEVEL
) &&
841 (KeGetCurrentThread()) &&
842 (KeGetCurrentThread() == KeGetCurrentPrcb()->IdleThread
))
844 KiDispatchThreadNoLock(Ready
);
848 KeReleaseDispatcherDatabaseLockFromDpcLevel();
851 /* Lower irql back */
852 KeLowerIrql(OldIrql
);