Fixes for problems with NtReplyWaitReceive and KeWaitForSingleObject
[reactos.git] / reactos / ntoskrnl / ke / wait.c
1 /*
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)
7 * REVISION HISTORY:
8 * 21/07/98: Created
9 * 12/1/99: Phillip Susi: Fixed wake code in KeDispatcherObjectWake
10 * so that things like KeWaitForXXX() return the correct value
11 */
12
13 /* NOTES ********************************************************************
14 *
15 */
16
17 /* INCLUDES ******************************************************************/
18
19 #include <ddk/ntddk.h>
20 #include <internal/ke.h>
21 #include <internal/ps.h>
22 #include <internal/ob.h>
23 #include <internal/id.h>
24
25 #define NDEBUG
26 #include <internal/debug.h>
27
28 /* GLOBALS ******************************************************************/
29
30 static KSPIN_LOCK DispatcherDatabaseLock;
31 static BOOLEAN WaitSet = FALSE;
32 static KIRQL oldlvl = PASSIVE_LEVEL;
33 static PKTHREAD Owner = NULL;
34
35 /* FUNCTIONS *****************************************************************/
36
37 VOID KeInitializeDispatcherHeader(DISPATCHER_HEADER* Header,
38 ULONG Type,
39 ULONG Size,
40 ULONG SignalState)
41 {
42 Header->Type = Type;
43 Header->Absolute = 0;
44 Header->Inserted = 0;
45 Header->Size = Size;
46 Header->SignalState = SignalState;
47 InitializeListHead(&(Header->WaitListHead));
48 }
49
50 VOID KeAcquireDispatcherDatabaseLock(BOOLEAN Wait)
51 /*
52 * PURPOSE: Acquires the dispatcher database lock for the caller
53 */
54 {
55 DPRINT("KeAcquireDispatcherDatabaseLock(Wait %x)\n",Wait);
56 if (WaitSet && Owner == KeGetCurrentThread())
57 {
58 return;
59 }
60 KeAcquireSpinLock(&DispatcherDatabaseLock,&oldlvl);
61 WaitSet = Wait;
62 Owner = KeGetCurrentThread();
63 }
64
65 VOID KeReleaseDispatcherDatabaseLock(BOOLEAN Wait)
66 {
67 DPRINT("KeReleaseDispatcherDatabaseLock(Wait %x)\n",Wait);
68 assert(Wait==WaitSet);
69 if (!Wait)
70 {
71 Owner = NULL;
72 KeReleaseSpinLock(&DispatcherDatabaseLock, oldlvl);
73 }
74 }
75
76 VOID KiSideEffectsBeforeWake(DISPATCHER_HEADER* hdr,
77 PKTHREAD Thread)
78 /*
79 * FUNCTION: Perform side effects on object before a wait for a thread is
80 * satisfied
81 */
82 {
83 switch (hdr->Type)
84 {
85 case InternalSynchronizationEvent:
86 hdr->SignalState = 0;
87 break;
88
89 case InternalSemaphoreType:
90 hdr->SignalState--;
91 break;
92
93 case InternalProcessType:
94 break;
95
96 case InternalThreadType:
97 break;
98
99 case InternalNotificationEvent:
100 break;
101
102 case InternalSynchronizationTimer:
103 hdr->SignalState = FALSE;
104 break;
105
106 case InternalNotificationTimer:
107 break;
108
109 case InternalMutexType:
110 {
111 PKMUTEX Mutex;
112
113 Mutex = CONTAINING_RECORD(hdr,
114 KMUTEX,
115 Header);
116 hdr->SignalState--;
117 assert(hdr->SignalState <= 1);
118 Mutex->OwnerThread = Thread;
119 }
120 break;
121
122 default:
123 DbgPrint("(%s:%d) Dispatcher object %x has unknown type\n",
124 __FILE__,__LINE__,hdr);
125 KeBugCheck(0);
126 }
127
128 }
129
130 static BOOLEAN KiIsObjectSignalled(DISPATCHER_HEADER* hdr,
131 PKTHREAD Thread)
132 {
133 if (hdr->Type == InternalMutexType)
134 {
135 PKMUTEX Mutex;
136
137 Mutex = CONTAINING_RECORD(hdr,
138 KMUTEX,
139 Header);
140
141 assert(hdr->SignalState <= 1);
142 if ((hdr->SignalState < 1 && Mutex->OwnerThread == Thread) ||
143 hdr->SignalState == 1)
144 {
145 KiSideEffectsBeforeWake(hdr,
146 Thread);
147 return(TRUE);
148 }
149 else
150 {
151 return(FALSE);
152 }
153 }
154 if (hdr->SignalState <= 0)
155 {
156 return(FALSE);
157 }
158 else
159 {
160 KiSideEffectsBeforeWake(hdr, Thread);
161 return(TRUE);
162 }
163 }
164
165 VOID KeRemoveAllWaitsThread(PETHREAD Thread, NTSTATUS WaitStatus)
166 {
167 PKWAIT_BLOCK WaitBlock;
168 BOOLEAN WasWaiting = FALSE;
169
170 KeAcquireDispatcherDatabaseLock(FALSE);
171
172 WaitBlock = (PKWAIT_BLOCK)Thread->Tcb.WaitBlockList;
173 if (WaitBlock != NULL)
174 {
175 WasWaiting = TRUE;
176 }
177 while (WaitBlock != NULL)
178 {
179 RemoveEntryList(&WaitBlock->WaitListEntry);
180 WaitBlock = WaitBlock->NextWaitBlock;
181 }
182 Thread->Tcb.WaitBlockList = NULL;
183
184 if (WasWaiting)
185 {
186 PsUnfreezeThread(Thread, &WaitStatus);
187 }
188
189 KeReleaseDispatcherDatabaseLock(FALSE);
190 }
191
192 static BOOLEAN KeDispatcherObjectWakeAll(DISPATCHER_HEADER* hdr)
193 {
194 PKWAIT_BLOCK current;
195 PLIST_ENTRY current_entry;
196 PKWAIT_BLOCK PrevBlock;
197 NTSTATUS Status;
198
199 DPRINT("KeDispatcherObjectWakeAll(hdr %x)\n",hdr);
200
201 if (IsListEmpty(&hdr->WaitListHead))
202 {
203 return(FALSE);
204 }
205
206 while (!IsListEmpty(&(hdr->WaitListHead)))
207 {
208 current_entry = RemoveHeadList(&hdr->WaitListHead);
209 current = CONTAINING_RECORD(current_entry,
210 KWAIT_BLOCK,
211 WaitListEntry);
212 DPRINT("Waking %x\n",current->Thread);
213 if (current->WaitType == WaitAny)
214 {
215 DPRINT("WaitAny: Remove all wait blocks.\n");
216 for( PrevBlock = current->Thread->WaitBlockList; PrevBlock; PrevBlock = PrevBlock->NextWaitBlock )
217 if( PrevBlock != current )
218 RemoveEntryList( &(PrevBlock->WaitListEntry) );
219 current->Thread->WaitBlockList = 0;
220 }
221 else
222 {
223 DPRINT("WaitAll: Remove the current wait block only.\n");
224
225 PrevBlock = current->Thread->WaitBlockList;
226 if (PrevBlock == current)
227 {
228 DPRINT( "WaitAll: Current block is list head.\n" );
229 current->Thread->WaitBlockList = current->NextWaitBlock;
230 }
231 else
232 {
233 DPRINT( "WaitAll: Current block is not list head.\n" );
234 while ( PrevBlock && PrevBlock->NextWaitBlock != current)
235 {
236 PrevBlock = PrevBlock->NextWaitBlock;
237 }
238 if (PrevBlock)
239 {
240 PrevBlock->NextWaitBlock = current->NextWaitBlock;
241 }
242 }
243 }
244 KiSideEffectsBeforeWake(hdr, current->Thread);
245 Status = current->WaitKey;
246 if (current->Thread->WaitBlockList == NULL)
247 {
248 PsUnfreezeThread(CONTAINING_RECORD(current->Thread,ETHREAD,Tcb),
249 &Status);
250 }
251 }
252 return(TRUE);
253 }
254
255 static BOOLEAN KeDispatcherObjectWakeOne(DISPATCHER_HEADER* hdr)
256 {
257 PKWAIT_BLOCK current;
258 PLIST_ENTRY current_entry;
259 PKWAIT_BLOCK PrevBlock;
260 NTSTATUS Status;
261
262 DPRINT("KeDispatcherObjectWakeOn(hdr %x)\n",hdr);
263 DPRINT("hdr->WaitListHead.Flink %x hdr->WaitListHead.Blink %x\n",
264 hdr->WaitListHead.Flink,hdr->WaitListHead.Blink);
265 if (IsListEmpty(&(hdr->WaitListHead)))
266 {
267 return(FALSE);
268 }
269 current_entry = RemoveHeadList(&(hdr->WaitListHead));
270 current = CONTAINING_RECORD(current_entry,KWAIT_BLOCK,
271 WaitListEntry);
272 DPRINT("current_entry %x current %x\n",current_entry,current);
273
274 if (current->WaitType == WaitAny)
275 {
276 DPRINT("WaitAny: Remove all wait blocks.\n");
277 for( PrevBlock = current->Thread->WaitBlockList; PrevBlock; PrevBlock = PrevBlock->NextWaitBlock )
278 if( PrevBlock != current )
279 RemoveEntryList( &(PrevBlock->WaitListEntry) );
280 current->Thread->WaitBlockList = 0;
281 }
282 else
283 {
284 DPRINT("WaitAll: Remove the current wait block only.\n");
285
286 PrevBlock = current->Thread->WaitBlockList;
287 if (PrevBlock == current)
288 {
289 DPRINT( "WaitAll: Current block is list head.\n" );
290 current->Thread->WaitBlockList = current->NextWaitBlock;
291 }
292 else
293 {
294 DPRINT( "WaitAll: Current block is not list head.\n" );
295 while ( PrevBlock && PrevBlock->NextWaitBlock != current)
296 {
297 PrevBlock = PrevBlock->NextWaitBlock;
298 }
299 if (PrevBlock)
300 {
301 PrevBlock->NextWaitBlock = current->NextWaitBlock;
302 }
303 }
304 }
305
306 DPRINT("Waking %x\n",current->Thread);
307 KiSideEffectsBeforeWake(hdr, current->Thread);
308 Status = current->WaitKey;
309 PsUnfreezeThread(CONTAINING_RECORD(current->Thread, ETHREAD, Tcb),
310 &Status);
311 return(TRUE);
312 }
313
314 BOOLEAN KeDispatcherObjectWake(DISPATCHER_HEADER* hdr)
315 /*
316 * FUNCTION: Wake threads waiting on a dispatcher object
317 * NOTE: The exact semantics of waking are dependant on the type of object
318 */
319 {
320 BOOL Ret;
321
322 DPRINT("Entering KeDispatcherObjectWake(hdr %x)\n",hdr);
323 // DPRINT("hdr->WaitListHead %x hdr->WaitListHead.Flink %x\n",
324 // &hdr->WaitListHead,hdr->WaitListHead.Flink);
325 DPRINT("hdr->Type %x\n",hdr->Type);
326 switch (hdr->Type)
327 {
328 case InternalNotificationEvent:
329 return(KeDispatcherObjectWakeAll(hdr));
330
331 case InternalNotificationTimer:
332 return(KeDispatcherObjectWakeAll(hdr));
333
334 case InternalSynchronizationEvent:
335 return(KeDispatcherObjectWakeOne(hdr));
336
337
338 case InternalSynchronizationTimer:
339 return(KeDispatcherObjectWakeOne(hdr));
340
341 case InternalSemaphoreType:
342 DPRINT("hdr->SignalState %d\n", hdr->SignalState);
343 if(hdr->SignalState>0)
344 {
345 do
346 {
347 DPRINT("Waking one semaphore waiter\n");
348 Ret = KeDispatcherObjectWakeOne(hdr);
349 } while(hdr->SignalState > 0 && Ret) ;
350 return(Ret);
351 }
352 else return FALSE;
353
354 case InternalProcessType:
355 return(KeDispatcherObjectWakeAll(hdr));
356
357 case InternalThreadType:
358 return(KeDispatcherObjectWakeAll(hdr));
359
360 case InternalMutexType:
361 return(KeDispatcherObjectWakeOne(hdr));
362 }
363 DbgPrint("Dispatcher object %x has unknown type %d\n", hdr, hdr->Type);
364 KeBugCheck(0);
365 return(FALSE);
366 }
367
368
369 NTSTATUS STDCALL KeWaitForSingleObject (PVOID Object,
370 KWAIT_REASON WaitReason,
371 KPROCESSOR_MODE WaitMode,
372 BOOLEAN Alertable,
373 PLARGE_INTEGER Timeout)
374 /*
375 * FUNCTION: Puts the current thread into a wait state until the
376 * given dispatcher object is set to signalled
377 * ARGUMENTS:
378 * Object = Object to wait on
379 * WaitReason = Reason for the wait (debugging aid)
380 * WaitMode = Can be KernelMode or UserMode, if UserMode then
381 * user-mode APCs can be delivered and the thread's
382 * stack can be paged out
383 * Altertable = Specifies if the wait is a alertable
384 * Timeout = Optional timeout value
385 * RETURNS: Status
386 */
387 {
388 DISPATCHER_HEADER* hdr = (DISPATCHER_HEADER *)Object;
389 PKTHREAD CurrentThread;
390 NTSTATUS Status;
391
392 DPRINT("Entering KeWaitForSingleObject(Object %x) "
393 "PsGetCurrentThread() %x\n",Object,PsGetCurrentThread());
394
395 CurrentThread = KeGetCurrentThread();
396
397 if (Alertable && !IsListEmpty(&CurrentThread->ApcState.ApcListHead[1]))
398 {
399 DPRINT("Thread is alertable and user APCs are pending\n");
400 KiTestAlert();
401 return(STATUS_USER_APC);
402 }
403
404 if (Timeout != NULL)
405 {
406 KeAddThreadTimeout(CurrentThread,Timeout);
407 }
408
409 do
410 {
411 KeAcquireDispatcherDatabaseLock(FALSE);
412
413 DPRINT("hdr->SignalState %d\n", hdr->SignalState);
414
415 if (KiIsObjectSignalled(hdr, CurrentThread))
416 {
417 KeReleaseDispatcherDatabaseLock(FALSE);
418 if (Timeout != NULL)
419 {
420 KeCancelTimer(&KeGetCurrentThread()->Timer);
421 }
422 return(STATUS_WAIT_0);
423 }
424
425 CurrentThread->WaitStatus = STATUS_UNSUCCESSFUL;
426 /* Append wait block to the KTHREAD wait block list */
427 CurrentThread->WaitBlockList = &CurrentThread->WaitBlock[0];
428 CurrentThread->WaitBlock[0].Object = Object;
429 CurrentThread->WaitBlock[0].Thread = CurrentThread;
430 CurrentThread->WaitBlock[0].WaitKey = 0;
431 CurrentThread->WaitBlock[0].WaitType = WaitAny;
432 CurrentThread->WaitBlock[0].NextWaitBlock = NULL;
433 InsertTailList(&hdr->WaitListHead,
434 &CurrentThread->WaitBlock[0].WaitListEntry);
435 KeReleaseDispatcherDatabaseLock(FALSE);
436 DPRINT("Waiting for %x with irql %d\n", Object, KeGetCurrentIrql());
437 Status = STATUS_SUCCESS;
438 PsFreezeThread(PsGetCurrentThread(),
439 &Status,
440 (UCHAR)Alertable,
441 WaitMode);
442 if (!NT_SUCCESS(Status))
443 {
444 DPRINT1("Woke from wait with status %x\n", Status);
445 }
446 } while (Status == STATUS_KERNEL_APC);
447
448 if (Timeout != NULL)
449 {
450 KeCancelTimer(&KeGetCurrentThread()->Timer);
451 }
452
453 DPRINT("Returning from KeWaitForSingleObject()\n");
454 return(Status);
455 }
456
457
458 NTSTATUS
459 STDCALL
460 KeWaitForMultipleObjects (
461 ULONG Count,
462 PVOID Object[],
463 WAIT_TYPE WaitType,
464 KWAIT_REASON WaitReason,
465 KPROCESSOR_MODE WaitMode,
466 BOOLEAN Alertable,
467 PLARGE_INTEGER Timeout,
468 PKWAIT_BLOCK WaitBlockArray
469 )
470 {
471 DISPATCHER_HEADER* hdr;
472 PKWAIT_BLOCK blk;
473 PKTHREAD CurrentThread;
474 ULONG CountSignaled;
475 ULONG i;
476 NTSTATUS Status;
477
478 DPRINT("Entering KeWaitForMultipleObjects(Count %lu Object[] %p) "
479 "PsGetCurrentThread() %x\n",Count,Object,PsGetCurrentThread());
480
481 CountSignaled = 0;
482 CurrentThread = KeGetCurrentThread();
483
484 if (WaitBlockArray == NULL)
485 {
486 if (Count > 4)
487 {
488 DbgPrint("(%s:%d) Too many objects!\n",
489 __FILE__,__LINE__);
490 return STATUS_UNSUCCESSFUL;
491 }
492 blk = &CurrentThread->WaitBlock[0];
493 }
494 else
495 {
496 if (Count > 64)
497 {
498 DbgPrint("(%s:%d) Too many objects!\n",
499 __FILE__,__LINE__);
500 return STATUS_UNSUCCESSFUL;
501 }
502 blk = WaitBlockArray;
503 }
504 if (Timeout != NULL)
505 {
506 KeAddThreadTimeout(CurrentThread,Timeout);
507 }
508
509 do {
510 KeAcquireDispatcherDatabaseLock(FALSE);
511
512 for (i = 0; i < Count; i++)
513 {
514 hdr = (DISPATCHER_HEADER *)Object[i];
515
516 DPRINT("hdr->SignalState %d\n", hdr->SignalState);
517
518 if (KiIsObjectSignalled(hdr, CurrentThread))
519 {
520 CountSignaled++;
521
522 if (WaitType == WaitAny)
523 {
524 KeReleaseDispatcherDatabaseLock(FALSE);
525 DPRINT("One object is already signaled!\n");
526 return(STATUS_WAIT_0 + i);
527 }
528 }
529 }
530
531 if ((WaitType == WaitAll) && (CountSignaled == Count))
532 {
533 KeReleaseDispatcherDatabaseLock(FALSE);
534 DPRINT("All objects are already signaled!\n");
535 return(STATUS_WAIT_0);
536 }
537
538 /* Append wait block to the KTHREAD wait block list */
539 CurrentThread->WaitBlockList = blk;
540
541 for (i = 0; i < Count; i++)
542 {
543 hdr = (DISPATCHER_HEADER *)Object[i];
544
545 DPRINT("hdr->SignalState %d\n", hdr->SignalState);
546
547 blk->Object = Object[i];
548 blk->Thread = CurrentThread;
549 blk->WaitKey = i;
550 blk->WaitType = WaitType;
551 if (i == Count - 1)
552 blk->NextWaitBlock = NULL;
553 else
554 blk->NextWaitBlock = blk + 1;
555 DPRINT("blk %p blk->NextWaitBlock %p\n",
556 blk, blk->NextWaitBlock);
557 InsertTailList(&(hdr->WaitListHead),&(blk->WaitListEntry));
558 // DPRINT("hdr->WaitListHead.Flink %x hdr->WaitListHead.Blink %x\n",
559 // hdr->WaitListHead.Flink,hdr->WaitListHead.Blink);
560
561 blk = blk->NextWaitBlock;
562 }
563
564 KeReleaseDispatcherDatabaseLock(FALSE);
565
566 DPRINT("Waiting at %s:%d with irql %d\n", __FILE__, __LINE__,
567 KeGetCurrentIrql());
568 PsFreezeThread(PsGetCurrentThread(),
569 &Status,
570 Alertable,
571 WaitMode);
572 } while( Status == STATUS_KERNEL_APC );
573 if (Timeout != NULL)
574 KeCancelTimer(&KeGetCurrentThread()->Timer);
575 DPRINT("Returning from KeWaitForMultipleObjects()\n");
576 return(Status);
577 }
578
579 VOID KeInitializeDispatcher(VOID)
580 {
581 KeInitializeSpinLock(&DispatcherDatabaseLock);
582 }
583
584 NTSTATUS STDCALL NtWaitForMultipleObjects(IN ULONG Count,
585 IN HANDLE Object [],
586 IN CINT WaitType,
587 IN BOOLEAN Alertable,
588 IN PLARGE_INTEGER Time)
589 {
590 KWAIT_BLOCK WaitBlockArray[64]; /* FIXME: use MAXIMUM_WAIT_OBJECTS instead */
591 PVOID ObjectPtrArray[64]; /* FIXME: use MAXIMUM_WAIT_OBJECTS instead */
592 NTSTATUS Status;
593 ULONG i, j;
594
595 DPRINT("NtWaitForMultipleObjects(Count %lu Object[] %x, Alertable %d, Time %x)\n",
596 Count,Object,Alertable,Time);
597
598 if (Count > 64) /* FIXME: use MAXIMUM_WAIT_OBJECTS instead */
599 return STATUS_UNSUCCESSFUL;
600
601 /* reference all objects */
602 for (i = 0; i < Count; i++)
603 {
604 Status = ObReferenceObjectByHandle(Object[i],
605 SYNCHRONIZE,
606 NULL,
607 UserMode,
608 &ObjectPtrArray[i],
609 NULL);
610 if (Status != STATUS_SUCCESS)
611 {
612 /* dereference all referenced objects */
613 for (j = 0; j < i; i++)
614 {
615 ObDereferenceObject(ObjectPtrArray[j]);
616 }
617
618 return(Status);
619 }
620 }
621
622 Status = KeWaitForMultipleObjects(Count,
623 ObjectPtrArray,
624 WaitType,
625 UserRequest,
626 UserMode,
627 Alertable,
628 Time,
629 WaitBlockArray);
630
631 /* dereference all objects */
632 for (i = 0; i < Count; i++)
633 {
634 ObDereferenceObject(ObjectPtrArray[i]);
635 }
636
637 return(Status);
638 }
639
640
641 NTSTATUS STDCALL NtWaitForSingleObject (IN HANDLE Object,
642 IN BOOLEAN Alertable,
643 IN PLARGE_INTEGER Time)
644 {
645 PVOID ObjectPtr;
646 NTSTATUS Status;
647
648 DPRINT("NtWaitForSingleObject(Object %x, Alertable %d, Time %x)\n",
649 Object,Alertable,Time);
650
651 Status = ObReferenceObjectByHandle(Object,
652 SYNCHRONIZE,
653 NULL,
654 UserMode,
655 &ObjectPtr,
656 NULL);
657 if (!NT_SUCCESS(Status))
658 {
659 return(Status);
660 }
661
662 DPRINT("ObjectPtr %x\n", ObjectPtr);
663
664 Status = KeWaitForSingleObject(ObjectPtr,
665 UserMode,
666 UserMode,
667 Alertable,
668 Time);
669
670 DPRINT("Returned from wait (status is %x) ObjectPtr %x(%d)\n",
671 Status, ObjectPtr, ObGetReferenceCount(ObjectPtr));
672
673 ObDereferenceObject(ObjectPtr);
674
675 return(Status);
676 }
677
678
679 NTSTATUS STDCALL
680 NtSignalAndWaitForSingleObject(IN HANDLE SignalObject,
681 IN HANDLE WaitObject,
682 IN BOOLEAN Alertable,
683 IN PLARGE_INTEGER Time)
684 {
685 KPROCESSOR_MODE ProcessorMode;
686 DISPATCHER_HEADER* hdr;
687 PVOID SignalObj;
688 PVOID WaitObj;
689 NTSTATUS Status;
690
691 ProcessorMode = CURRENT_KPCR->CurrentThread->PreviousMode;
692 Status = ObReferenceObjectByHandle(SignalObject,
693 0,
694 NULL,
695 ProcessorMode,
696 &SignalObj,
697 NULL);
698 if (!NT_SUCCESS(Status))
699 {
700 return Status;
701 }
702
703 Status = ObReferenceObjectByHandle(WaitObject,
704 SYNCHRONIZE,
705 NULL,
706 ProcessorMode,
707 &WaitObj,
708 NULL);
709 if (!NT_SUCCESS(Status))
710 {
711 ObDereferenceObject(SignalObj);
712 return Status;
713 }
714
715 hdr = (DISPATCHER_HEADER *)SignalObj;
716 switch (hdr->Type)
717 {
718 case InternalNotificationEvent:
719 case InternalSynchronizationEvent:
720 KeSetEvent(SignalObj,
721 EVENT_INCREMENT,
722 TRUE);
723 break;
724
725 case InternalMutexType:
726 KeReleaseMutex(SignalObj,
727 TRUE);
728 break;
729
730 case InternalSemaphoreType:
731 KeReleaseSemaphore(SignalObj,
732 SEMAPHORE_INCREMENT,
733 1,
734 TRUE);
735 break;
736
737 default:
738 ObDereferenceObject(SignalObj);
739 ObDereferenceObject(WaitObj);
740 return STATUS_OBJECT_TYPE_MISMATCH;
741 }
742
743 Status = KeWaitForSingleObject(WaitObj,
744 UserRequest,
745 ProcessorMode,
746 Alertable,
747 Time);
748
749 ObDereferenceObject(SignalObj);
750 ObDereferenceObject(WaitObj);
751
752 return Status;
753 }