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
= NULL
;
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: Unhandled case...what should we do? */
130 DPRINT1("Could not create timer for KeDelayExecutionThread\n");
133 /* Handle Kernel Queues */
134 if (CurrentThread
->Queue
) {
136 DPRINT("Waking Queue\n");
137 KiWakeQueue(CurrentThread
->Queue
);
140 /* Block the Thread */
141 DPRINT("Blocking the Thread: %d, %d, %x\n", Alertable
, WaitMode
, KeGetCurrentThread());
142 PsBlockThread(&Status
,
147 /* Check if we were executing an APC or if we timed out */
148 if (Status
!= STATUS_KERNEL_APC
) {
150 /* This is a good thing */
151 if (Status
== STATUS_TIMEOUT
) Status
= STATUS_SUCCESS
;
157 DPRINT("Looping Again\n");
158 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
162 /* Release the Lock, we are done */
163 DPRINT("Returning from KeDelayExecutionThread(), %x. Status: %d\n", KeGetCurrentThread(), Status
);
164 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
171 * FUNCTION: Puts the current thread into a wait state until the
172 * given dispatcher object is set to signalled
174 * Object = Object to wait on
175 * WaitReason = Reason for the wait (debugging aid)
176 * WaitMode = Can be KernelMode or UserMode, if UserMode then
177 * user-mode APCs can be delivered and the thread's
178 * stack can be paged out
179 * Altertable = Specifies if the wait is a alertable
180 * Timeout = Optional timeout value
185 KeWaitForSingleObject(PVOID Object
,
186 KWAIT_REASON WaitReason
,
187 KPROCESSOR_MODE WaitMode
,
189 PLARGE_INTEGER Timeout
)
191 PDISPATCHER_HEADER CurrentObject
;
192 PKWAIT_BLOCK WaitBlock
;
193 PKWAIT_BLOCK TimerWaitBlock
;
195 PKTHREAD CurrentThread
= KeGetCurrentThread();
199 DPRINT("Entering KeWaitForSingleObject\n");
201 /* Check if the lock is already held */
202 if (CurrentThread
->WaitNext
) {
204 /* Lock is held, disable Wait Next */
205 DPRINT("Lock is held\n");
206 CurrentThread
->WaitNext
= FALSE
;
210 /* Lock not held, acquire it */
211 DPRINT("Lock is not held, acquiring\n");
212 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
215 /* Start the actual Loop */
218 /* Get the current Wait Status */
219 WaitStatus
= CurrentThread
->WaitStatus
;
221 /* Append wait block to the KTHREAD wait block list */
222 CurrentThread
->WaitBlockList
= WaitBlock
= &CurrentThread
->WaitBlock
[0];
224 /* Get the Current Object */
225 CurrentObject
= (PDISPATCHER_HEADER
)Object
;
228 * Temporary hack until my Object Manager re-write. Basically some objects, like
229 * the File Object, but also LPCs and others, are actually waitable on their event.
230 * The Object Manager sets this up in The ObjectTypeInformation->DefaultObject member,
231 * by using pretty much the same kind of hack as us. Normal objects point to themselves
232 * in that pointer. Then, NtWaitForXXX will populate the WaitList that gets sent to us by
233 * using ->DefaultObject, so the proper actual objects will be sent to us. Until then however,
234 * I will keep this hack here, since there's no need to make an interim hack until the rewrite
235 * -- Alex Ionescu 24/02/05
237 if (CurrentObject
->Type
== IO_TYPE_FILE
) {
239 DPRINT1("Hack used: %x\n", &((PFILE_OBJECT
)CurrentObject
)->Event
);
240 CurrentObject
= (PDISPATCHER_HEADER
)(&((PFILE_OBJECT
)CurrentObject
)->Event
);
243 /* Check if the Object is Signaled */
244 if (KiIsObjectSignaled(CurrentObject
, CurrentThread
)) {
246 /* Just unwait this guy and exit */
247 if (CurrentObject
->SignalState
!= MINLONG
) {
249 /* It has a normal signal state, so unwait it and return */
250 KiSatisfyObjectWait(CurrentObject
, CurrentThread
);
251 Status
= STATUS_WAIT_0
;
256 /* Is this a Mutant? */
257 if (CurrentObject
->Type
== MutantObject
) {
259 /* According to wasm.ru, we must raise this exception (tested and true) */
260 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
261 ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED
);
266 /* Set up the Wait Block */
267 WaitBlock
->Object
= CurrentObject
;
268 WaitBlock
->Thread
= CurrentThread
;
269 WaitBlock
->WaitKey
= (USHORT
)(STATUS_WAIT_0
);
270 WaitBlock
->WaitType
= WaitAny
;
271 WaitBlock
->NextWaitBlock
= NULL
;
273 /* Make sure we can satisfy the Alertable request */
274 KiCheckAlertability(Alertable
, CurrentThread
, WaitMode
, &Status
);
276 /* Set the Wait Status */
277 CurrentThread
->WaitStatus
= Status
;
279 /* Enable the Timeout Timer if there was any specified */
280 if (Timeout
!= NULL
) {
282 /* However if 0 timeout was specified, then we must fail since we need to peform a wait */
283 if (!Timeout
->QuadPart
) {
285 /* Return a timeout */
286 Status
= STATUS_TIMEOUT
;
290 /* Point to Timer Wait Block and Thread Timer */
291 TimerWaitBlock
= &CurrentThread
->WaitBlock
[TIMER_WAIT_BLOCK
];
292 ThreadTimer
= &CurrentThread
->Timer
;
294 /* Connect the Timer Wait Block */
295 WaitBlock
->NextWaitBlock
= TimerWaitBlock
;
297 /* Set up the Timer Wait Block */
298 TimerWaitBlock
->Object
= (PVOID
)ThreadTimer
;
299 TimerWaitBlock
->Thread
= CurrentThread
;
300 TimerWaitBlock
->WaitKey
= STATUS_TIMEOUT
;
301 TimerWaitBlock
->WaitType
= WaitAny
;
302 TimerWaitBlock
->NextWaitBlock
= NULL
;
304 /* Link the timer to this Wait Block */
305 InitializeListHead(&ThreadTimer
->Header
.WaitListHead
);
306 InsertTailList(&ThreadTimer
->Header
.WaitListHead
, &TimerWaitBlock
->WaitListEntry
);
308 /* Insert the Timer into the Timer Lists and enable it */
309 if (!KiInsertTimer(ThreadTimer
, *Timeout
)) {
311 /* Return a timeout if we couldn't insert the timer for some reason */
312 Status
= STATUS_TIMEOUT
;
317 /* Link the Object to this Wait Block */
318 InsertTailList(&CurrentObject
->WaitListHead
, &WaitBlock
->WaitListEntry
);
320 /* Handle Kernel Queues */
321 if (CurrentThread
->Queue
) {
323 DPRINT("Waking Queue\n");
324 KiWakeQueue(CurrentThread
->Queue
);
327 /* Block the Thread */
328 DPRINT("Blocking the Thread: %d, %d, %d, %x\n", Alertable
, WaitMode
, WaitReason
, KeGetCurrentThread());
329 PsBlockThread(&Status
,
334 /* Check if we were executing an APC */
335 if (Status
!= STATUS_KERNEL_APC
) {
341 DPRINT("Looping Again\n");
342 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
347 /* Release the Lock, we are done */
348 DPRINT("Returning from KeWaitForMultipleObjects(), %x. Status: %d\n", KeGetCurrentThread(), Status
);
349 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
357 KeWaitForMultipleObjects(ULONG Count
,
360 KWAIT_REASON WaitReason
,
361 KPROCESSOR_MODE WaitMode
,
363 PLARGE_INTEGER Timeout
,
364 PKWAIT_BLOCK WaitBlockArray
)
366 PDISPATCHER_HEADER CurrentObject
;
367 PKWAIT_BLOCK WaitBlock
;
368 PKWAIT_BLOCK TimerWaitBlock
;
370 PKTHREAD CurrentThread
= KeGetCurrentThread();
371 ULONG AllObjectsSignaled
;
376 DPRINT("Entering KeWaitForMultipleObjects(Count %lu Object[] %p) "
377 "PsGetCurrentThread() %x, Timeout %x\n", Count
, Object
, PsGetCurrentThread(), Timeout
);
379 /* Set the Current Thread */
380 CurrentThread
= KeGetCurrentThread();
382 /* Check if the lock is already held */
383 if (CurrentThread
->WaitNext
) {
385 /* Lock is held, disable Wait Next */
386 DPRINT("Lock is held\n");
387 CurrentThread
->WaitNext
= FALSE
;
391 /* Lock not held, acquire it */
392 DPRINT("Lock is not held, acquiring\n");
393 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
396 /* Make sure the Wait Count is valid for the Thread and Maximum Wait Objects */
397 if (!WaitBlockArray
) {
399 /* Check in regards to the Thread Object Limit */
400 if (Count
> THREAD_WAIT_OBJECTS
) {
402 DPRINT1("(%s:%d) Too many objects!\n", __FILE__
, __LINE__
);
403 KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED
);
406 /* Use the Thread's Wait Block */
407 WaitBlockArray
= &CurrentThread
->WaitBlock
[0];
411 /* Using our own Block Array. Check in regards to System Object Limit */
412 if (Count
> MAXIMUM_WAIT_OBJECTS
) {
414 DPRINT1("(%s:%d) Too many objects!\n", __FILE__
, __LINE__
);
415 KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED
);
419 /* Start the actual Loop */
422 /* Get the current Wait Status */
423 WaitStatus
= CurrentThread
->WaitStatus
;
425 /* Append wait block to the KTHREAD wait block list */
426 CurrentThread
->WaitBlockList
= WaitBlock
= WaitBlockArray
;
428 /* Check if the wait is (already) satisfied */
429 AllObjectsSignaled
= TRUE
;
431 /* First, we'll try to satisfy the wait directly */
432 for (WaitIndex
= 0; WaitIndex
< Count
; WaitIndex
++) {
434 /* Get the Current Object */
435 CurrentObject
= (PDISPATCHER_HEADER
)Object
[WaitIndex
];
438 * Temporary hack until my Object Manager re-write. Basically some objects, like
439 * the File Object, but also LPCs and others, are actually waitable on their event.
440 * The Object Manager sets this up in The ObjectTypeInformation->DefaultObject member,
441 * by using pretty much the same kind of hack as us. Normal objects point to themselves
442 * in that pointer. Then, NtWaitForXXX will populate the WaitList that gets sent to us by
443 * using ->DefaultObject, so the proper actual objects will be sent to us. Until then however,
444 * I will keep this hack here, since there's no need to make an interim hack until the rewrite
445 * -- Alex Ionescu 24/02/05
447 if (CurrentObject
->Type
== IO_TYPE_FILE
) {
449 DPRINT1("Hack used: %x\n", &((PFILE_OBJECT
)CurrentObject
)->Event
);
450 CurrentObject
= (PDISPATCHER_HEADER
)(&((PFILE_OBJECT
)CurrentObject
)->Event
);
453 /* Check if the Object is Signaled */
454 if (KiIsObjectSignaled(CurrentObject
, CurrentThread
)) {
456 /* Check what kind of wait this is */
457 if (WaitType
== WaitAny
) {
459 /* This is a Wait Any, so just unwait this guy and exit */
460 if (CurrentObject
->SignalState
!= MINLONG
) {
462 /* It has a normal signal state, so unwait it and return */
463 KiSatisfyObjectWait(CurrentObject
, CurrentThread
);
464 Status
= STATUS_WAIT_0
| WaitIndex
;
469 /* Is this a Mutant? */
470 if (CurrentObject
->Type
== MutantObject
) {
472 /* According to wasm.ru, we must raise this exception (tested and true) */
473 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
474 ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED
);
481 /* One of the objects isn't signaled... if this is a WaitAll, we will fail later */
482 AllObjectsSignaled
= FALSE
;
485 /* Set up a Wait Block for this Object */
486 WaitBlock
->Object
= CurrentObject
;
487 WaitBlock
->Thread
= CurrentThread
;
488 WaitBlock
->WaitKey
= (USHORT
)(STATUS_WAIT_0
+ WaitIndex
);
489 WaitBlock
->WaitType
= (USHORT
)WaitType
;
490 WaitBlock
->NextWaitBlock
= WaitBlock
+ 1;
492 /* Move to the next Wait Block */
493 WaitBlock
= WaitBlock
->NextWaitBlock
;
496 /* Return to the Root Wait Block */
498 WaitBlock
->NextWaitBlock
= NULL
;
500 /* Check if this is a Wait All and all the objects are signaled */
501 if ((WaitType
== WaitAll
) && (AllObjectsSignaled
)) {
503 /* Return to the Root Wait Block */
504 WaitBlock
= CurrentThread
->WaitBlockList
;
506 /* Satisfy their Waits and return to the caller */
507 KiSatisifyMultipleObjectWaits(WaitBlock
);
508 Status
= STATUS_WAIT_0
;
512 /* Make sure we can satisfy the Alertable request */
513 KiCheckAlertability(Alertable
, CurrentThread
, WaitMode
, &Status
);
515 /* Set the Wait Status */
516 CurrentThread
->WaitStatus
= Status
;
518 /* Enable the Timeout Timer if there was any specified */
519 if (Timeout
!= NULL
) {
521 /* However if 0 timeout was specified, then we must fail since we need to peform a wait */
522 if (!Timeout
->QuadPart
) {
524 /* Return a timeout */
525 Status
= STATUS_TIMEOUT
;
529 /* Point to Timer Wait Block and Thread Timer */
530 TimerWaitBlock
= &CurrentThread
->WaitBlock
[TIMER_WAIT_BLOCK
];
531 ThreadTimer
= &CurrentThread
->Timer
;
533 /* Connect the Timer Wait Block */
534 WaitBlock
->NextWaitBlock
= TimerWaitBlock
;
536 /* Set up the Timer Wait Block */
537 TimerWaitBlock
->Object
= (PVOID
)ThreadTimer
;
538 TimerWaitBlock
->Thread
= CurrentThread
;
539 TimerWaitBlock
->WaitKey
= STATUS_TIMEOUT
;
540 TimerWaitBlock
->WaitType
= WaitAny
;
541 TimerWaitBlock
->NextWaitBlock
= NULL
;
543 /* Link the timer to this Wait Block */
544 InitializeListHead(&ThreadTimer
->Header
.WaitListHead
);
546 /* Insert the Timer into the Timer Lists and enable it */
547 if (!KiInsertTimer(ThreadTimer
, *Timeout
)) {
549 /* Return a timeout if we couldn't insert the timer for some reason */
550 Status
= STATUS_TIMEOUT
;
555 /* Insert into Object's Wait List*/
556 WaitBlock
= CurrentThread
->WaitBlockList
;
559 /* Get the Current Object */
560 CurrentObject
= WaitBlock
->Object
;
562 /* Link the Object to this Wait Block */
563 InsertTailList(&CurrentObject
->WaitListHead
, &WaitBlock
->WaitListEntry
);
565 /* Move to the next Wait Block */
566 WaitBlock
= WaitBlock
->NextWaitBlock
;
569 /* Handle Kernel Queues */
570 if (CurrentThread
->Queue
) {
572 DPRINT("Waking Queue\n");
573 KiWakeQueue(CurrentThread
->Queue
);
576 /* Block the Thread */
577 DPRINT("Blocking the Thread: %d, %d, %d, %x\n", Alertable
, WaitMode
, WaitReason
, KeGetCurrentThread());
578 PsBlockThread(&Status
,
583 /* Check if we were executing an APC */
584 if (Status
!= STATUS_KERNEL_APC
) {
590 DPRINT("Looping Again\n");
591 CurrentThread
->WaitIrql
= KeAcquireDispatcherDatabaseLock();
596 /* Release the Lock, we are done */
597 DPRINT("Returning from KeWaitForMultipleObjects(), %x. Status: %d\n", KeGetCurrentThread(), Status
);
598 KeReleaseDispatcherDatabaseLock(CurrentThread
->WaitIrql
);
604 KiSatisfyObjectWait(PDISPATCHER_HEADER Object
,
608 /* Special case for Mutants */
609 if (Object
->Type
== MutantObject
) {
611 /* Decrease the Signal State */
612 Object
->SignalState
--;
614 /* Check if it's now non-signaled */
615 if (Object
->SignalState
== 0) {
617 /* Set the Owner Thread */
618 ((PKMUTANT
)Object
)->OwnerThread
= Thread
;
620 /* Disable APCs if needed */
621 Thread
->KernelApcDisable
-= ((PKMUTANT
)Object
)->ApcDisable
;
623 /* Check if it's abandoned */
624 if (((PKMUTANT
)Object
)->Abandoned
) {
627 ((PKMUTANT
)Object
)->Abandoned
= FALSE
;
630 Thread
->WaitStatus
= STATUS_ABANDONED
;
633 /* Insert it into the Mutant List */
634 InsertHeadList(&Thread
->MutantListHead
, &((PKMUTANT
)Object
)->MutantListEntry
);
637 } else if ((Object
->Type
& TIMER_OR_EVENT_TYPE
) == EventSynchronizationObject
) {
639 /* These guys (Syncronization Timers and Events) just get un-signaled */
640 Object
->SignalState
= 0;
642 } else if (Object
->Type
== SemaphoreObject
) {
644 /* These ones can have multiple signalings, so we only decrease it */
645 Object
->SignalState
--;
651 KiWaitTest(PDISPATCHER_HEADER Object
,
654 PLIST_ENTRY WaitEntry
;
655 PLIST_ENTRY WaitList
;
656 PKWAIT_BLOCK CurrentWaitBlock
;
657 PKWAIT_BLOCK NextWaitBlock
;
659 /* Loop the Wait Entries */
660 DPRINT("KiWaitTest for Object: %x\n", Object
);
661 WaitList
= &Object
->WaitListHead
;
662 WaitEntry
= WaitList
->Flink
;
663 while ((WaitEntry
!= WaitList
) && (Object
->SignalState
> 0)) {
665 /* Get the current wait block */
666 CurrentWaitBlock
= CONTAINING_RECORD(WaitEntry
, KWAIT_BLOCK
, WaitListEntry
);
668 /* Check the current Wait Mode */
669 if (CurrentWaitBlock
->WaitType
== WaitAny
) {
671 /* Easy case, satisfy only this wait */
672 DPRINT("Satisfiying a Wait any\n");
673 WaitEntry
= WaitEntry
->Blink
;
674 KiSatisfyObjectWait(Object
, CurrentWaitBlock
->Thread
);
678 /* Everything must be satisfied */
679 DPRINT("Checking for a Wait All\n");
680 NextWaitBlock
= CurrentWaitBlock
->NextWaitBlock
;
682 /* Loop first to make sure they are valid */
683 while (NextWaitBlock
) {
685 /* Check if the object is signaled */
686 if (!KiIsObjectSignaled(Object
, CurrentWaitBlock
->Thread
)) {
688 /* It's not, move to the next one */
689 DPRINT1("One of the object is non-signaled, sorry.\n");
693 /* Go to the next Wait block */
694 NextWaitBlock
= NextWaitBlock
->NextWaitBlock
;
697 /* All the objects are signaled, we can satisfy */
698 DPRINT("Satisfiying a Wait All\n");
699 WaitEntry
= WaitEntry
->Blink
;
700 KiSatisifyMultipleObjectWaits(CurrentWaitBlock
);
703 /* All waits satisfied, unwait the thread */
704 DPRINT("Unwaiting the Thread\n");
705 KiAbortWaitThread(CurrentWaitBlock
->Thread
, CurrentWaitBlock
->WaitKey
, Increment
);
709 WaitEntry
= WaitEntry
->Flink
;
715 /* Must be called with the dispatcher lock held */
718 KiAbortWaitThread(PKTHREAD Thread
,
722 PKWAIT_BLOCK WaitBlock
;
724 /* If we are blocked, we must be waiting on something also */
725 DPRINT("KiAbortWaitThread: %x, Status: %x, %x \n", Thread
, WaitStatus
, Thread
->WaitBlockList
);
726 ASSERT((Thread
->State
== THREAD_STATE_BLOCKED
) == (Thread
->WaitBlockList
!= NULL
));
728 /* Remove the Wait Blocks from the list */
729 DPRINT("Removing waits\n");
730 WaitBlock
= Thread
->WaitBlockList
;
734 DPRINT("Removing Waitblock: %x, %x\n", WaitBlock
, WaitBlock
->NextWaitBlock
);
735 RemoveEntryList(&WaitBlock
->WaitListEntry
);
737 /* Go to the next one */
738 WaitBlock
= WaitBlock
->NextWaitBlock
;
741 /* Check if there's a Thread Timer */
742 if (Thread
->Timer
.Header
.Inserted
) {
744 /* Cancel the Thread Timer with the no-lock fastpath */
745 DPRINT("Removing the Thread's Timer\n");
746 Thread
->Timer
.Header
.Inserted
= FALSE
;
747 RemoveEntryList(&Thread
->Timer
.TimerListEntry
);
750 /* Increment the Queue's active threads */
753 DPRINT("Incrementing Queue's active threads\n");
754 Thread
->Queue
->CurrentCount
++;
757 /* Reschedule the Thread */
758 DPRINT("Unblocking the Thread\n");
759 PsUnblockThread((PETHREAD
)Thread
, &WaitStatus
, 0);
765 KiIsObjectSignaled(PDISPATCHER_HEADER Object
,
768 /* Mutants are...well...mutants! */
769 if (Object
->Type
== MutantObject
) {
772 * Because Cutler hates mutants, they are actually signaled if the Signal State is <= 0
773 * Well, only if they are recursivly acquired (i.e if we own it right now).
774 * Of course, they are also signaled if their signal state is 1.
776 if ((Object
->SignalState
<= 0 && ((PKMUTANT
)Object
)->OwnerThread
== Thread
) ||
777 (Object
->SignalState
== 1)) {
779 /* Signaled Mutant */
784 /* Unsignaled Mutant */
789 /* Any other object is not a mutated freak, so let's use logic */
790 return (!Object
->SignalState
<= 0);
796 KiIsObjectWaitable(PVOID Object
)
798 POBJECT_HEADER Header
;
799 Header
= BODY_TO_HEADER(Object
);
801 if (Header
->ObjectType
== ExEventObjectType
||
802 Header
->ObjectType
== ExIoCompletionType
||
803 Header
->ObjectType
== ExMutantObjectType
||
804 Header
->ObjectType
== ExSemaphoreObjectType
||
805 Header
->ObjectType
== ExTimerType
||
806 Header
->ObjectType
== PsProcessType
||
807 Header
->ObjectType
== PsThreadType
||
808 Header
->ObjectType
== IoFileObjectType
) {
821 KiSatisifyMultipleObjectWaits(PKWAIT_BLOCK WaitBlock
)
823 PKTHREAD WaitThread
= WaitBlock
->Thread
;
825 /* Loop through all the Wait Blocks, and wake each Object */
828 /* Wake the Object */
829 KiSatisfyObjectWait(WaitBlock
->Object
, WaitThread
);
830 WaitBlock
= WaitBlock
->NextWaitBlock
;
837 KeInitializeDispatcherHeader(DISPATCHER_HEADER
* Header
,
842 Header
->Type
= (UCHAR
)Type
;
843 Header
->Absolute
= 0;
844 Header
->Inserted
= 0;
845 Header
->Size
= (UCHAR
)Size
;
846 Header
->SignalState
= SignalState
;
847 InitializeListHead(&(Header
->WaitListHead
));
853 KeAcquireDispatcherDatabaseLock(VOID
)
857 KeAcquireSpinLock (&DispatcherDatabaseLock
, &OldIrql
);
864 KeAcquireDispatcherDatabaseLockAtDpcLevel(VOID
)
866 KeAcquireSpinLockAtDpcLevel (&DispatcherDatabaseLock
);
872 KeInitializeDispatcher(VOID
)
874 /* Initialize the Dispatcher Lock */
875 KeInitializeSpinLock(&DispatcherDatabaseLock
);
881 KeReleaseDispatcherDatabaseLock(KIRQL OldIrql
)
883 /* If it's the idle thread, dispatch */
884 if (!KeIsExecutingDpc() && OldIrql
< DISPATCH_LEVEL
&& KeGetCurrentThread() != NULL
&&
885 KeGetCurrentThread() == KeGetCurrentPrcb()->IdleThread
) {
887 PsDispatchThreadNoLock(THREAD_STATE_READY
);
888 KeLowerIrql(OldIrql
);
892 /* Just release the spin lock */
893 KeReleaseSpinLock(&DispatcherDatabaseLock
, OldIrql
);
900 KeReleaseDispatcherDatabaseLockFromDpcLevel(VOID
)
902 KeReleaseSpinLockFromDpcLevel(&DispatcherDatabaseLock
);