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 /* 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
,
34 KPROCESSOR_MODE WaitMode
,
38 * At this point, we have to do a wait, so make sure we can make
39 * the thread Alertable if requested.
43 /* If the Thread is Alerted, set the Wait Status accordingly */
44 if (Thread
->Alerted
[(int)WaitMode
])
46 Thread
->Alerted
[(int)WaitMode
] = FALSE
;
47 DPRINT("Thread was Alerted in the specified Mode\n");
48 *Status
= STATUS_ALERTED
;
51 else if ((WaitMode
!= KernelMode
) &&
52 (!IsListEmpty(&Thread
->ApcState
.ApcListHead
[UserMode
])))
54 /* If there are User APCs Pending, then we can't really be alertable */
55 DPRINT("APCs are Pending\n");
56 Thread
->ApcState
.UserApcPending
= TRUE
;
57 *Status
= STATUS_USER_APC
;
60 else if (Thread
->Alerted
[KernelMode
])
63 * The thread is not alerted in the mode given, but it is alerted
66 Thread
->Alerted
[KernelMode
] = FALSE
;
67 DPRINT("Thread was Alerted in Kernel-Mode\n");
68 *Status
= STATUS_ALERTED
;
72 else if ((WaitMode
!= KernelMode
) &&
73 (Thread
->ApcState
.UserApcPending
))
76 * If there are User APCs Pending and we are waiting in usermode,
77 * then we must notify the caller
79 DPRINT("APCs are Pending\n");
80 *Status
= STATUS_USER_APC
;
84 /* Stay in the loop */
91 * FUNCTION: Puts the current thread into an alertable or nonalertable
92 * wait state for a given internal
94 * WaitMode = Processor mode in which the caller is waiting
95 * Altertable = Specifies if the wait is alertable
96 * Interval = Specifies the interval to wait
101 KeDelayExecutionThread(KPROCESSOR_MODE WaitMode
,
103 PLARGE_INTEGER Interval
)
105 PKWAIT_BLOCK TimerWaitBlock
;
107 PKTHREAD CurrentThread
= KeGetCurrentThread();
110 DPRINT("Entering KeDelayExecutionThread\n");
112 /* Check if the lock is already held */
113 if (CurrentThread
->WaitNext
)
115 /* Lock is held, disable Wait Next */
116 DPRINT("Lock is held\n");
117 CurrentThread
->WaitNext
= FALSE
;
121 /* Lock not held, acquire it */
122 DPRINT("Lock is not held, acquiring\n");
123 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
126 /* Use built-in Wait block */
127 TimerWaitBlock
= &CurrentThread
->WaitBlock
[TIMER_WAIT_BLOCK
];
129 /* Start Wait Loop */
132 /* Chceck if we can do an alertable wait, if requested */
133 if (KiCheckAlertability(Alertable
, CurrentThread
, WaitMode
, &Status
)) break;
136 ThreadTimer
= &CurrentThread
->Timer
;
138 /* Setup the Wait Block */
139 CurrentThread
->WaitBlockList
= TimerWaitBlock
;
140 TimerWaitBlock
->Object
= (PVOID
)ThreadTimer
;
141 TimerWaitBlock
->Thread
= CurrentThread
;
142 TimerWaitBlock
->WaitKey
= (USHORT
)STATUS_TIMEOUT
;
143 TimerWaitBlock
->WaitType
= WaitAny
;
144 TimerWaitBlock
->NextWaitBlock
= TimerWaitBlock
;
146 /* Link the timer to this Wait Block */
147 InitializeListHead(&ThreadTimer
->Header
.WaitListHead
);
148 InsertTailList(&ThreadTimer
->Header
.WaitListHead
, &TimerWaitBlock
->WaitListEntry
);
150 /* Insert the Timer into the Timer Lists and enable it */
151 if (!KiInsertTimer(ThreadTimer
, *Interval
))
153 /* FIXME: The timer already expired, we should find a new ready thread */
154 Status
= STATUS_SUCCESS
;
158 /* Handle Kernel Queues */
159 if (CurrentThread
->Queue
)
161 DPRINT("Waking Queue\n");
162 KiWakeQueue(CurrentThread
->Queue
);
165 /* Block the Thread */
166 DPRINT("Blocking the Thread: %d, %d, %x\n",
167 Alertable
, WaitMode
, KeGetCurrentThread());
168 KiBlockThread(&Status
,
173 /* Check if we were executing an APC or if we timed out */
174 if (Status
!= STATUS_KERNEL_APC
)
176 /* This is a good thing */
177 if (Status
== STATUS_TIMEOUT
) Status
= STATUS_SUCCESS
;
183 DPRINT("Looping Again\n"); // FIXME: Need to modify interval
184 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
188 /* Release the Lock, we are done */
189 DPRINT("Returning from KeDelayExecutionThread(), %x. Status: %d\n",
190 KeGetCurrentThread(), Status
);
191 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
198 * FUNCTION: Puts the current thread into a wait state until the
199 * given dispatcher object is set to signalled
201 * Object = Object to wait on
202 * WaitReason = Reason for the wait (debugging aid)
203 * WaitMode = Can be KernelMode or UserMode, if UserMode then
204 * user-mode APCs can be delivered and the thread's
205 * stack can be paged out
206 * Altertable = Specifies if the wait is a alertable
207 * Timeout = Optional timeout value
212 KeWaitForSingleObject(PVOID Object
,
213 KWAIT_REASON WaitReason
,
214 KPROCESSOR_MODE WaitMode
,
216 PLARGE_INTEGER Timeout
)
218 PKMUTANT CurrentObject
;
219 PKWAIT_BLOCK WaitBlock
;
220 PKWAIT_BLOCK TimerWaitBlock
;
222 PKTHREAD CurrentThread
= KeGetCurrentThread();
225 DPRINT("Entering KeWaitForSingleObject\n");
227 /* Check if the lock is already held */
228 if (CurrentThread
->WaitNext
)
230 /* Lock is held, disable Wait Next */
231 DPRINT("Lock is held\n");
232 CurrentThread
->WaitNext
= FALSE
;
236 /* Lock not held, acquire it */
237 DPRINT("Lock is not held, acquiring\n");
238 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
241 /* Start the actual Loop */
244 /* Get the current Wait Status */
245 WaitStatus
= CurrentThread
->WaitStatus
;
247 /* Append wait block to the KTHREAD wait block list */
248 CurrentThread
->WaitBlockList
= WaitBlock
= &CurrentThread
->WaitBlock
[0];
250 /* Get the Current Object */
251 CurrentObject
= (PKMUTANT
)Object
;
253 /* Check if it's a mutant */
254 if (CurrentObject
->Header
.Type
== MutantObject
)
256 /* Check its signal state or if we own it */
257 if ((CurrentObject
->Header
.SignalState
> 0) ||
258 (CurrentThread
== CurrentObject
->OwnerThread
))
260 /* Just unwait this guy and exit */
261 if (CurrentObject
->Header
.SignalState
!= (LONG
)MINLONG
)
263 /* It has a normal signal state, so unwait it and return */
264 KiSatisfyMutantWait(CurrentObject
, CurrentThread
);
265 Status
= STATUS_WAIT_0
;
270 /* According to wasm.ru, we must raise this exception (tested and true) */
271 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
272 ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED
);
276 else if (CurrentObject
->Header
.SignalState
> 0)
278 /* Another satisfied object */
279 KiSatisfyNonMutantWait(CurrentObject
, CurrentThread
);
280 Status
= STATUS_WAIT_0
;
284 /* Set up the Wait Block */
285 WaitBlock
->Object
= CurrentObject
;
286 WaitBlock
->Thread
= CurrentThread
;
287 WaitBlock
->WaitKey
= (USHORT
)(STATUS_WAIT_0
);
288 WaitBlock
->WaitType
= WaitAny
;
289 WaitBlock
->NextWaitBlock
= WaitBlock
;
291 /* Make sure we can satisfy the Alertable request */
292 if (KiCheckAlertability(Alertable
, CurrentThread
, WaitMode
, &Status
)) break;
294 /* Set the Wait Status */
295 CurrentThread
->WaitStatus
= Status
;
297 /* Enable the Timeout Timer if there was any specified */
300 /* Fail if the timeout interval is actually 0 */
301 if (!Timeout
->QuadPart
)
303 /* Return a timeout */
304 Status
= STATUS_TIMEOUT
;
308 /* Point to Timer Wait Block and Thread Timer */
309 TimerWaitBlock
= &CurrentThread
->WaitBlock
[TIMER_WAIT_BLOCK
];
310 ThreadTimer
= &CurrentThread
->Timer
;
312 /* Connect the Timer Wait Block */
313 WaitBlock
->NextWaitBlock
= TimerWaitBlock
;
315 /* Set up the Timer Wait Block */
316 TimerWaitBlock
->Object
= (PVOID
)ThreadTimer
;
317 TimerWaitBlock
->Thread
= CurrentThread
;
318 TimerWaitBlock
->WaitKey
= STATUS_TIMEOUT
;
319 TimerWaitBlock
->WaitType
= WaitAny
;
320 TimerWaitBlock
->NextWaitBlock
= WaitBlock
;
322 /* Link the timer to this Wait Block */
323 InitializeListHead(&ThreadTimer
->Header
.WaitListHead
);
324 InsertTailList(&ThreadTimer
->Header
.WaitListHead
,
325 &TimerWaitBlock
->WaitListEntry
);
327 /* Insert the Timer into the Timer Lists and enable it */
328 if (!KiInsertTimer(ThreadTimer
, *Timeout
))
330 /* Return a timeout if we couldn't insert the timer */
331 Status
= STATUS_TIMEOUT
;
336 /* Link the Object to this Wait Block */
337 InsertTailList(&CurrentObject
->Header
.WaitListHead
,
338 &WaitBlock
->WaitListEntry
);
340 /* Handle Kernel Queues */
341 if (CurrentThread
->Queue
)
343 DPRINT("Waking Queue\n");
344 KiWakeQueue(CurrentThread
->Queue
);
347 /* Block the Thread */
348 DPRINT("Blocking the Thread: %d, %d, %d, %x\n",
349 Alertable
, WaitMode
, WaitReason
, KeGetCurrentThread());
350 KiBlockThread(&Status
,
355 /* Check if we were executing an APC */
356 if (Status
!= STATUS_KERNEL_APC
)
362 /* Loop again and acquire the dispatcher lock */
363 DPRINT("Looping Again\n"); // FIXME: Change interval
364 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
368 /* Release the Lock, we are done */
369 DPRINT("Returning from KeWaitForMultipleObjects(), %x. Status: %d\n",
370 KeGetCurrentThread(), Status
);
371 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
375 /* Adjust the Quantum */
376 KiAdjustQuantumThread(CurrentThread
);
378 /* Release & Return */
379 DPRINT("Quick-return from KeWaitForMultipleObjects(), %x. Status: %d\n.",
380 KeGetCurrentThread(), Status
);
381 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
389 KeWaitForMultipleObjects(ULONG Count
,
392 KWAIT_REASON WaitReason
,
393 KPROCESSOR_MODE WaitMode
,
395 PLARGE_INTEGER Timeout
,
396 PKWAIT_BLOCK WaitBlockArray
)
398 PKMUTANT CurrentObject
;
399 PKWAIT_BLOCK WaitBlock
;
400 PKWAIT_BLOCK TimerWaitBlock
;
402 PKTHREAD CurrentThread
= KeGetCurrentThread();
403 ULONG AllObjectsSignaled
;
407 DPRINT("Entering KeWaitForMultipleObjects(Count %lu Object[] %p) "
408 "PsGetCurrentThread() %x, Timeout %x\n",
409 Count
, Object
, PsGetCurrentThread(), Timeout
);
411 /* Set the Current Thread */
412 CurrentThread
= KeGetCurrentThread();
414 /* Check if the lock is already held */
415 if (CurrentThread
->WaitNext
)
417 /* Lock is held, disable Wait Next */
418 DPRINT("Lock is held\n");
419 CurrentThread
->WaitNext
= FALSE
;
423 /* Lock not held, acquire it */
424 DPRINT("Lock is not held, acquiring\n");
425 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
428 /* Make sure the Wait Count is valid for the Thread and Maximum Wait Objects */
431 /* Check in regards to the Thread Object Limit */
432 if (Count
> THREAD_WAIT_OBJECTS
) KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED
);
434 /* Use the Thread's Wait Block */
435 WaitBlockArray
= &CurrentThread
->WaitBlock
[0];
439 /* Using our own Block Array. Check in regards to System Object Limit */
440 if (Count
> MAXIMUM_WAIT_OBJECTS
) KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED
);
443 /* Start the actual Loop */
446 /* Get the current Wait Status */
447 WaitStatus
= CurrentThread
->WaitStatus
;
449 /* Append wait block to the KTHREAD wait block list */
450 CurrentThread
->WaitBlockList
= WaitBlock
= WaitBlockArray
;
452 /* Check if the wait is (already) satisfied */
453 AllObjectsSignaled
= TRUE
;
455 /* First, we'll try to satisfy the wait directly */
456 for (WaitIndex
= 0; WaitIndex
< Count
; WaitIndex
++)
458 /* Get the Current Object */
459 CurrentObject
= (PKMUTANT
)Object
[WaitIndex
];
461 /* Check the type of wait */
462 if (WaitType
== WaitAny
)
464 /* Check if the Object is a mutant */
465 if (CurrentObject
->Header
.Type
== MutantObject
)
467 /* Check if it's signaled */
468 if ((CurrentObject
->Header
.SignalState
> 0) ||
469 (CurrentThread
== CurrentObject
->OwnerThread
))
471 /* This is a Wait Any, so just unwait this and exit */
472 if (CurrentObject
->Header
.SignalState
!= (LONG
)MINLONG
)
474 /* Normal signal state, so unwait it and return */
475 KiSatisfyMutantWait(CurrentObject
, CurrentThread
);
476 Status
= STATUS_WAIT_0
| WaitIndex
;
481 /* According to wasm.ru, we must raise this exception (tested and true) */
482 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
483 ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED
);
487 else if (CurrentObject
->Header
.SignalState
> 0)
489 /* Another signaled object, unwait and return */
490 KiSatisfyNonMutantWait(CurrentObject
, CurrentThread
);
497 /* Check if we're dealing with a mutant again */
498 if (CurrentObject
->Header
.Type
== MutantObject
)
500 /* Check if it has an invalid count */
501 if ((CurrentThread
== CurrentObject
->OwnerThread
) &&
502 (CurrentObject
->Header
.SignalState
== MINLONG
))
504 /* Raise an exception */
505 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
506 ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED
);
508 else if ((CurrentObject
->Header
.SignalState
<= 0) &&
509 (CurrentThread
!= CurrentObject
->OwnerThread
))
511 /* We don't own it, can't satisfy the wait */
512 AllObjectsSignaled
= FALSE
;
515 else if (CurrentObject
->Header
.SignalState
<= 0)
517 /* Not signaled, can't satisfy */
518 AllObjectsSignaled
= FALSE
;
522 /* Set up a Wait Block for this Object */
523 WaitBlock
->Object
= CurrentObject
;
524 WaitBlock
->Thread
= CurrentThread
;
525 WaitBlock
->WaitKey
= (USHORT
)WaitIndex
;
526 WaitBlock
->WaitType
= (USHORT
)WaitType
;
527 WaitBlock
->NextWaitBlock
= WaitBlock
+ 1;
529 /* Move to the next Wait Block */
530 WaitBlock
= WaitBlock
->NextWaitBlock
;
533 /* Return to the Root Wait Block */
535 WaitBlock
->NextWaitBlock
= WaitBlockArray
;
537 /* Check if this is a Wait All and all the objects are signaled */
538 if ((WaitType
== WaitAll
) && (AllObjectsSignaled
))
540 /* Return to the Root Wait Block */
541 WaitBlock
= CurrentThread
->WaitBlockList
;
543 /* Satisfy their Waits and return to the caller */
544 KiSatisifyMultipleObjectWaits(WaitBlock
);
545 Status
= STATUS_WAIT_0
;
549 /* Make sure we can satisfy the Alertable request */
550 if (KiCheckAlertability(Alertable
, CurrentThread
, WaitMode
, &Status
)) break;
552 /* Set the Wait Status */
553 CurrentThread
->WaitStatus
= Status
;
555 /* Enable the Timeout Timer if there was any specified */
558 /* Make sure the timeout interval isn't actually 0 */
559 if (!Timeout
->QuadPart
)
561 /* Return a timeout */
562 Status
= STATUS_TIMEOUT
;
566 /* Point to Timer Wait Block and Thread Timer */
567 TimerWaitBlock
= &CurrentThread
->WaitBlock
[TIMER_WAIT_BLOCK
];
568 ThreadTimer
= &CurrentThread
->Timer
;
570 /* Connect the Timer Wait Block */
571 WaitBlock
->NextWaitBlock
= TimerWaitBlock
;
573 /* Set up the Timer Wait Block */
574 TimerWaitBlock
->Object
= (PVOID
)ThreadTimer
;
575 TimerWaitBlock
->Thread
= CurrentThread
;
576 TimerWaitBlock
->WaitKey
= STATUS_TIMEOUT
;
577 TimerWaitBlock
->WaitType
= WaitAny
;
578 TimerWaitBlock
->NextWaitBlock
= WaitBlockArray
;
580 /* Link the timer to this Wait Block */
581 InitializeListHead(&ThreadTimer
->Header
.WaitListHead
);
583 /* Insert the Timer into the Timer Lists and enable it */
584 if (!KiInsertTimer(ThreadTimer
, *Timeout
))
586 /* Return a timeout if we couldn't insert the timer */
587 Status
= STATUS_TIMEOUT
;
592 /* Insert into Object's Wait List*/
593 WaitBlock
= CurrentThread
->WaitBlockList
;
596 /* Get the Current Object */
597 CurrentObject
= WaitBlock
->Object
;
599 /* Link the Object to this Wait Block */
600 InsertTailList(&CurrentObject
->Header
.WaitListHead
,
601 &WaitBlock
->WaitListEntry
);
603 /* Move to the next Wait Block */
604 WaitBlock
= WaitBlock
->NextWaitBlock
;
606 while (WaitBlock
!= WaitBlockArray
);
608 /* Handle Kernel Queues */
609 if (CurrentThread
->Queue
)
611 DPRINT("Waking Queue\n");
612 KiWakeQueue(CurrentThread
->Queue
);
615 /* Block the Thread */
616 DPRINT("Blocking the Thread: %d, %d, %d, %x\n",
617 Alertable
, WaitMode
, WaitReason
, KeGetCurrentThread());
618 KiBlockThread(&Status
,
623 /* Check if we were executing an APC */
624 DPRINT("Thread is back\n");
625 if (Status
!= STATUS_KERNEL_APC
)
631 /* Loop again and re-acquire the dispatcher lock */
632 DPRINT("Looping Again\n"); // FIXME: Fix-up the interval */
633 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
637 /* Release the Lock, we are done */
638 DPRINT("Returning, %x. Status: %d\n", KeGetCurrentThread(), Status
);
639 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
643 /* Adjust the Quantum */
644 KiAdjustQuantumThread(CurrentThread
);
646 /* Release & Return */
647 DPRINT("Returning, %x. Status: %d\n. We did not wait.",
648 KeGetCurrentThread(), Status
);
649 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
655 KiWaitTest(PVOID ObjectPointer
,
658 PLIST_ENTRY WaitEntry
;
659 PLIST_ENTRY WaitList
;
660 PKWAIT_BLOCK CurrentWaitBlock
;
661 PKWAIT_BLOCK NextWaitBlock
;
663 PKMUTANT FirstObject
= ObjectPointer
, Object
;
665 /* Loop the Wait Entries */
666 DPRINT("KiWaitTest for Object: %x\n", FirstObject
);
667 WaitList
= &FirstObject
->Header
.WaitListHead
;
668 WaitEntry
= WaitList
->Flink
;
669 while ((FirstObject
->Header
.SignalState
> 0) && (WaitEntry
!= WaitList
))
671 /* Get the current wait block */
672 CurrentWaitBlock
= CONTAINING_RECORD(WaitEntry
,
675 WaitThread
= CurrentWaitBlock
->Thread
;
677 /* Check the current Wait Mode */
678 if (CurrentWaitBlock
->WaitType
== WaitAny
)
680 /* Easy case, satisfy only this wait */
681 DPRINT("Satisfiying a Wait any\n");
682 WaitEntry
= WaitEntry
->Blink
;
683 KiSatisfyObjectWait(FirstObject
, WaitThread
);
687 /* Everything must be satisfied */
688 DPRINT("Checking for a Wait All\n");
689 NextWaitBlock
= CurrentWaitBlock
->NextWaitBlock
;
691 /* Loop first to make sure they are valid */
692 while (NextWaitBlock
!= CurrentWaitBlock
)
694 /* Check if the object is signaled */
695 Object
= NextWaitBlock
->Object
;
696 DPRINT("Checking: %p %d\n",
697 Object
, Object
->Header
.SignalState
);
698 if (NextWaitBlock
->WaitKey
!= STATUS_TIMEOUT
)
700 /* Check if this is a mutant */
701 if ((Object
->Header
.Type
== MutantObject
) &&
702 (Object
->Header
.SignalState
<= 0) &&
703 (WaitThread
== Object
->OwnerThread
))
705 /* It's a signaled mutant */
707 else if (Object
->Header
.SignalState
<= 0)
709 /* Skip the unwaiting */
714 /* Go to the next Wait block */
715 NextWaitBlock
= NextWaitBlock
->NextWaitBlock
;
718 /* All the objects are signaled, we can satisfy */
719 DPRINT("Satisfiying a Wait All\n");
720 WaitEntry
= WaitEntry
->Blink
;
721 KiSatisifyMultipleObjectWaits(CurrentWaitBlock
);
724 /* All waits satisfied, unwait the thread */
725 DPRINT("Unwaiting the Thread\n");
726 KiAbortWaitThread(WaitThread
, CurrentWaitBlock
->WaitKey
, Increment
);
730 WaitEntry
= WaitEntry
->Flink
;
736 /* Must be called with the dispatcher lock held */
739 KiAbortWaitThread(PKTHREAD Thread
,
743 PKWAIT_BLOCK WaitBlock
;
745 /* If we are blocked, we must be waiting on something also */
746 DPRINT("KiAbortWaitThread: %x, Status: %x, %x \n",
747 Thread
, WaitStatus
, Thread
->WaitBlockList
);
749 /* Remove the Wait Blocks from the list */
750 DPRINT("Removing waits\n");
751 WaitBlock
= Thread
->WaitBlockList
;
755 DPRINT("Removing Waitblock: %x, %x\n",
756 WaitBlock
, WaitBlock
->NextWaitBlock
);
757 RemoveEntryList(&WaitBlock
->WaitListEntry
);
759 /* Go to the next one */
760 WaitBlock
= WaitBlock
->NextWaitBlock
;
761 } while (WaitBlock
!= Thread
->WaitBlockList
);
763 /* Check if there's a Thread Timer */
764 if (Thread
->Timer
.Header
.Inserted
)
766 /* Cancel the Thread Timer with the no-lock fastpath */
767 DPRINT("Removing the Thread's Timer\n");
768 Thread
->Timer
.Header
.Inserted
= FALSE
;
769 RemoveEntryList(&Thread
->Timer
.TimerListEntry
);
772 /* Increment the Queue's active threads */
775 DPRINT("Incrementing Queue's active threads\n");
776 Thread
->Queue
->CurrentCount
++;
779 /* Reschedule the Thread */
780 DPRINT("Unblocking the Thread\n");
781 KiUnblockThread(Thread
, &WaitStatus
, 0);
786 KiAcquireFastMutex(IN PFAST_MUTEX FastMutex
)
788 /* Increase contention count */
789 FastMutex
->Contention
++;
791 /* Wait for the event */
792 KeWaitForSingleObject(&FastMutex
->Gate
,
801 KiExitDispatcher(KIRQL OldIrql
)
803 /* If it's the idle thread, dispatch */
804 if (!(KeIsExecutingDpc()) &&
805 (OldIrql
< DISPATCH_LEVEL
) &&
806 (KeGetCurrentThread()) &&
807 (KeGetCurrentThread() == KeGetCurrentPrcb()->IdleThread
))
809 KiDispatchThreadNoLock(Ready
);
812 /* Lower irql back */
813 KeLowerIrql(OldIrql
);