3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS project
5 * FILE: ntoskrnl/ke/wait.c
6 * PURPOSE: Manages non-busy waiting
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
12 /* NOTES ********************************************************************
16 /* INCLUDES ******************************************************************/
21 #include <internal/debug.h>
23 /* GLOBALS ******************************************************************/
25 static KSPIN_LOCK DispatcherDatabaseLock
;
27 #define KeDispatcherObjectWakeOne(hdr, increment) KeDispatcherObjectWakeOneOrAll(hdr, increment, FALSE)
28 #define KeDispatcherObjectWakeAll(hdr, increment) KeDispatcherObjectWakeOneOrAll(hdr, increment, TRUE)
30 extern POBJECT_TYPE EXPORTED ExMutantObjectType
;
31 extern POBJECT_TYPE EXPORTED ExSemaphoreObjectType
;
32 extern POBJECT_TYPE EXPORTED ExTimerType
;
34 /* FUNCTIONS *****************************************************************/
36 VOID
KeInitializeDispatcherHeader(DISPATCHER_HEADER
* Header
,
41 Header
->Type
= (UCHAR
)Type
;
44 Header
->Size
= (UCHAR
)Size
;
45 Header
->SignalState
= SignalState
;
46 InitializeListHead(&(Header
->WaitListHead
));
51 KeAcquireDispatcherDatabaseLock(VOID
)
53 * PURPOSE: Acquires the dispatcher database lock for the caller
58 DPRINT("KeAcquireDispatcherDatabaseLock()\n");
60 KeAcquireSpinLock (&DispatcherDatabaseLock
, &OldIrql
);
66 KeAcquireDispatcherDatabaseLockAtDpcLevel(VOID
)
68 * PURPOSE: Acquires the dispatcher database lock for the caller
71 DPRINT("KeAcquireDispatcherDatabaseLockAtDpcLevel()\n");
73 KeAcquireSpinLockAtDpcLevel (&DispatcherDatabaseLock
);
78 KeReleaseDispatcherDatabaseLock(KIRQL OldIrql
)
80 DPRINT("KeReleaseDispatcherDatabaseLock(OldIrql %x)\n",OldIrql
);
81 if (!KeIsExecutingDpc() &&
82 OldIrql
< DISPATCH_LEVEL
&&
83 KeGetCurrentThread() != NULL
&&
84 KeGetCurrentThread() == KeGetCurrentKPCR()->PrcbData
.IdleThread
)
86 PsDispatchThreadNoLock(THREAD_STATE_READY
);
91 KeReleaseSpinLock(&DispatcherDatabaseLock
, OldIrql
);
97 KeReleaseDispatcherDatabaseLockFromDpcLevel(VOID
)
99 DPRINT("KeReleaseDispatcherDatabaseLock()\n");
101 KeReleaseSpinLockFromDpcLevel(&DispatcherDatabaseLock
);
106 KiSideEffectsBeforeWake(DISPATCHER_HEADER
* hdr
,
109 * FUNCTION: Perform side effects on object before a wait for a thread is
113 BOOLEAN Abandoned
= FALSE
;
117 case InternalSynchronizationEvent
:
118 hdr
->SignalState
= 0;
121 case InternalQueueType
:
124 case InternalSemaphoreType
:
128 case InternalProcessType
:
131 case InternalThreadType
:
134 case InternalNotificationEvent
:
137 case InternalSynchronizationTimer
:
138 hdr
->SignalState
= FALSE
;
141 case InternalNotificationTimer
:
144 case InternalMutexType
:
148 Mutex
= CONTAINING_RECORD(hdr
, KMUTEX
, Header
);
150 ASSERT(hdr
->SignalState
<= 1);
151 if (hdr
->SignalState
== 0)
155 DPRINT("Thread == NULL!\n");
158 Abandoned
= Mutex
->Abandoned
;
160 InsertTailList(&Thread
->MutantListHead
, &Mutex
->MutantListEntry
);
161 Mutex
->OwnerThread
= Thread
;
162 Mutex
->Abandoned
= FALSE
;
168 DbgPrint("(%s:%d) Dispatcher object %x has unknown type\n", __FILE__
, __LINE__
, hdr
);
176 KiIsObjectSignalled(DISPATCHER_HEADER
* hdr
,
179 if (hdr
->Type
== InternalMutexType
)
183 Mutex
= CONTAINING_RECORD(hdr
, KMUTEX
, Header
);
185 ASSERT(hdr
->SignalState
<= 1);
187 if ((hdr
->SignalState
< 1 && Mutex
->OwnerThread
== Thread
) || hdr
->SignalState
== 1)
197 if (hdr
->SignalState
<= 0)
207 /* Must be called with the dispatcher lock held */
208 BOOLEAN
KiAbortWaitThread(PKTHREAD Thread
, NTSTATUS WaitStatus
)
210 PKWAIT_BLOCK WaitBlock
;
213 /* if we are blocked, we must be waiting on something also */
214 ASSERT((Thread
->State
== THREAD_STATE_BLOCKED
) == (Thread
->WaitBlockList
!= NULL
));
216 WaitBlock
= (PKWAIT_BLOCK
)Thread
->WaitBlockList
;
217 WasWaiting
= (WaitBlock
!= NULL
);
221 RemoveEntryList(&WaitBlock
->WaitListEntry
);
222 WaitBlock
= WaitBlock
->NextWaitBlock
;
225 Thread
->WaitBlockList
= NULL
;
229 PsUnblockThread((PETHREAD
)Thread
, &WaitStatus
, 0);
235 KeDispatcherObjectWakeOneOrAll(DISPATCHER_HEADER
* hdr
,
240 PKWAIT_BLOCK WaiterHead
;
241 PLIST_ENTRY EnumEntry
;
245 BOOLEAN WakedAny
= FALSE
;
247 DPRINT("KeDispatcherObjectWakeOnOrAll(hdr %x)\n", hdr
);
248 DPRINT ("hdr->WaitListHead.Flink %x hdr->WaitListHead.Blink %x\n",
249 hdr
->WaitListHead
.Flink
, hdr
->WaitListHead
.Blink
);
251 if (IsListEmpty(&hdr
->WaitListHead
))
256 //enum waiters for this dispatcher object
257 EnumEntry
= hdr
->WaitListHead
.Flink
;
258 while (EnumEntry
!= &hdr
->WaitListHead
&& (WakeAll
|| !WakedAny
))
260 WaiterHead
= CONTAINING_RECORD(EnumEntry
, KWAIT_BLOCK
, WaitListEntry
);
261 DPRINT("current_entry %x current %x\n", EnumEntry
, WaiterHead
);
262 EnumEntry
= EnumEntry
->Flink
;
263 ASSERT(WaiterHead
->Thread
!= NULL
);
264 ASSERT(WaiterHead
->Thread
->WaitBlockList
!= NULL
);
268 if (WaiterHead
->WaitType
== WaitAny
)
270 DPRINT("WaitAny: Remove all wait blocks.\n");
271 for (Waiter
= WaiterHead
->Thread
->WaitBlockList
; Waiter
; Waiter
= Waiter
->NextWaitBlock
)
273 RemoveEntryList(&Waiter
->WaitListEntry
);
276 WaiterHead
->Thread
->WaitBlockList
= NULL
;
279 * If a WakeAll KiSideEffectsBeforeWake(hdr,.. will be called several times,
280 * but thats ok since WakeAll objects has no sideeffects.
282 Abandoned
|= KiSideEffectsBeforeWake(hdr
, WaiterHead
->Thread
);
286 DPRINT("WaitAll: All WaitAll objects must be signaled.\n");
290 //all WaitAll obj. for thread need to be signaled to satisfy a wake
291 for (Waiter
= WaiterHead
->Thread
->WaitBlockList
; Waiter
; Waiter
= Waiter
->NextWaitBlock
)
293 //no need to check hdr since it has to be signaled
294 if (Waiter
->WaitType
== WaitAll
&& Waiter
->Object
!= hdr
)
296 if (!KiIsObjectSignalled(Waiter
->Object
, Waiter
->Thread
))
306 for (Waiter
= WaiterHead
->Thread
->WaitBlockList
; Waiter
; Waiter
= Waiter
->NextWaitBlock
)
308 RemoveEntryList(&Waiter
->WaitListEntry
);
310 if (Waiter
->WaitType
== WaitAll
)
312 Abandoned
|= KiSideEffectsBeforeWake(Waiter
->Object
, Waiter
->Thread
);
315 //no WaitAny objects can possibly be signaled since we are here
316 ASSERT(!(Waiter
->WaitType
== WaitAny
317 && KiIsObjectSignalled(Waiter
->Object
, Waiter
->Thread
)));
320 WaiterHead
->Thread
->WaitBlockList
= NULL
;
324 if (WaiterHead
->Thread
->WaitBlockList
== NULL
)
326 Status
= WaiterHead
->WaitKey
;
329 DPRINT("Abandoned mutex among objects");
330 Status
+= STATUS_ABANDONED_WAIT_0
;
334 DPRINT("Waking %x status = %x\n", WaiterHead
->Thread
, Status
);
335 PsUnblockThread(CONTAINING_RECORD(WaiterHead
->Thread
, ETHREAD
, Tcb
),
344 BOOLEAN
KiDispatcherObjectWake(DISPATCHER_HEADER
* hdr
, KPRIORITY increment
)
346 * FUNCTION: Wake threads waiting on a dispatcher object
347 * NOTE: The exact semantics of waking are dependant on the type of object
352 DPRINT("Entering KeDispatcherObjectWake(hdr %x)\n",hdr
);
353 // DPRINT("hdr->WaitListHead %x hdr->WaitListHead.Flink %x\n",
354 // &hdr->WaitListHead,hdr->WaitListHead.Flink);
355 DPRINT("hdr->Type %x\n",hdr
->Type
);
358 case InternalNotificationEvent
:
359 return(KeDispatcherObjectWakeAll(hdr
, increment
));
361 case InternalNotificationTimer
:
362 return(KeDispatcherObjectWakeAll(hdr
, increment
));
364 case InternalSynchronizationEvent
:
365 return(KeDispatcherObjectWakeOne(hdr
, increment
));
367 case InternalSynchronizationTimer
:
368 return(KeDispatcherObjectWakeOne(hdr
, increment
));
370 case InternalQueueType
:
371 return(KeDispatcherObjectWakeOne(hdr
, increment
));
373 case InternalSemaphoreType
:
374 DPRINT("hdr->SignalState %d\n", hdr
->SignalState
);
375 if(hdr
->SignalState
>0)
379 DPRINT("Waking one semaphore waiter\n");
380 Ret
= KeDispatcherObjectWakeOne(hdr
, increment
);
381 } while(hdr
->SignalState
> 0 && Ret
) ;
386 case InternalProcessType
:
387 return(KeDispatcherObjectWakeAll(hdr
, increment
));
389 case InternalThreadType
:
390 return(KeDispatcherObjectWakeAll(hdr
, increment
));
392 case InternalMutexType
:
393 return(KeDispatcherObjectWakeOne(hdr
, increment
));
395 DbgPrint("Dispatcher object %x has unknown type %d\n", hdr
, hdr
->Type
);
404 KeDelayExecutionThread (KPROCESSOR_MODE WaitMode
,
406 PLARGE_INTEGER Interval
)
408 * FUNCTION: Puts the current thread into an alertable or nonalertable
409 * wait state for a given internal
411 * WaitMode = Processor mode in which the caller is waiting
412 * Altertable = Specifies if the wait is alertable
413 * Interval = Specifies the interval to wait
417 PKTHREAD Thread
= KeGetCurrentThread();
419 KeSetTimer(&Thread
->Timer
, *Interval
, NULL
);
420 return (KeWaitForSingleObject(&Thread
->Timer
,
421 (WaitMode
== KernelMode
) ? Executive
: UserRequest
, /* TMN: Was unconditionally Executive */
422 WaitMode
, /* TMN: Was UserMode */
431 KeWaitForSingleObject(PVOID Object
,
432 KWAIT_REASON WaitReason
,
433 KPROCESSOR_MODE WaitMode
,
435 PLARGE_INTEGER Timeout
)
437 * FUNCTION: Puts the current thread into a wait state until the
438 * given dispatcher object is set to signalled
440 * Object = Object to wait on
441 * WaitReason = Reason for the wait (debugging aid)
442 * WaitMode = Can be KernelMode or UserMode, if UserMode then
443 * user-mode APCs can be delivered and the thread's
444 * stack can be paged out
445 * Altertable = Specifies if the wait is a alertable
446 * Timeout = Optional timeout value
450 return KeWaitForMultipleObjects(1,
463 KiGetWaitableObjectFromObject(PVOID Object
)
465 //special case when waiting on file objects
466 if ( ((PDISPATCHER_HEADER
)Object
)->Type
== InternalFileType
)
468 return &((PFILE_OBJECT
)Object
)->Event
;
476 KiIsObjectWaitable(PVOID Object
)
478 POBJECT_HEADER Header
;
479 Header
= BODY_TO_HEADER(Object
);
480 if (Header
->ObjectType
== ExEventObjectType
||
481 Header
->ObjectType
== ExIoCompletionType
||
482 Header
->ObjectType
== ExMutantObjectType
||
483 Header
->ObjectType
== ExSemaphoreObjectType
||
484 Header
->ObjectType
== ExTimerType
||
485 Header
->ObjectType
== PsProcessType
||
486 Header
->ObjectType
== PsThreadType
||
487 Header
->ObjectType
== IoFileObjectType
)
501 KeWaitForMultipleObjects(ULONG Count
,
504 KWAIT_REASON WaitReason
,
505 KPROCESSOR_MODE WaitMode
,
507 PLARGE_INTEGER Timeout
,
508 PKWAIT_BLOCK WaitBlockArray
)
510 DISPATCHER_HEADER
*hdr
;
512 PKTHREAD CurrentThread
;
520 DPRINT("Entering KeWaitForMultipleObjects(Count %lu Object[] %p) "
521 "PsGetCurrentThread() %x\n", Count
, Object
, PsGetCurrentThread());
523 ASSERT(0 < Count
&& Count
<= MAXIMUM_WAIT_OBJECTS
);
525 CurrentThread
= KeGetCurrentThread();
528 * Work out where we are going to put the wait blocks
530 if (WaitBlockArray
== NULL
)
532 if (Count
> THREAD_WAIT_OBJECTS
)
534 DPRINT("(%s:%d) Too many objects!\n", __FILE__
, __LINE__
);
535 return (STATUS_UNSUCCESSFUL
);
537 WaitBlockArray
= &CurrentThread
->WaitBlock
[0];
541 if (Count
> MAXIMUM_WAIT_OBJECTS
)
543 DPRINT("(%s:%d) Too many objects!\n", __FILE__
, __LINE__
);
544 return (STATUS_UNSUCCESSFUL
);
551 * Set up the timeout if required
553 if (Timeout
!= NULL
&& Timeout
->QuadPart
!= 0)
555 KeSetTimer(&CurrentThread
->Timer
, *Timeout
, NULL
);
560 if (CurrentThread
->WaitNext
)
562 CurrentThread
->WaitNext
= FALSE
;
563 OldIrql
= CurrentThread
->WaitIrql
;
567 OldIrql
= KeAcquireDispatcherDatabaseLock ();
570 /* Get the current Wait Status */
571 WaitStatus
= CurrentThread
->WaitStatus
;
575 /* If the Thread is Alerted, set the Wait Status accordingly */
576 if (CurrentThread
->Alerted
[(int)WaitMode
]) {
578 CurrentThread
->Alerted
[(int)WaitMode
] = FALSE
;
579 DPRINT("Thread was Alerted\n");
580 WaitStatus
= STATUS_ALERTED
;
582 /* If there are User APCs Pending, then we can't really be alertable */
583 } else if ((!IsListEmpty(&CurrentThread
->ApcState
.ApcListHead
[UserMode
])) &&
584 (WaitMode
== UserMode
)) {
586 DPRINT1("APCs are Pending\n");
587 CurrentThread
->ApcState
.UserApcPending
= TRUE
;
588 WaitStatus
= STATUS_USER_APC
;
591 /* If there are User APCs Pending and we are waiting in usermode, then we must notify the caller */
592 } else if ((CurrentThread
->ApcState
.UserApcPending
) && (WaitMode
== UserMode
)) {
593 DPRINT1("APCs are Pending\n");
594 WaitStatus
= STATUS_USER_APC
;
598 * Check if the wait is (already) satisfied
602 for (i
= 0; i
< Count
; i
++)
604 hdr
= (DISPATCHER_HEADER
*) KiGetWaitableObjectFromObject(Object
[i
]);
606 if (KiIsObjectSignalled(hdr
, CurrentThread
))
610 if (WaitType
== WaitAny
)
612 Abandoned
= KiSideEffectsBeforeWake(hdr
, CurrentThread
) ? TRUE
: Abandoned
;
614 KeReleaseDispatcherDatabaseLock(OldIrql
);
616 if (Timeout
!= NULL
&& Timeout
->QuadPart
!= 0)
618 KeCancelTimer(&CurrentThread
->Timer
);
621 DPRINT("One object is (already) signaled!\n");
622 if (Abandoned
== TRUE
)
624 return (STATUS_ABANDONED_WAIT_0
+ i
);
627 return (STATUS_WAIT_0
+ i
);
633 if ((WaitType
== WaitAll
) && (CountSignaled
== Count
))
635 for (i
= 0; i
< Count
; i
++)
637 hdr
= (DISPATCHER_HEADER
*) KiGetWaitableObjectFromObject(Object
[i
]);
638 Abandoned
= KiSideEffectsBeforeWake(hdr
, CurrentThread
) ? TRUE
: Abandoned
;
641 KeReleaseDispatcherDatabaseLock(OldIrql
);
643 if (Timeout
!= NULL
&& Timeout
->QuadPart
!= 0)
645 KeCancelTimer(&CurrentThread
->Timer
);
648 DPRINT("All objects are (already) signaled!\n");
650 if (Abandoned
== TRUE
)
652 return (STATUS_ABANDONED_WAIT_0
);
655 return (STATUS_WAIT_0
);
658 //zero timeout is used for testing if the object(s) can be immediately acquired
659 if (Timeout
!= NULL
&& Timeout
->QuadPart
== 0)
661 KeReleaseDispatcherDatabaseLock(OldIrql
);
662 return STATUS_TIMEOUT
;
666 * Check if we have already timed out
668 if (Timeout
!= NULL
&& KiIsObjectSignalled(&CurrentThread
->Timer
.Header
, CurrentThread
))
670 KiSideEffectsBeforeWake(&CurrentThread
->Timer
.Header
, CurrentThread
);
671 KeReleaseDispatcherDatabaseLock(OldIrql
);
672 KeCancelTimer(&CurrentThread
->Timer
);
673 return (STATUS_TIMEOUT
);
676 /* Append wait block to the KTHREAD wait block list */
677 CurrentThread
->WaitBlockList
= blk
= WaitBlockArray
;
682 CurrentThread
->WaitStatus
= WaitStatus
;;
684 for (i
= 0; i
< Count
; i
++)
686 hdr
= (DISPATCHER_HEADER
*) KiGetWaitableObjectFromObject(Object
[i
]);
688 blk
->Object
= KiGetWaitableObjectFromObject(Object
[i
]);
689 blk
->Thread
= CurrentThread
;
690 blk
->WaitKey
= (USHORT
)(STATUS_WAIT_0
+ i
);
691 blk
->WaitType
= (USHORT
)WaitType
;
693 if (i
== (Count
- 1))
697 blk
->NextWaitBlock
= &CurrentThread
->WaitBlock
[3];
701 blk
->NextWaitBlock
= NULL
;
706 blk
->NextWaitBlock
= blk
+ 1;
710 * add wait block to disp. obj. wait list
711 * Use FIFO for all waits except for queues which use LIFO
713 if (WaitReason
== WrQueue
)
715 InsertHeadList(&hdr
->WaitListHead
, &blk
->WaitListEntry
);
719 InsertTailList(&hdr
->WaitListHead
, &blk
->WaitListEntry
);
722 blk
= blk
->NextWaitBlock
;
727 CurrentThread
->WaitBlock
[3].Object
= (PVOID
) & CurrentThread
->Timer
;
728 CurrentThread
->WaitBlock
[3].Thread
= CurrentThread
;
729 CurrentThread
->WaitBlock
[3].WaitKey
= STATUS_TIMEOUT
;
730 CurrentThread
->WaitBlock
[3].WaitType
= WaitAny
;
731 CurrentThread
->WaitBlock
[3].NextWaitBlock
= NULL
;
733 InsertTailList(&CurrentThread
->Timer
.Header
.WaitListHead
,
734 &CurrentThread
->WaitBlock
[3].WaitListEntry
);
738 if (CurrentThread
->Queue
&& WaitReason
!= WrQueue
)
740 DPRINT("queue: sleep on something else\n");
741 CurrentThread
->Queue
->CurrentCount
--;
743 //wake another thread
744 if (CurrentThread
->Queue
->CurrentCount
< CurrentThread
->Queue
->MaximumCount
&&
745 !IsListEmpty(&CurrentThread
->Queue
->EntryListHead
))
747 KiDispatcherObjectWake(&CurrentThread
->Queue
->Header
, IO_NO_INCREMENT
);
751 PsBlockThread(&Status
, Alertable
, WaitMode
, TRUE
, OldIrql
, (UCHAR
)WaitReason
);
754 OldIrql
= KeAcquireDispatcherDatabaseLock ();
755 if (CurrentThread
->Queue
&& WaitReason
!= WrQueue
)
757 DPRINT("queue: wake from something else\n");
758 CurrentThread
->Queue
->CurrentCount
++;
760 if (Status
== STATUS_KERNEL_APC
)
762 CurrentThread
->WaitNext
= TRUE
;
763 CurrentThread
->WaitIrql
= OldIrql
;
767 KeReleaseDispatcherDatabaseLock(OldIrql
);
770 } while (Status
== STATUS_KERNEL_APC
);
775 KeCancelTimer(&CurrentThread
->Timer
);
778 DPRINT("Returning from KeWaitForMultipleObjects()\n");
782 VOID
KeInitializeDispatcher(VOID
)
784 KeInitializeSpinLock(&DispatcherDatabaseLock
);
788 NtWaitForMultipleObjects(IN ULONG ObjectCount
,
789 IN PHANDLE ObjectsArray
,
790 IN WAIT_TYPE WaitType
,
791 IN BOOLEAN Alertable
,
792 IN PLARGE_INTEGER TimeOut OPTIONAL
)
794 KWAIT_BLOCK WaitBlockArray
[MAXIMUM_WAIT_OBJECTS
];
795 HANDLE SafeObjectsArray
[MAXIMUM_WAIT_OBJECTS
];
796 PVOID ObjectPtrArray
[MAXIMUM_WAIT_OBJECTS
];
798 KPROCESSOR_MODE PreviousMode
;
799 LARGE_INTEGER SafeTimeOut
;
800 NTSTATUS Status
= STATUS_SUCCESS
;
802 DPRINT("NtWaitForMultipleObjects(ObjectCount %lu ObjectsArray[] %x, Alertable %d, "
803 "TimeOut %x)\n", ObjectCount
,ObjectsArray
,Alertable
,TimeOut
);
805 PreviousMode
= ExGetPreviousMode();
807 if (ObjectCount
> MAXIMUM_WAIT_OBJECTS
)
808 return STATUS_UNSUCCESSFUL
;
809 if (0 == ObjectCount
)
810 return STATUS_INVALID_PARAMETER
;
812 if(PreviousMode
!= KernelMode
)
816 ProbeForRead(ObjectsArray
,
817 ObjectCount
* sizeof(ObjectsArray
[0]),
819 /* make a copy so we don't have to guard with SEH later and keep track of
820 what objects we referenced in case dereferencing pointers suddenly fails */
821 RtlCopyMemory(SafeObjectsArray
, ObjectsArray
, ObjectCount
* sizeof(ObjectsArray
[0]));
822 ObjectsArray
= SafeObjectsArray
;
826 ProbeForRead(TimeOut
,
827 sizeof(LARGE_INTEGER
),
829 /* make a local copy of the timeout on the stack */
830 SafeTimeOut
= *TimeOut
;
831 TimeOut
= &SafeTimeOut
;
836 Status
= _SEH_GetExceptionCode();
840 if(!NT_SUCCESS(Status
))
846 /* reference all objects */
847 for (i
= 0; i
< ObjectCount
; i
++)
849 Status
= ObReferenceObjectByHandle(ObjectsArray
[i
],
855 if (!NT_SUCCESS(Status
) || !KiIsObjectWaitable(ObjectPtrArray
[i
]))
857 if (NT_SUCCESS(Status
))
859 DPRINT1("Waiting for object type '%wZ' is not supported\n",
860 &BODY_TO_HEADER(ObjectPtrArray
[i
])->ObjectType
->TypeName
);
861 Status
= STATUS_HANDLE_NOT_WAITABLE
;
864 /* dereference all referenced objects */
865 for (j
= 0; j
< i
; j
++)
867 ObDereferenceObject(ObjectPtrArray
[j
]);
874 Status
= KeWaitForMultipleObjects(ObjectCount
,
883 /* dereference all objects */
884 for (i
= 0; i
< ObjectCount
; i
++)
886 ObDereferenceObject(ObjectPtrArray
[i
]);
897 NtWaitForSingleObject(IN HANDLE ObjectHandle
,
898 IN BOOLEAN Alertable
,
899 IN PLARGE_INTEGER TimeOut OPTIONAL
)
902 KPROCESSOR_MODE PreviousMode
;
903 LARGE_INTEGER SafeTimeOut
;
904 NTSTATUS Status
= STATUS_SUCCESS
;
906 DPRINT("NtWaitForSingleObject(ObjectHandle %x, Alertable %d, TimeOut %x)\n",
907 ObjectHandle
,Alertable
,TimeOut
);
909 PreviousMode
= ExGetPreviousMode();
911 if(TimeOut
!= NULL
&& PreviousMode
!= KernelMode
)
915 ProbeForRead(TimeOut
,
916 sizeof(LARGE_INTEGER
),
918 /* make a copy on the stack */
919 SafeTimeOut
= *TimeOut
;
920 TimeOut
= &SafeTimeOut
;
924 Status
= _SEH_GetExceptionCode();
928 if(!NT_SUCCESS(Status
))
934 Status
= ObReferenceObjectByHandle(ObjectHandle
,
940 if (!NT_SUCCESS(Status
))
944 if (!KiIsObjectWaitable(ObjectPtr
))
946 DPRINT1("Waiting for object type '%wZ' is not supported\n",
947 &BODY_TO_HEADER(ObjectPtr
)->ObjectType
->TypeName
);
948 Status
= STATUS_HANDLE_NOT_WAITABLE
;
952 Status
= KeWaitForSingleObject(ObjectPtr
,
959 ObDereferenceObject(ObjectPtr
);
966 NtSignalAndWaitForSingleObject(IN HANDLE ObjectHandleToSignal
,
967 IN HANDLE WaitableObjectHandle
,
968 IN BOOLEAN Alertable
,
969 IN PLARGE_INTEGER TimeOut OPTIONAL
)
971 KPROCESSOR_MODE PreviousMode
;
972 DISPATCHER_HEADER
* hdr
;
975 LARGE_INTEGER SafeTimeOut
;
976 NTSTATUS Status
= STATUS_SUCCESS
;
978 PreviousMode
= ExGetPreviousMode();
980 if(TimeOut
!= NULL
&& PreviousMode
!= KernelMode
)
984 ProbeForRead(TimeOut
,
985 sizeof(LARGE_INTEGER
),
987 /* make a copy on the stack */
988 SafeTimeOut
= *TimeOut
;
989 TimeOut
= &SafeTimeOut
;
993 Status
= _SEH_GetExceptionCode();
997 if(!NT_SUCCESS(Status
))
1003 Status
= ObReferenceObjectByHandle(ObjectHandleToSignal
,
1009 if (!NT_SUCCESS(Status
))
1014 Status
= ObReferenceObjectByHandle(WaitableObjectHandle
,
1020 if (!NT_SUCCESS(Status
))
1022 ObDereferenceObject(SignalObj
);
1026 hdr
= (DISPATCHER_HEADER
*)SignalObj
;
1029 case InternalNotificationEvent
:
1030 case InternalSynchronizationEvent
:
1031 KeSetEvent(SignalObj
,
1036 case InternalMutexType
:
1037 KeReleaseMutex(SignalObj
,
1041 case InternalSemaphoreType
:
1042 KeReleaseSemaphore(SignalObj
,
1043 SEMAPHORE_INCREMENT
,
1049 ObDereferenceObject(SignalObj
);
1050 ObDereferenceObject(WaitObj
);
1051 return STATUS_OBJECT_TYPE_MISMATCH
;
1054 Status
= KeWaitForSingleObject(WaitObj
,
1060 ObDereferenceObject(SignalObj
);
1061 ObDereferenceObject(WaitObj
);