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
6 * PROGRAMMER: David Welch (welch@mcmail.com)
9 * 12/1/99: Phillip Susi: Fixed wake code in KeDispatcherObjectWake
10 * so that things like KeWaitForXXX() return the correct value
13 /* NOTES ********************************************************************
17 /* INCLUDES ******************************************************************/
22 #include <internal/debug.h>
24 /* GLOBALS ******************************************************************/
26 static KSPIN_LOCK DispatcherDatabaseLock
;
28 #define KeDispatcherObjectWakeOne(hdr, increment) KeDispatcherObjectWakeOneOrAll(hdr, increment, FALSE)
29 #define KeDispatcherObjectWakeAll(hdr, increment) KeDispatcherObjectWakeOneOrAll(hdr, increment, TRUE)
31 extern POBJECT_TYPE EXPORTED ExMutantObjectType
;
32 extern POBJECT_TYPE EXPORTED ExSemaphoreObjectType
;
33 extern POBJECT_TYPE EXPORTED ExTimerType
;
35 /* FUNCTIONS *****************************************************************/
37 VOID
KeInitializeDispatcherHeader(DISPATCHER_HEADER
* Header
,
42 Header
->Type
= (UCHAR
)Type
;
45 Header
->Size
= (UCHAR
)Size
;
46 Header
->SignalState
= SignalState
;
47 InitializeListHead(&(Header
->WaitListHead
));
52 KeAcquireDispatcherDatabaseLock(VOID
)
54 * PURPOSE: Acquires the dispatcher database lock for the caller
59 DPRINT("KeAcquireDispatcherDatabaseLock()\n");
61 KeAcquireSpinLock (&DispatcherDatabaseLock
, &OldIrql
);
67 KeAcquireDispatcherDatabaseLockAtDpcLevel(VOID
)
69 * PURPOSE: Acquires the dispatcher database lock for the caller
72 DPRINT("KeAcquireDispatcherDatabaseLockAtDpcLevel()\n");
74 KeAcquireSpinLockAtDpcLevel (&DispatcherDatabaseLock
);
79 KeReleaseDispatcherDatabaseLock(KIRQL OldIrql
)
81 DPRINT("KeReleaseDispatcherDatabaseLock(OldIrql %x)\n",OldIrql
);
82 if (!KeIsExecutingDpc() &&
83 OldIrql
< DISPATCH_LEVEL
&&
84 KeGetCurrentThread() != NULL
&&
85 KeGetCurrentThread() == KeGetCurrentKPCR()->PrcbData
.IdleThread
)
87 PsDispatchThreadNoLock(THREAD_STATE_READY
);
92 KeReleaseSpinLock(&DispatcherDatabaseLock
, OldIrql
);
98 KeReleaseDispatcherDatabaseLockFromDpcLevel(VOID
)
100 DPRINT("KeReleaseDispatcherDatabaseLock()\n");
102 KeReleaseSpinLockFromDpcLevel(&DispatcherDatabaseLock
);
107 KiSideEffectsBeforeWake(DISPATCHER_HEADER
* hdr
,
110 * FUNCTION: Perform side effects on object before a wait for a thread is
114 BOOLEAN Abandoned
= FALSE
;
118 case InternalSynchronizationEvent
:
119 hdr
->SignalState
= 0;
122 case InternalQueueType
:
125 case InternalSemaphoreType
:
129 case InternalProcessType
:
132 case InternalThreadType
:
135 case InternalNotificationEvent
:
138 case InternalSynchronizationTimer
:
139 hdr
->SignalState
= FALSE
;
142 case InternalNotificationTimer
:
145 case InternalMutexType
:
149 Mutex
= CONTAINING_RECORD(hdr
, KMUTEX
, Header
);
151 ASSERT(hdr
->SignalState
<= 1);
152 if (hdr
->SignalState
== 0)
156 DPRINT("Thread == NULL!\n");
159 Abandoned
= Mutex
->Abandoned
;
161 InsertTailList(&Thread
->MutantListHead
, &Mutex
->MutantListEntry
);
162 Mutex
->OwnerThread
= Thread
;
163 Mutex
->Abandoned
= FALSE
;
169 DbgPrint("(%s:%d) Dispatcher object %x has unknown type\n", __FILE__
, __LINE__
, hdr
);
177 KiIsObjectSignalled(DISPATCHER_HEADER
* hdr
,
180 if (hdr
->Type
== InternalMutexType
)
184 Mutex
= CONTAINING_RECORD(hdr
, KMUTEX
, Header
);
186 ASSERT(hdr
->SignalState
<= 1);
188 if ((hdr
->SignalState
< 1 && Mutex
->OwnerThread
== Thread
) || hdr
->SignalState
== 1)
198 if (hdr
->SignalState
<= 0)
208 /* Must be called with the dispatcher lock held */
209 BOOLEAN
KiAbortWaitThread(PKTHREAD Thread
, NTSTATUS WaitStatus
)
211 PKWAIT_BLOCK WaitBlock
;
214 /* if we are blocked, we must be waiting on something also */
215 ASSERT((Thread
->State
== THREAD_STATE_BLOCKED
) == (Thread
->WaitBlockList
!= NULL
));
217 WaitBlock
= (PKWAIT_BLOCK
)Thread
->WaitBlockList
;
218 WasWaiting
= (WaitBlock
!= NULL
);
222 RemoveEntryList(&WaitBlock
->WaitListEntry
);
223 WaitBlock
= WaitBlock
->NextWaitBlock
;
226 Thread
->WaitBlockList
= NULL
;
230 PsUnblockThread((PETHREAD
)Thread
, &WaitStatus
, 0);
236 KeDispatcherObjectWakeOneOrAll(DISPATCHER_HEADER
* hdr
,
241 PKWAIT_BLOCK WaiterHead
;
242 PLIST_ENTRY EnumEntry
;
246 BOOLEAN WakedAny
= FALSE
;
248 DPRINT("KeDispatcherObjectWakeOnOrAll(hdr %x)\n", hdr
);
249 DPRINT ("hdr->WaitListHead.Flink %x hdr->WaitListHead.Blink %x\n",
250 hdr
->WaitListHead
.Flink
, hdr
->WaitListHead
.Blink
);
252 if (IsListEmpty(&hdr
->WaitListHead
))
257 //enum waiters for this dispatcher object
258 EnumEntry
= hdr
->WaitListHead
.Flink
;
259 while (EnumEntry
!= &hdr
->WaitListHead
&& (WakeAll
|| !WakedAny
))
261 WaiterHead
= CONTAINING_RECORD(EnumEntry
, KWAIT_BLOCK
, WaitListEntry
);
262 DPRINT("current_entry %x current %x\n", EnumEntry
, WaiterHead
);
263 EnumEntry
= EnumEntry
->Flink
;
264 ASSERT(WaiterHead
->Thread
!= NULL
);
265 ASSERT(WaiterHead
->Thread
->WaitBlockList
!= NULL
);
269 if (WaiterHead
->WaitType
== WaitAny
)
271 DPRINT("WaitAny: Remove all wait blocks.\n");
272 for (Waiter
= WaiterHead
->Thread
->WaitBlockList
; Waiter
; Waiter
= Waiter
->NextWaitBlock
)
274 RemoveEntryList(&Waiter
->WaitListEntry
);
277 WaiterHead
->Thread
->WaitBlockList
= NULL
;
280 * If a WakeAll KiSideEffectsBeforeWake(hdr,.. will be called several times,
281 * but thats ok since WakeAll objects has no sideeffects.
283 Abandoned
|= KiSideEffectsBeforeWake(hdr
, WaiterHead
->Thread
);
287 DPRINT("WaitAll: All WaitAll objects must be signaled.\n");
291 //all WaitAll obj. for thread need to be signaled to satisfy a wake
292 for (Waiter
= WaiterHead
->Thread
->WaitBlockList
; Waiter
; Waiter
= Waiter
->NextWaitBlock
)
294 //no need to check hdr since it has to be signaled
295 if (Waiter
->WaitType
== WaitAll
&& Waiter
->Object
!= hdr
)
297 if (!KiIsObjectSignalled(Waiter
->Object
, Waiter
->Thread
))
307 for (Waiter
= WaiterHead
->Thread
->WaitBlockList
; Waiter
; Waiter
= Waiter
->NextWaitBlock
)
309 RemoveEntryList(&Waiter
->WaitListEntry
);
311 if (Waiter
->WaitType
== WaitAll
)
313 Abandoned
|= KiSideEffectsBeforeWake(Waiter
->Object
, Waiter
->Thread
);
316 //no WaitAny objects can possibly be signaled since we are here
317 ASSERT(!(Waiter
->WaitType
== WaitAny
318 && KiIsObjectSignalled(Waiter
->Object
, Waiter
->Thread
)));
321 WaiterHead
->Thread
->WaitBlockList
= NULL
;
325 if (WaiterHead
->Thread
->WaitBlockList
== NULL
)
327 Status
= WaiterHead
->WaitKey
;
330 DPRINT("Abandoned mutex among objects");
331 Status
+= STATUS_ABANDONED_WAIT_0
;
335 DPRINT("Waking %x status = %x\n", WaiterHead
->Thread
, Status
);
336 PsUnblockThread(CONTAINING_RECORD(WaiterHead
->Thread
, ETHREAD
, Tcb
),
345 BOOLEAN
KiDispatcherObjectWake(DISPATCHER_HEADER
* hdr
, KPRIORITY increment
)
347 * FUNCTION: Wake threads waiting on a dispatcher object
348 * NOTE: The exact semantics of waking are dependant on the type of object
353 DPRINT("Entering KeDispatcherObjectWake(hdr %x)\n",hdr
);
354 // DPRINT("hdr->WaitListHead %x hdr->WaitListHead.Flink %x\n",
355 // &hdr->WaitListHead,hdr->WaitListHead.Flink);
356 DPRINT("hdr->Type %x\n",hdr
->Type
);
359 case InternalNotificationEvent
:
360 return(KeDispatcherObjectWakeAll(hdr
, increment
));
362 case InternalNotificationTimer
:
363 return(KeDispatcherObjectWakeAll(hdr
, increment
));
365 case InternalSynchronizationEvent
:
366 return(KeDispatcherObjectWakeOne(hdr
, increment
));
368 case InternalSynchronizationTimer
:
369 return(KeDispatcherObjectWakeOne(hdr
, increment
));
371 case InternalQueueType
:
372 return(KeDispatcherObjectWakeOne(hdr
, increment
));
374 case InternalSemaphoreType
:
375 DPRINT("hdr->SignalState %d\n", hdr
->SignalState
);
376 if(hdr
->SignalState
>0)
380 DPRINT("Waking one semaphore waiter\n");
381 Ret
= KeDispatcherObjectWakeOne(hdr
, increment
);
382 } while(hdr
->SignalState
> 0 && Ret
) ;
387 case InternalProcessType
:
388 return(KeDispatcherObjectWakeAll(hdr
, increment
));
390 case InternalThreadType
:
391 return(KeDispatcherObjectWakeAll(hdr
, increment
));
393 case InternalMutexType
:
394 return(KeDispatcherObjectWakeOne(hdr
, increment
));
396 DbgPrint("Dispatcher object %x has unknown type %d\n", hdr
, hdr
->Type
);
406 KeWaitForSingleObject(PVOID Object
,
407 KWAIT_REASON WaitReason
,
408 KPROCESSOR_MODE WaitMode
,
410 PLARGE_INTEGER Timeout
)
412 * FUNCTION: Puts the current thread into a wait state until the
413 * given dispatcher object is set to signalled
415 * Object = Object to wait on
416 * WaitReason = Reason for the wait (debugging aid)
417 * WaitMode = Can be KernelMode or UserMode, if UserMode then
418 * user-mode APCs can be delivered and the thread's
419 * stack can be paged out
420 * Altertable = Specifies if the wait is a alertable
421 * Timeout = Optional timeout value
425 return KeWaitForMultipleObjects(1,
438 KiGetWaitableObjectFromObject(PVOID Object
)
440 //special case when waiting on file objects
441 if ( ((PDISPATCHER_HEADER
)Object
)->Type
== InternalFileType
)
443 return &((PFILE_OBJECT
)Object
)->Event
;
451 KiIsObjectWaitable(PVOID Object
)
453 POBJECT_HEADER Header
;
454 Header
= BODY_TO_HEADER(Object
);
455 if (Header
->ObjectType
== ExEventObjectType
||
456 Header
->ObjectType
== ExIoCompletionType
||
457 Header
->ObjectType
== ExMutantObjectType
||
458 Header
->ObjectType
== ExSemaphoreObjectType
||
459 Header
->ObjectType
== ExTimerType
||
460 Header
->ObjectType
== PsProcessType
||
461 Header
->ObjectType
== PsThreadType
||
462 Header
->ObjectType
== IoFileObjectType
)
476 KeWaitForMultipleObjects(ULONG Count
,
479 KWAIT_REASON WaitReason
,
480 KPROCESSOR_MODE WaitMode
,
482 PLARGE_INTEGER Timeout
,
483 PKWAIT_BLOCK WaitBlockArray
)
485 DISPATCHER_HEADER
*hdr
;
487 PKTHREAD CurrentThread
;
494 DPRINT("Entering KeWaitForMultipleObjects(Count %lu Object[] %p) "
495 "PsGetCurrentThread() %x\n", Count
, Object
, PsGetCurrentThread());
497 ASSERT(0 < Count
&& Count
<= MAXIMUM_WAIT_OBJECTS
);
499 CurrentThread
= KeGetCurrentThread();
502 * Work out where we are going to put the wait blocks
504 if (WaitBlockArray
== NULL
)
506 if (Count
> THREAD_WAIT_OBJECTS
)
508 DPRINT("(%s:%d) Too many objects!\n", __FILE__
, __LINE__
);
509 return (STATUS_UNSUCCESSFUL
);
511 WaitBlockArray
= &CurrentThread
->WaitBlock
[0];
515 if (Count
> MAXIMUM_WAIT_OBJECTS
)
517 DPRINT("(%s:%d) Too many objects!\n", __FILE__
, __LINE__
);
518 return (STATUS_UNSUCCESSFUL
);
525 * Set up the timeout if required
527 if (Timeout
!= NULL
&& Timeout
->QuadPart
!= 0)
529 KeSetTimer(&CurrentThread
->Timer
, *Timeout
, NULL
);
534 if (CurrentThread
->WaitNext
)
536 CurrentThread
->WaitNext
= FALSE
;
537 OldIrql
= CurrentThread
->WaitIrql
;
541 OldIrql
= KeAcquireDispatcherDatabaseLock ();
546 * A Wait can either be Alertable, or Non-Alertable.
547 * An Alertable Wait means that APCs can "Wake" the Thread, also called UnWaiting
548 * If an APC is Pending however, we must refuse an Alertable Wait. Such a wait would
549 * be pointless since an APC is just about to be delivered.
551 * There are many ways to check if it's safe to be alertable, and these are the ones
552 * that I could think of:
553 * - The Thread is already Alerted. So someone beat us to the punch and we bail out.
554 * - The Thread is Waiting in User-Mode, the APC Queue is not-empty.
555 * It's defintely clear that we have incoming APCs, so we need to bail out and let the system
556 * know that there are Pending User APCs (so they can be Delivered and maybe we can try again)
558 * Furthermore, wether or not we want to be Alertable, if the Thread is waiting in User-Mode, and there
559 * are Pending User APCs, we should bail out, since APCs will be delivered any second.
562 if (CurrentThread
->Alerted
[(int)WaitMode
]) {
563 CurrentThread
->Alerted
[(int)WaitMode
] = FALSE
;
564 DPRINT("Alertability failed\n");
565 KeReleaseDispatcherDatabaseLock(OldIrql
);
566 return (STATUS_ALERTED
);
567 } else if ((!IsListEmpty(&CurrentThread
->ApcState
.ApcListHead
[UserMode
])) && (WaitMode
== UserMode
)) {
568 DPRINT1("Alertability failed\n");
569 CurrentThread
->ApcState
.UserApcPending
= TRUE
;
570 KeReleaseDispatcherDatabaseLock(OldIrql
);
571 return (STATUS_USER_APC
);
573 } else if ((CurrentThread
->ApcState
.UserApcPending
) && (WaitMode
!= KernelMode
)) {
574 DPRINT1("Alertability failed\n");
575 KeReleaseDispatcherDatabaseLock(OldIrql
);
576 return (STATUS_USER_APC
);
580 * Check if the wait is (already) satisfied
584 for (i
= 0; i
< Count
; i
++)
586 hdr
= (DISPATCHER_HEADER
*) KiGetWaitableObjectFromObject(Object
[i
]);
588 if (KiIsObjectSignalled(hdr
, CurrentThread
))
592 if (WaitType
== WaitAny
)
594 Abandoned
= KiSideEffectsBeforeWake(hdr
, CurrentThread
) ? TRUE
: Abandoned
;
596 if (Timeout
!= NULL
&& Timeout
->QuadPart
!= 0)
598 KeCancelTimer(&CurrentThread
->Timer
);
601 KeReleaseDispatcherDatabaseLock(OldIrql
);
603 DPRINT("One object is (already) signaled!\n");
604 if (Abandoned
== TRUE
)
606 return (STATUS_ABANDONED_WAIT_0
+ i
);
609 return (STATUS_WAIT_0
+ i
);
615 if ((WaitType
== WaitAll
) && (CountSignaled
== Count
))
617 for (i
= 0; i
< Count
; i
++)
619 hdr
= (DISPATCHER_HEADER
*) KiGetWaitableObjectFromObject(Object
[i
]);
620 Abandoned
= KiSideEffectsBeforeWake(hdr
, CurrentThread
) ? TRUE
: Abandoned
;
623 if (Timeout
!= NULL
&& Timeout
->QuadPart
!= 0)
625 KeCancelTimer(&CurrentThread
->Timer
);
628 KeReleaseDispatcherDatabaseLock(OldIrql
);
629 DPRINT("All objects are (already) signaled!\n");
631 if (Abandoned
== TRUE
)
633 return (STATUS_ABANDONED_WAIT_0
);
636 return (STATUS_WAIT_0
);
639 //zero timeout is used for testing if the object(s) can be immediately acquired
640 if (Timeout
!= NULL
&& Timeout
->QuadPart
== 0)
642 KeReleaseDispatcherDatabaseLock(OldIrql
);
643 return STATUS_TIMEOUT
;
647 * Check if we have already timed out
649 if (Timeout
!= NULL
&& KiIsObjectSignalled(&CurrentThread
->Timer
.Header
, CurrentThread
))
651 KiSideEffectsBeforeWake(&CurrentThread
->Timer
.Header
, CurrentThread
);
652 KeCancelTimer(&CurrentThread
->Timer
);
653 KeReleaseDispatcherDatabaseLock(OldIrql
);
654 return (STATUS_TIMEOUT
);
657 /* Append wait block to the KTHREAD wait block list */
658 CurrentThread
->WaitBlockList
= blk
= WaitBlockArray
;
663 CurrentThread
->WaitStatus
= STATUS_UNSUCCESSFUL
;
665 for (i
= 0; i
< Count
; i
++)
667 hdr
= (DISPATCHER_HEADER
*) KiGetWaitableObjectFromObject(Object
[i
]);
669 blk
->Object
= KiGetWaitableObjectFromObject(Object
[i
]);
670 blk
->Thread
= CurrentThread
;
671 blk
->WaitKey
= (USHORT
)(STATUS_WAIT_0
+ i
);
672 blk
->WaitType
= (USHORT
)WaitType
;
674 if (i
== (Count
- 1))
678 blk
->NextWaitBlock
= &CurrentThread
->WaitBlock
[3];
682 blk
->NextWaitBlock
= NULL
;
687 blk
->NextWaitBlock
= blk
+ 1;
691 * add wait block to disp. obj. wait list
692 * Use FIFO for all waits except for queues which use LIFO
694 if (WaitReason
== WrQueue
)
696 InsertHeadList(&hdr
->WaitListHead
, &blk
->WaitListEntry
);
700 InsertTailList(&hdr
->WaitListHead
, &blk
->WaitListEntry
);
703 blk
= blk
->NextWaitBlock
;
708 CurrentThread
->WaitBlock
[3].Object
= (PVOID
) & CurrentThread
->Timer
;
709 CurrentThread
->WaitBlock
[3].Thread
= CurrentThread
;
710 CurrentThread
->WaitBlock
[3].WaitKey
= STATUS_TIMEOUT
;
711 CurrentThread
->WaitBlock
[3].WaitType
= WaitAny
;
712 CurrentThread
->WaitBlock
[3].NextWaitBlock
= NULL
;
714 InsertTailList(&CurrentThread
->Timer
.Header
.WaitListHead
,
715 &CurrentThread
->WaitBlock
[3].WaitListEntry
);
719 if (CurrentThread
->Queue
&& WaitReason
!= WrQueue
)
721 DPRINT("queue: sleep on something else\n");
722 CurrentThread
->Queue
->CurrentCount
--;
724 //wake another thread
725 if (CurrentThread
->Queue
->CurrentCount
< CurrentThread
->Queue
->MaximumCount
&&
726 !IsListEmpty(&CurrentThread
->Queue
->EntryListHead
))
728 KiDispatcherObjectWake(&CurrentThread
->Queue
->Header
, IO_NO_INCREMENT
);
732 PsBlockThread(&Status
, Alertable
, WaitMode
, TRUE
, OldIrql
, (UCHAR
)WaitReason
);
735 OldIrql
= KeAcquireDispatcherDatabaseLock ();
736 if (CurrentThread
->Queue
&& WaitReason
!= WrQueue
)
738 DPRINT("queue: wake from something else\n");
739 CurrentThread
->Queue
->CurrentCount
++;
741 if (Status
== STATUS_KERNEL_APC
)
743 CurrentThread
->WaitNext
= TRUE
;
744 CurrentThread
->WaitIrql
= OldIrql
;
748 KeReleaseDispatcherDatabaseLock(OldIrql
);
751 } while (Status
== STATUS_KERNEL_APC
);
756 KeCancelTimer(&CurrentThread
->Timer
);
759 DPRINT("Returning from KeWaitForMultipleObjects()\n");
763 VOID
KeInitializeDispatcher(VOID
)
765 KeInitializeSpinLock(&DispatcherDatabaseLock
);
769 NtWaitForMultipleObjects(IN ULONG Count
,
771 IN WAIT_TYPE WaitType
,
772 IN BOOLEAN Alertable
,
773 IN PLARGE_INTEGER UnsafeTime
)
775 KWAIT_BLOCK WaitBlockArray
[MAXIMUM_WAIT_OBJECTS
];
776 PVOID ObjectPtrArray
[MAXIMUM_WAIT_OBJECTS
];
779 KPROCESSOR_MODE WaitMode
;
782 DPRINT("NtWaitForMultipleObjects(Count %lu Object[] %x, Alertable %d, "
783 "Time %x)\n", Count
,Object
,Alertable
,Time
);
785 if (Count
> MAXIMUM_WAIT_OBJECTS
)
786 return STATUS_UNSUCCESSFUL
;
788 return STATUS_INVALID_PARAMETER
;
792 Status
= MmCopyFromCaller(&Time
, UnsafeTime
, sizeof(LARGE_INTEGER
));
793 if (!NT_SUCCESS(Status
))
799 WaitMode
= ExGetPreviousMode();
801 /* reference all objects */
802 for (i
= 0; i
< Count
; i
++)
804 Status
= ObReferenceObjectByHandle(Object
[i
],
810 if (!NT_SUCCESS(Status
) || !KiIsObjectWaitable(ObjectPtrArray
[i
]))
812 if (NT_SUCCESS(Status
))
814 DPRINT1("Waiting for object type '%wZ' is not supported\n",
815 &BODY_TO_HEADER(ObjectPtrArray
[i
])->ObjectType
->TypeName
);
816 Status
= STATUS_HANDLE_NOT_WAITABLE
;
819 /* dereference all referenced objects */
820 for (j
= 0; j
< i
; j
++)
822 ObDereferenceObject(ObjectPtrArray
[j
]);
829 Status
= KeWaitForMultipleObjects(Count
,
835 UnsafeTime
? &Time
: NULL
,
838 /* dereference all objects */
839 for (i
= 0; i
< Count
; i
++)
841 ObDereferenceObject(ObjectPtrArray
[i
]);
852 NtWaitForSingleObject(IN HANDLE Object
,
853 IN BOOLEAN Alertable
,
854 IN PLARGE_INTEGER UnsafeTime
)
858 KPROCESSOR_MODE WaitMode
;
861 DPRINT("NtWaitForSingleObject(Object %x, Alertable %d, Time %x)\n",
862 Object
,Alertable
,Time
);
866 Status
= MmCopyFromCaller(&Time
, UnsafeTime
, sizeof(LARGE_INTEGER
));
867 if (!NT_SUCCESS(Status
))
873 WaitMode
= ExGetPreviousMode();
875 Status
= ObReferenceObjectByHandle(Object
,
881 if (!NT_SUCCESS(Status
))
885 if (!KiIsObjectWaitable(ObjectPtr
))
887 DPRINT1("Waiting for object type '%wZ' is not supported\n",
888 &BODY_TO_HEADER(ObjectPtr
)->ObjectType
->TypeName
);
889 Status
= STATUS_HANDLE_NOT_WAITABLE
;
893 Status
= KeWaitForSingleObject(ObjectPtr
,
897 UnsafeTime
? &Time
: NULL
);
900 ObDereferenceObject(ObjectPtr
);
907 NtSignalAndWaitForSingleObject(IN HANDLE SignalObject
,
908 IN HANDLE WaitObject
,
909 IN BOOLEAN Alertable
,
910 IN PLARGE_INTEGER Time
)
912 KPROCESSOR_MODE WaitMode
;
913 DISPATCHER_HEADER
* hdr
;
918 WaitMode
= ExGetPreviousMode();
919 Status
= ObReferenceObjectByHandle(SignalObject
,
925 if (!NT_SUCCESS(Status
))
930 Status
= ObReferenceObjectByHandle(WaitObject
,
936 if (!NT_SUCCESS(Status
))
938 ObDereferenceObject(SignalObj
);
942 hdr
= (DISPATCHER_HEADER
*)SignalObj
;
945 case InternalNotificationEvent
:
946 case InternalSynchronizationEvent
:
947 KeSetEvent(SignalObj
,
952 case InternalMutexType
:
953 KeReleaseMutex(SignalObj
,
957 case InternalSemaphoreType
:
958 KeReleaseSemaphore(SignalObj
,
965 ObDereferenceObject(SignalObj
);
966 ObDereferenceObject(WaitObj
);
967 return STATUS_OBJECT_TYPE_MISMATCH
;
970 Status
= KeWaitForSingleObject(WaitObj
,
976 ObDereferenceObject(SignalObj
);
977 ObDereferenceObject(WaitObj
);