@implemented and @unimplemented comments for ntoskrnl/ke/*.c
[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 #include <ntos/ntdef.h>
25
26 #define NDEBUG
27 #include <internal/debug.h>
28
29 /* GLOBALS ******************************************************************/
30
31 static KSPIN_LOCK DispatcherDatabaseLock;
32 static BOOLEAN WaitSet = FALSE;
33 static KIRQL oldlvl = PASSIVE_LEVEL;
34 static PKTHREAD Owner = NULL;
35
36 #define KeDispatcherObjectWakeOne(hdr) KeDispatcherObjectWakeOneOrAll(hdr, FALSE)
37 #define KeDispatcherObjectWakeAll(hdr) KeDispatcherObjectWakeOneOrAll(hdr, TRUE)
38
39 /* FUNCTIONS *****************************************************************/
40
41 VOID KeInitializeDispatcherHeader(DISPATCHER_HEADER* Header,
42 ULONG Type,
43 ULONG Size,
44 ULONG SignalState)
45 {
46 Header->Type = Type;
47 Header->Absolute = 0;
48 Header->Inserted = 0;
49 Header->Size = Size;
50 Header->SignalState = SignalState;
51 InitializeListHead(&(Header->WaitListHead));
52 }
53
54 VOID KeAcquireDispatcherDatabaseLock(BOOLEAN Wait)
55 /*
56 * PURPOSE: Acquires the dispatcher database lock for the caller
57 */
58 {
59 DPRINT("KeAcquireDispatcherDatabaseLock(Wait %x)\n",Wait);
60 if (WaitSet && Owner == KeGetCurrentThread())
61 {
62 return;
63 }
64 KeAcquireSpinLock(&DispatcherDatabaseLock, &oldlvl);
65 WaitSet = Wait;
66 Owner = KeGetCurrentThread();
67 }
68
69 VOID KeReleaseDispatcherDatabaseLockAtDpcLevel(BOOLEAN Wait)
70 {
71 DPRINT("KeReleaseDispatcherDatabaseLockAtDpcLevel(Wait %x)\n", Wait);
72 assert(Wait == WaitSet);
73 if (!Wait)
74 {
75 Owner = NULL;
76 KeReleaseSpinLockFromDpcLevel(&DispatcherDatabaseLock);
77 }
78 }
79
80 VOID KeReleaseDispatcherDatabaseLock(BOOLEAN Wait)
81 {
82 DPRINT("KeReleaseDispatcherDatabaseLock(Wait %x)\n",Wait);
83 assert(Wait==WaitSet);
84 if (!Wait)
85 {
86 Owner = NULL;
87 KeReleaseSpinLock(&DispatcherDatabaseLock, oldlvl);
88 }
89 }
90
91 static BOOLEAN
92 KiSideEffectsBeforeWake(DISPATCHER_HEADER * hdr,
93 PKTHREAD Thread)
94 /*
95 * FUNCTION: Perform side effects on object before a wait for a thread is
96 * satisfied
97 */
98 {
99 BOOLEAN Abandoned = FALSE;
100
101 switch (hdr->Type)
102 {
103 case InternalSynchronizationEvent:
104 hdr->SignalState = 0;
105 break;
106
107 case InternalQueueType:
108 case InternalSemaphoreType:
109 hdr->SignalState--;
110 break;
111
112 case InternalProcessType:
113 break;
114
115 case InternalThreadType:
116 break;
117
118 case InternalNotificationEvent:
119 break;
120
121 case InternalSynchronizationTimer:
122 hdr->SignalState = FALSE;
123 break;
124
125 case InternalNotificationTimer:
126 break;
127
128 case InternalMutexType:
129 {
130 PKMUTEX Mutex;
131
132 Mutex = CONTAINING_RECORD(hdr, KMUTEX, Header);
133 hdr->SignalState--;
134 assert(hdr->SignalState <= 1);
135 if (hdr->SignalState == 0)
136 {
137 if (Thread == NULL)
138 {
139 DPRINT("Thread == NULL!\n");
140 KeBugCheck(0);
141 }
142 Abandoned = Mutex->Abandoned;
143 if (Thread != NULL)
144 InsertTailList(&Thread->MutantListHead, &Mutex->MutantListEntry);
145 Mutex->OwnerThread = Thread;
146 Mutex->Abandoned = FALSE;
147 }
148 }
149 break;
150
151 default:
152 DbgPrint("(%s:%d) Dispatcher object %x has unknown type\n", __FILE__, __LINE__, hdr);
153 KeBugCheck(0);
154 }
155
156 return Abandoned;
157 }
158
159 static BOOLEAN
160 KiIsObjectSignalled(DISPATCHER_HEADER * hdr,
161 PKTHREAD Thread)
162 {
163 if (hdr->Type == InternalMutexType)
164 {
165 PKMUTEX Mutex;
166
167 Mutex = CONTAINING_RECORD(hdr, KMUTEX, Header);
168
169 assert(hdr->SignalState <= 1);
170
171 if ((hdr->SignalState < 1 && Mutex->OwnerThread == Thread) || hdr->SignalState == 1)
172 {
173 return (TRUE);
174 }
175 else
176 {
177 return (FALSE);
178 }
179 }
180
181 if (hdr->SignalState <= 0)
182 {
183 return (FALSE);
184 }
185 else
186 {
187 return (TRUE);
188 }
189 }
190
191 VOID KeRemoveAllWaitsThread(PETHREAD Thread, NTSTATUS WaitStatus)
192 {
193 PKWAIT_BLOCK WaitBlock;
194 BOOLEAN WasWaiting = FALSE;
195
196 KeAcquireDispatcherDatabaseLock(FALSE);
197
198 WaitBlock = (PKWAIT_BLOCK)Thread->Tcb.WaitBlockList;
199 if (WaitBlock != NULL)
200 {
201 WasWaiting = TRUE;
202 }
203 while (WaitBlock != NULL)
204 {
205 RemoveEntryList(&WaitBlock->WaitListEntry);
206 WaitBlock = WaitBlock->NextWaitBlock;
207 }
208 Thread->Tcb.WaitBlockList = NULL;
209
210 if (WasWaiting)
211 {
212 PsUnblockThread(Thread, &WaitStatus);
213 }
214
215 KeReleaseDispatcherDatabaseLock(FALSE);
216 }
217
218 static BOOLEAN
219 KeDispatcherObjectWakeOneOrAll(DISPATCHER_HEADER * hdr,
220 BOOLEAN WakeAll)
221 {
222 PKWAIT_BLOCK Waiter;
223 PKWAIT_BLOCK WaiterHead;
224 PLIST_ENTRY EnumEntry;
225 NTSTATUS Status;
226 BOOLEAN Abandoned;
227 BOOLEAN AllSignaled;
228 BOOLEAN WakedAny = FALSE;
229
230 DPRINT("KeDispatcherObjectWakeOnOrAll(hdr %x)\n", hdr);
231 DPRINT ("hdr->WaitListHead.Flink %x hdr->WaitListHead.Blink %x\n",
232 hdr->WaitListHead.Flink, hdr->WaitListHead.Blink);
233
234 if (IsListEmpty(&hdr->WaitListHead))
235 {
236 return (FALSE);
237 }
238
239 //enum waiters for this dispatcher object
240 EnumEntry = hdr->WaitListHead.Flink;
241 while (EnumEntry != &hdr->WaitListHead && (WakeAll || !WakedAny))
242 {
243 WaiterHead = CONTAINING_RECORD(EnumEntry, KWAIT_BLOCK, WaitListEntry);
244 DPRINT("current_entry %x current %x\n", EnumEntry, WaiterHead);
245 EnumEntry = EnumEntry->Flink;
246 assert(WaiterHead->Thread->WaitBlockList != NULL);
247
248 Abandoned = FALSE;
249
250 if (WaiterHead->WaitType == WaitAny)
251 {
252 DPRINT("WaitAny: Remove all wait blocks.\n");
253 for (Waiter = WaiterHead->Thread->WaitBlockList; Waiter; Waiter = Waiter->NextWaitBlock)
254 {
255 RemoveEntryList(&Waiter->WaitListEntry);
256 }
257
258 WaiterHead->Thread->WaitBlockList = NULL;
259
260 /*
261 * If a WakeAll KiSideEffectsBeforeWake(hdr,.. will be called several times,
262 * but thats ok since WakeAll objects has no sideeffects.
263 */
264 Abandoned = KiSideEffectsBeforeWake(hdr, WaiterHead->Thread) ? TRUE : Abandoned;
265 }
266 else
267 {
268 DPRINT("WaitAll: All WaitAll objects must be signaled.\n");
269
270 AllSignaled = TRUE;
271
272 //all WaitAll obj. for thread need to be signaled to satisfy a wake
273 for (Waiter = WaiterHead->Thread->WaitBlockList; Waiter; Waiter = Waiter->NextWaitBlock)
274 {
275 //no need to check hdr since it has to be signaled
276 if (Waiter->WaitType == WaitAll && Waiter->Object != hdr)
277 {
278 if (!KiIsObjectSignalled(Waiter->Object, Waiter->Thread))
279 {
280 AllSignaled = FALSE;
281 break;
282 }
283 }
284 }
285
286 if (AllSignaled)
287 {
288 for (Waiter = WaiterHead->Thread->WaitBlockList; Waiter; Waiter = Waiter->NextWaitBlock)
289 {
290 RemoveEntryList(&Waiter->WaitListEntry);
291
292 if (Waiter->WaitType == WaitAll)
293 {
294 Abandoned = KiSideEffectsBeforeWake(Waiter->Object, Waiter->Thread)
295 ? TRUE : Abandoned;
296 }
297
298 //no WaitAny objects can possibly be signaled since we are here
299 assert(!(Waiter->WaitType == WaitAny
300 && KiIsObjectSignalled(Waiter->Object, Waiter->Thread)));
301 }
302
303 WaiterHead->Thread->WaitBlockList = NULL;
304 }
305 }
306
307 if (WaiterHead->Thread->WaitBlockList == NULL)
308 {
309 Status = WaiterHead->WaitKey;
310 if (Abandoned)
311 {
312 DPRINT("Abandoned mutex among objects");
313 Status += STATUS_ABANDONED_WAIT_0;
314 }
315
316 WakedAny = TRUE;
317 DPRINT("Waking %x status = %x\n", WaiterHead->Thread, Status);
318 PsUnblockThread(CONTAINING_RECORD(WaiterHead->Thread, ETHREAD, Tcb), &Status);
319 }
320 }
321
322 return WakedAny;
323 }
324
325
326 BOOLEAN KeDispatcherObjectWake(DISPATCHER_HEADER* hdr)
327 /*
328 * FUNCTION: Wake threads waiting on a dispatcher object
329 * NOTE: The exact semantics of waking are dependant on the type of object
330 */
331 {
332 BOOL Ret;
333
334 DPRINT("Entering KeDispatcherObjectWake(hdr %x)\n",hdr);
335 // DPRINT("hdr->WaitListHead %x hdr->WaitListHead.Flink %x\n",
336 // &hdr->WaitListHead,hdr->WaitListHead.Flink);
337 DPRINT("hdr->Type %x\n",hdr->Type);
338 switch (hdr->Type)
339 {
340 case InternalNotificationEvent:
341 return(KeDispatcherObjectWakeAll(hdr));
342
343 case InternalNotificationTimer:
344 return(KeDispatcherObjectWakeAll(hdr));
345
346 case InternalSynchronizationEvent:
347 return(KeDispatcherObjectWakeOne(hdr));
348
349 case InternalSynchronizationTimer:
350 return(KeDispatcherObjectWakeOne(hdr));
351
352 case InternalQueueType:
353 case InternalSemaphoreType:
354 DPRINT("hdr->SignalState %d\n", hdr->SignalState);
355 if(hdr->SignalState>0)
356 {
357 do
358 {
359 DPRINT("Waking one semaphore waiter\n");
360 Ret = KeDispatcherObjectWakeOne(hdr);
361 } while(hdr->SignalState > 0 && Ret) ;
362 return(Ret);
363 }
364 else return FALSE;
365
366 case InternalProcessType:
367 return(KeDispatcherObjectWakeAll(hdr));
368
369 case InternalThreadType:
370 return(KeDispatcherObjectWakeAll(hdr));
371
372 case InternalMutexType:
373 return(KeDispatcherObjectWakeOne(hdr));
374 }
375 DbgPrint("Dispatcher object %x has unknown type %d\n", hdr, hdr->Type);
376 KeBugCheck(0);
377 return(FALSE);
378 }
379
380
381 /*
382 * @implemented
383 */
384 NTSTATUS STDCALL
385 KeWaitForSingleObject(PVOID Object,
386 KWAIT_REASON WaitReason,
387 KPROCESSOR_MODE WaitMode,
388 BOOLEAN Alertable,
389 PLARGE_INTEGER Timeout)
390 /*
391 * FUNCTION: Puts the current thread into a wait state until the
392 * given dispatcher object is set to signalled
393 * ARGUMENTS:
394 * Object = Object to wait on
395 * WaitReason = Reason for the wait (debugging aid)
396 * WaitMode = Can be KernelMode or UserMode, if UserMode then
397 * user-mode APCs can be delivered and the thread's
398 * stack can be paged out
399 * Altertable = Specifies if the wait is a alertable
400 * Timeout = Optional timeout value
401 * RETURNS: Status
402 */
403 {
404 return KeWaitForMultipleObjects(1,
405 &Object,
406 WaitAny,
407 WaitReason,
408 WaitMode,
409 Alertable,
410 Timeout,
411 NULL);
412 }
413
414
415 inline
416 PVOID
417 KiGetWaitableObjectFromObject(PVOID Object)
418 {
419 //special case when waiting on file objects
420 if ( ((PDISPATCHER_HEADER)Object)->Type == InternalFileType)
421 {
422 return &((PFILE_OBJECT)Object)->Event;
423 }
424
425 return Object;
426 }
427
428
429 /*
430 * @implemented
431 */
432 NTSTATUS STDCALL
433 KeWaitForMultipleObjects(ULONG Count,
434 PVOID Object[],
435 WAIT_TYPE WaitType,
436 KWAIT_REASON WaitReason,
437 KPROCESSOR_MODE WaitMode,
438 BOOLEAN Alertable,
439 PLARGE_INTEGER Timeout,
440 PKWAIT_BLOCK WaitBlockArray)
441 {
442 DISPATCHER_HEADER *hdr;
443 PKWAIT_BLOCK blk;
444 PKTHREAD CurrentThread;
445 ULONG CountSignaled;
446 ULONG i;
447 NTSTATUS Status;
448 KIRQL WaitIrql;
449 BOOLEAN Abandoned;
450
451 DPRINT("Entering KeWaitForMultipleObjects(Count %lu Object[] %p) "
452 "PsGetCurrentThread() %x\n", Count, Object, PsGetCurrentThread());
453
454 CurrentThread = KeGetCurrentThread();
455 WaitIrql = KeGetCurrentIrql();
456
457 /*
458 * Work out where we are going to put the wait blocks
459 */
460 if (WaitBlockArray == NULL)
461 {
462 if (Count > THREAD_WAIT_OBJECTS)
463 {
464 DPRINT("(%s:%d) Too many objects!\n", __FILE__, __LINE__);
465 return (STATUS_UNSUCCESSFUL);
466 }
467 WaitBlockArray = &CurrentThread->WaitBlock[0];
468 }
469 else
470 {
471 if (Count > EX_MAXIMUM_WAIT_OBJECTS)
472 {
473 DPRINT("(%s:%d) Too many objects!\n", __FILE__, __LINE__);
474 return (STATUS_UNSUCCESSFUL);
475 }
476 }
477
478 /*
479 * Set up the timeout if required
480 */
481 if (Timeout != NULL && Timeout->QuadPart != 0)
482 {
483 KeInitializeTimer(&CurrentThread->Timer);
484 KeSetTimer(&CurrentThread->Timer, *Timeout, NULL);
485 }
486
487 do
488 {
489 KeAcquireDispatcherDatabaseLock(FALSE);
490
491 /*
492 * If we are going to wait alertably and a user apc is pending
493 * then return
494 */
495 if (Alertable && KiTestAlert())
496 {
497 KeReleaseDispatcherDatabaseLock(FALSE);
498 return (STATUS_USER_APC);
499 }
500
501 /*
502 * Check if the wait is (already) satisfied
503 */
504 CountSignaled = 0;
505 Abandoned = FALSE;
506 for (i = 0; i < Count; i++)
507 {
508 hdr = (DISPATCHER_HEADER *) KiGetWaitableObjectFromObject(Object[i]);
509
510 if (KiIsObjectSignalled(hdr, CurrentThread))
511 {
512 CountSignaled++;
513
514 if (WaitType == WaitAny)
515 {
516 Abandoned = KiSideEffectsBeforeWake(hdr, CurrentThread) ? TRUE : Abandoned;
517
518 if (Timeout != NULL && Timeout->QuadPart != 0)
519 {
520 KeCancelTimer(&CurrentThread->Timer);
521 }
522
523 KeReleaseDispatcherDatabaseLock(FALSE);
524
525 DPRINT("One object is (already) signaled!\n");
526 if (Abandoned == TRUE)
527 {
528 return (STATUS_ABANDONED_WAIT_0 + i);
529 }
530
531 return (STATUS_WAIT_0 + i);
532 }
533 }
534 }
535
536 Abandoned = FALSE;
537 if ((WaitType == WaitAll) && (CountSignaled == Count))
538 {
539 for (i = 0; i < Count; i++)
540 {
541 hdr = (DISPATCHER_HEADER *) KiGetWaitableObjectFromObject(Object[i]);
542 Abandoned = KiSideEffectsBeforeWake(hdr, CurrentThread) ? TRUE : Abandoned;
543 }
544
545 if (Timeout != NULL && Timeout->QuadPart != 0)
546 {
547 KeCancelTimer(&CurrentThread->Timer);
548 }
549
550 KeReleaseDispatcherDatabaseLock(FALSE);
551 DPRINT("All objects are (already) signaled!\n");
552
553 if (Abandoned == TRUE)
554 {
555 return (STATUS_ABANDONED_WAIT_0);
556 }
557
558 return (STATUS_WAIT_0);
559 }
560
561 //zero timeout is used for testing if the object(s) can be immediately acquired
562 if (Timeout != NULL && Timeout->QuadPart == 0)
563 {
564 KeReleaseDispatcherDatabaseLock(FALSE);
565 return STATUS_TIMEOUT;
566 }
567
568 /*
569 * Check if we have already timed out
570 */
571 if (Timeout != NULL && KiIsObjectSignalled(&CurrentThread->Timer.Header, CurrentThread))
572 {
573 KiSideEffectsBeforeWake(&CurrentThread->Timer.Header, CurrentThread);
574 KeCancelTimer(&CurrentThread->Timer);
575 KeReleaseDispatcherDatabaseLock(FALSE);
576 return (STATUS_TIMEOUT);
577 }
578
579 /* Append wait block to the KTHREAD wait block list */
580 CurrentThread->WaitBlockList = blk = WaitBlockArray;
581
582 /*
583 * Set up the wait
584 */
585 CurrentThread->WaitStatus = STATUS_UNSUCCESSFUL;
586
587 for (i = 0; i < Count; i++)
588 {
589 hdr = (DISPATCHER_HEADER *) KiGetWaitableObjectFromObject(Object[i]);
590
591 blk->Object = KiGetWaitableObjectFromObject(Object[i]);
592 blk->Thread = CurrentThread;
593 blk->WaitKey = STATUS_WAIT_0 + i;
594 blk->WaitType = WaitType;
595
596 if (i == (Count - 1))
597 {
598 if (Timeout != NULL)
599 {
600 blk->NextWaitBlock = &CurrentThread->WaitBlock[3];
601 }
602 else
603 {
604 blk->NextWaitBlock = NULL;
605 }
606 }
607 else
608 {
609 blk->NextWaitBlock = blk + 1;
610 }
611
612 /*
613 * add wait block to disp. obj. wait list
614 * Use FIFO for all waits except for queues which use LIFO
615 */
616 if (WaitReason == WrQueue)
617 {
618 InsertHeadList(&hdr->WaitListHead, &blk->WaitListEntry);
619 }
620 else
621 {
622 InsertTailList(&hdr->WaitListHead, &blk->WaitListEntry);
623 }
624
625 blk = blk->NextWaitBlock;
626 }
627
628 if (Timeout != NULL)
629 {
630 CurrentThread->WaitBlock[3].Object = (PVOID) & CurrentThread->Timer;
631 CurrentThread->WaitBlock[3].Thread = CurrentThread;
632 CurrentThread->WaitBlock[3].WaitKey = STATUS_TIMEOUT;
633 CurrentThread->WaitBlock[3].WaitType = WaitAny;
634 CurrentThread->WaitBlock[3].NextWaitBlock = NULL;
635
636 InsertTailList(&CurrentThread->Timer.Header.WaitListHead,
637 &CurrentThread->WaitBlock[3].WaitListEntry);
638 }
639
640 //io completion
641 if (CurrentThread->Queue)
642 {
643 CurrentThread->Queue->CurrentCount--;
644 if (WaitReason != WrQueue && CurrentThread->Queue->CurrentCount < CurrentThread->Queue->MaximumCount &&
645 !IsListEmpty(&CurrentThread->Queue->EntryListHead))
646 {
647 KeDispatcherObjectWake(&CurrentThread->Queue->Header);
648 }
649 }
650
651 PsBlockThread(&Status, Alertable, WaitMode, TRUE, WaitIrql, WaitReason);
652
653 //io completion
654 if (CurrentThread->Queue)
655 {
656 CurrentThread->Queue->CurrentCount++;
657 }
658
659
660 }
661 while (Status == STATUS_KERNEL_APC);
662
663 if (Timeout != NULL)
664 {
665 KeCancelTimer(&CurrentThread->Timer);
666 }
667
668 DPRINT("Returning from KeWaitForMultipleObjects()\n");
669 return (Status);
670 }
671
672 VOID KeInitializeDispatcher(VOID)
673 {
674 KeInitializeSpinLock(&DispatcherDatabaseLock);
675 }
676
677 /*
678 * @implemented
679 */
680 NTSTATUS STDCALL
681 NtWaitForMultipleObjects(IN ULONG Count,
682 IN HANDLE Object [],
683 IN WAIT_TYPE WaitType,
684 IN BOOLEAN Alertable,
685 IN PLARGE_INTEGER Time)
686 {
687 KWAIT_BLOCK WaitBlockArray[EX_MAXIMUM_WAIT_OBJECTS];
688 PVOID ObjectPtrArray[EX_MAXIMUM_WAIT_OBJECTS];
689 NTSTATUS Status;
690 ULONG i, j;
691 KPROCESSOR_MODE WaitMode;
692
693 DPRINT("NtWaitForMultipleObjects(Count %lu Object[] %x, Alertable %d, "
694 "Time %x)\n", Count,Object,Alertable,Time);
695
696 if (Count > EX_MAXIMUM_WAIT_OBJECTS)
697 return STATUS_UNSUCCESSFUL;
698
699 WaitMode = ExGetPreviousMode();
700
701 /* reference all objects */
702 for (i = 0; i < Count; i++)
703 {
704 Status = ObReferenceObjectByHandle(Object[i],
705 SYNCHRONIZE,
706 NULL,
707 WaitMode,
708 &ObjectPtrArray[i],
709 NULL);
710 if (Status != STATUS_SUCCESS)
711 {
712 /* dereference all referenced objects */
713 for (j = 0; j < i; j++)
714 {
715 ObDereferenceObject(ObjectPtrArray[j]);
716 }
717
718 return(Status);
719 }
720 }
721
722 Status = KeWaitForMultipleObjects(Count,
723 ObjectPtrArray,
724 WaitType,
725 UserRequest,
726 WaitMode,
727 Alertable,
728 Time,
729 WaitBlockArray);
730
731 /* dereference all objects */
732 for (i = 0; i < Count; i++)
733 {
734 ObDereferenceObject(ObjectPtrArray[i]);
735 }
736
737 return(Status);
738 }
739
740
741 /*
742 * @implemented
743 */
744 NTSTATUS STDCALL
745 NtWaitForSingleObject(IN HANDLE Object,
746 IN BOOLEAN Alertable,
747 IN PLARGE_INTEGER Time)
748 {
749 PVOID ObjectPtr;
750 NTSTATUS Status;
751 KPROCESSOR_MODE WaitMode;
752
753 DPRINT("NtWaitForSingleObject(Object %x, Alertable %d, Time %x)\n",
754 Object,Alertable,Time);
755
756 WaitMode = ExGetPreviousMode();
757
758 Status = ObReferenceObjectByHandle(Object,
759 SYNCHRONIZE,
760 NULL,
761 WaitMode,
762 &ObjectPtr,
763 NULL);
764 if (!NT_SUCCESS(Status))
765 {
766 return(Status);
767 }
768
769 Status = KeWaitForSingleObject(ObjectPtr,
770 UserRequest,
771 WaitMode,
772 Alertable,
773 Time);
774
775 ObDereferenceObject(ObjectPtr);
776
777 return(Status);
778 }
779
780
781 /*
782 * @implemented
783 */
784 NTSTATUS STDCALL
785 NtSignalAndWaitForSingleObject(IN HANDLE SignalObject,
786 IN HANDLE WaitObject,
787 IN BOOLEAN Alertable,
788 IN PLARGE_INTEGER Time)
789 {
790 KPROCESSOR_MODE WaitMode;
791 DISPATCHER_HEADER* hdr;
792 PVOID SignalObj;
793 PVOID WaitObj;
794 NTSTATUS Status;
795
796 WaitMode = ExGetPreviousMode();
797 Status = ObReferenceObjectByHandle(SignalObject,
798 0,
799 NULL,
800 WaitMode,
801 &SignalObj,
802 NULL);
803 if (!NT_SUCCESS(Status))
804 {
805 return Status;
806 }
807
808 Status = ObReferenceObjectByHandle(WaitObject,
809 SYNCHRONIZE,
810 NULL,
811 WaitMode,
812 &WaitObj,
813 NULL);
814 if (!NT_SUCCESS(Status))
815 {
816 ObDereferenceObject(SignalObj);
817 return Status;
818 }
819
820 hdr = (DISPATCHER_HEADER *)SignalObj;
821 switch (hdr->Type)
822 {
823 case InternalNotificationEvent:
824 case InternalSynchronizationEvent:
825 KeSetEvent(SignalObj,
826 EVENT_INCREMENT,
827 TRUE);
828 break;
829
830 case InternalMutexType:
831 KeReleaseMutex(SignalObj,
832 TRUE);
833 break;
834
835 case InternalSemaphoreType:
836 KeReleaseSemaphore(SignalObj,
837 SEMAPHORE_INCREMENT,
838 1,
839 TRUE);
840 break;
841
842 default:
843 ObDereferenceObject(SignalObj);
844 ObDereferenceObject(WaitObj);
845 return STATUS_OBJECT_TYPE_MISMATCH;
846 }
847
848 Status = KeWaitForSingleObject(WaitObj,
849 UserRequest,
850 WaitMode,
851 Alertable,
852 Time);
853
854 ObDereferenceObject(SignalObj);
855 ObDereferenceObject(WaitObj);
856
857 return Status;
858 }