xref: /reactos/dll/win32/kernel32/client/synch.c (revision c2c66aff)
1 /*
2  * PROJECT:         ReactOS Win32 Base API
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            dll/win32/kernel32/client/synch.c
5  * PURPOSE:         Wrappers for the NT Wait Implementation
6  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
7  */
8 
9 /* INCLUDES *****************************************************************/
10 #include <k32.h>
11 
12 #define NDEBUG
13 #include <debug.h>
14 
15 #undef InterlockedIncrement
16 #undef InterlockedDecrement
17 #undef InterlockedExchange
18 #undef InterlockedExchangeAdd
19 #undef InterlockedCompareExchange
20 
21 /* FUNCTIONS *****************************************************************/
22 
23 /*
24  * @implemented
25  */
26 LONG
27 WINAPI
28 InterlockedIncrement(IN OUT LONG volatile *lpAddend)
29 {
30     return _InterlockedIncrement(lpAddend);
31 }
32 
33 /*
34  * @implemented
35  */
36 LONG
37 WINAPI
38 InterlockedDecrement(IN OUT LONG volatile *lpAddend)
39 {
40     return _InterlockedDecrement(lpAddend);
41 }
42 
43 /*
44  * @implemented
45  */
46 LONG
47 WINAPI
48 InterlockedExchange(IN OUT LONG volatile *Target,
49                     IN LONG Value)
50 {
51     return _InterlockedExchange(Target, Value);
52 }
53 
54 /*
55  * @implemented
56  */
57 LONG
58 WINAPI
59 InterlockedExchangeAdd(IN OUT LONG volatile *Addend,
60                        IN LONG Value)
61 {
62     return _InterlockedExchangeAdd(Addend, Value);
63 }
64 
65 /*
66  * @implemented
67  */
68 LONG
69 WINAPI
70 InterlockedCompareExchange(IN OUT LONG volatile *Destination,
71                            IN LONG Exchange,
72                            IN LONG Comperand)
73 {
74     return _InterlockedCompareExchange(Destination, Exchange, Comperand);
75 }
76 
77 /*
78  * @implemented
79  */
80 DWORD
81 WINAPI
82 WaitForSingleObject(IN HANDLE hHandle,
83                     IN DWORD dwMilliseconds)
84 {
85     /* Call the extended API */
86     return WaitForSingleObjectEx(hHandle, dwMilliseconds, FALSE);
87 }
88 
89 /*
90  * @implemented
91  */
92 DWORD
93 WINAPI
94 WaitForSingleObjectEx(IN HANDLE hHandle,
95                       IN DWORD dwMilliseconds,
96                       IN BOOL bAlertable)
97 {
98     PLARGE_INTEGER TimePtr;
99     LARGE_INTEGER Time;
100     NTSTATUS Status;
101     RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActCtx;
102 
103     /* APCs must execute with the default activation context */
104     if (bAlertable)
105     {
106         /* Setup the frame */
107         RtlZeroMemory(&ActCtx, sizeof(ActCtx));
108         ActCtx.Size = sizeof(ActCtx);
109         ActCtx.Format = RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER;
110         RtlActivateActivationContextUnsafeFast(&ActCtx, NULL);
111     }
112 
113     /* Get real handle */
114     hHandle = TranslateStdHandle(hHandle);
115 
116     /* Check for console handle */
117     if ((IsConsoleHandle(hHandle)) && (VerifyConsoleIoHandle(hHandle)))
118     {
119         /* Get the real wait handle */
120         hHandle = GetConsoleInputWaitHandle();
121     }
122 
123     /* Convert the timeout */
124     TimePtr = BaseFormatTimeOut(&Time, dwMilliseconds);
125 
126     /* Start wait loop */
127     do
128     {
129         /* Do the wait */
130         Status = NtWaitForSingleObject(hHandle, (BOOLEAN)bAlertable, TimePtr);
131         if (!NT_SUCCESS(Status))
132         {
133             /* The wait failed */
134             BaseSetLastNTError(Status);
135             Status = WAIT_FAILED;
136         }
137     } while ((Status == STATUS_ALERTED) && (bAlertable));
138 
139     /* Cleanup the activation context */
140     if (bAlertable) RtlDeactivateActivationContextUnsafeFast(&ActCtx);
141 
142     /* Return wait status */
143     return Status;
144 }
145 
146 /*
147  * @implemented
148  */
149 DWORD
150 WINAPI
151 WaitForMultipleObjects(IN DWORD nCount,
152                        IN CONST HANDLE *lpHandles,
153                        IN BOOL bWaitAll,
154                        IN DWORD dwMilliseconds)
155 {
156     /* Call the extended API */
157     return WaitForMultipleObjectsEx(nCount,
158                                     lpHandles,
159                                     bWaitAll,
160                                     dwMilliseconds,
161                                     FALSE);
162 }
163 
164 /*
165  * @implemented
166  */
167 DWORD
168 WINAPI
169 WaitForMultipleObjectsEx(IN DWORD nCount,
170                          IN CONST HANDLE *lpHandles,
171                          IN BOOL bWaitAll,
172                          IN DWORD dwMilliseconds,
173                          IN BOOL bAlertable)
174 {
175     PLARGE_INTEGER TimePtr;
176     LARGE_INTEGER Time;
177     PHANDLE HandleBuffer;
178     HANDLE Handle[8];
179     DWORD i;
180     NTSTATUS Status;
181     RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActCtx;
182 
183     /* APCs must execute with the default activation context */
184     if (bAlertable)
185     {
186         /* Setup the frame */
187         RtlZeroMemory(&ActCtx, sizeof(ActCtx));
188         ActCtx.Size = sizeof(ActCtx);
189         ActCtx.Format = RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER;
190         RtlActivateActivationContextUnsafeFast(&ActCtx, NULL);
191     }
192 
193     /* Check if we have more handles then we locally optimize */
194     if (nCount > 8)
195     {
196         /* Allocate a buffer for them */
197         HandleBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
198                                        0,
199                                        nCount * sizeof(HANDLE));
200         if (!HandleBuffer)
201         {
202             /* No buffer, fail the wait */
203             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
204             if (bAlertable) RtlDeactivateActivationContextUnsafeFast(&ActCtx);
205             return WAIT_FAILED;
206         }
207     }
208     else
209     {
210         /* Otherwise, use our local buffer */
211         HandleBuffer = Handle;
212     }
213 
214     /* Copy the handles into our buffer and loop them all */
215     RtlCopyMemory(HandleBuffer, (LPVOID)lpHandles, nCount * sizeof(HANDLE));
216     for (i = 0; i < nCount; i++)
217     {
218         /* Check what kind of handle this is */
219         HandleBuffer[i] = TranslateStdHandle(HandleBuffer[i]);
220 
221         /* Check for console handle */
222         if ((IsConsoleHandle(HandleBuffer[i])) &&
223             (VerifyConsoleIoHandle(HandleBuffer[i])))
224         {
225             /* Get the real wait handle */
226             HandleBuffer[i] = GetConsoleInputWaitHandle();
227         }
228     }
229 
230     /* Convert the timeout */
231     TimePtr = BaseFormatTimeOut(&Time, dwMilliseconds);
232 
233     /* Start wait loop */
234     do
235     {
236         /* Do the wait */
237         Status = NtWaitForMultipleObjects(nCount,
238                                           HandleBuffer,
239                                           bWaitAll ? WaitAll : WaitAny,
240                                           (BOOLEAN)bAlertable,
241                                           TimePtr);
242         if (!NT_SUCCESS(Status))
243         {
244             /* Wait failed */
245             BaseSetLastNTError(Status);
246             Status = WAIT_FAILED;
247         }
248     } while ((Status == STATUS_ALERTED) && (bAlertable));
249 
250     /* Check if we didn't use our local buffer */
251     if (HandleBuffer != Handle)
252     {
253         /* Free the allocated one */
254         RtlFreeHeap(RtlGetProcessHeap(), 0, HandleBuffer);
255     }
256 
257     /* Cleanup the activation context */
258     if (bAlertable) RtlDeactivateActivationContextUnsafeFast(&ActCtx);
259 
260     /* Return wait status */
261     return Status;
262 }
263 
264 /*
265  * @implemented
266  */
267 DWORD
268 WINAPI
269 SignalObjectAndWait(IN HANDLE hObjectToSignal,
270                     IN HANDLE hObjectToWaitOn,
271                     IN DWORD dwMilliseconds,
272                     IN BOOL bAlertable)
273 {
274     PLARGE_INTEGER TimePtr;
275     LARGE_INTEGER Time;
276     NTSTATUS Status;
277     RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActCtx;
278 
279     /* APCs must execute with the default activation context */
280     if (bAlertable)
281     {
282         /* Setup the frame */
283         RtlZeroMemory(&ActCtx, sizeof(ActCtx));
284         ActCtx.Size = sizeof(ActCtx);
285         ActCtx.Format = RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER;
286         RtlActivateActivationContextUnsafeFast(&ActCtx, NULL);
287     }
288 
289     /* Get real handle */
290     hObjectToWaitOn = TranslateStdHandle(hObjectToWaitOn);
291 
292     /* Check for console handle */
293     if ((IsConsoleHandle(hObjectToWaitOn)) &&
294         (VerifyConsoleIoHandle(hObjectToWaitOn)))
295     {
296         /* Get the real wait handle */
297         hObjectToWaitOn = GetConsoleInputWaitHandle();
298     }
299 
300     /* Convert the timeout */
301     TimePtr = BaseFormatTimeOut(&Time, dwMilliseconds);
302 
303     /* Start wait loop */
304     do
305     {
306         /* Do the wait */
307         Status = NtSignalAndWaitForSingleObject(hObjectToSignal,
308                                                 hObjectToWaitOn,
309                                                 (BOOLEAN)bAlertable,
310                                                 TimePtr);
311         if (!NT_SUCCESS(Status))
312         {
313             /* The wait failed */
314             BaseSetLastNTError(Status);
315             Status = WAIT_FAILED;
316         }
317     } while ((Status == STATUS_ALERTED) && (bAlertable));
318 
319     /* Cleanup the activation context */
320     if (bAlertable) RtlDeactivateActivationContextUnsafeFast(&ActCtx);
321 
322     /* Return wait status */
323     return Status;
324 }
325 
326 /*
327  * @implemented
328  */
329 HANDLE
330 WINAPI
331 CreateWaitableTimerW(IN LPSECURITY_ATTRIBUTES lpTimerAttributes OPTIONAL,
332                      IN BOOL bManualReset,
333                      IN LPCWSTR lpTimerName OPTIONAL)
334 {
335     CreateNtObjectFromWin32Api(WaitableTimer, Timer, TIMER,
336                                lpTimerAttributes,
337                                lpTimerName,
338                                bManualReset ? NotificationTimer : SynchronizationTimer);
339 }
340 
341 /*
342  * @implemented
343  */
344 HANDLE
345 WINAPI
346 CreateWaitableTimerA(IN LPSECURITY_ATTRIBUTES lpTimerAttributes OPTIONAL,
347                      IN BOOL bManualReset,
348                      IN LPCSTR lpTimerName OPTIONAL)
349 {
350     ConvertWin32AnsiObjectApiToUnicodeApi(WaitableTimer, lpTimerName, lpTimerAttributes, bManualReset);
351 }
352 
353 /*
354  * @implemented
355  */
356 HANDLE
357 WINAPI
358 OpenWaitableTimerW(IN DWORD dwDesiredAccess,
359                    IN BOOL bInheritHandle,
360                    IN LPCWSTR lpTimerName)
361 {
362     OpenNtObjectFromWin32Api(Timer, dwDesiredAccess, bInheritHandle, lpTimerName);
363 }
364 
365 /*
366  * @implemented
367  */
368 HANDLE
369 WINAPI
370 OpenWaitableTimerA(IN DWORD dwDesiredAccess,
371                    IN BOOL bInheritHandle,
372                    IN LPCSTR lpTimerName)
373 {
374     ConvertOpenWin32AnsiObjectApiToUnicodeApi(WaitableTimer, dwDesiredAccess, bInheritHandle, lpTimerName);
375 }
376 
377 /*
378  * @implemented
379  */
380 BOOL
381 WINAPI
382 SetWaitableTimer(IN HANDLE hTimer,
383                  IN const LARGE_INTEGER *pDueTime,
384                  IN LONG lPeriod,
385                  IN PTIMERAPCROUTINE pfnCompletionRoutine OPTIONAL,
386                  IN OPTIONAL LPVOID lpArgToCompletionRoutine,
387                  IN BOOL fResume)
388 {
389     NTSTATUS Status;
390 
391     /* Set the timer */
392     Status = NtSetTimer(hTimer,
393                         (PLARGE_INTEGER)pDueTime,
394                         (PTIMER_APC_ROUTINE)pfnCompletionRoutine,
395                         lpArgToCompletionRoutine,
396                         (BOOLEAN)fResume,
397                         lPeriod,
398                         NULL);
399     if (NT_SUCCESS(Status)) return TRUE;
400 
401     /* If we got here, then we failed */
402     BaseSetLastNTError(Status);
403     return FALSE;
404 }
405 
406 /*
407  * @implemented
408  */
409 BOOL
410 WINAPI
411 CancelWaitableTimer(IN HANDLE hTimer)
412 {
413     NTSTATUS Status;
414 
415     /* Cancel the timer */
416     Status = NtCancelTimer(hTimer, NULL);
417     if (NT_SUCCESS(Status)) return TRUE;
418 
419     /* If we got here, then we failed */
420     BaseSetLastNTError(Status);
421     return FALSE;
422 }
423 
424 /*
425  * @implemented
426  */
427 HANDLE
428 WINAPI
429 DECLSPEC_HOTPATCH
430 CreateSemaphoreA(IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes  OPTIONAL,
431                  IN LONG lInitialCount,
432                  IN LONG lMaximumCount,
433                  IN LPCSTR lpName  OPTIONAL)
434 {
435     ConvertWin32AnsiObjectApiToUnicodeApi(Semaphore, lpName, lpSemaphoreAttributes, lInitialCount, lMaximumCount);
436 }
437 
438 /*
439  * @implemented
440  */
441 HANDLE
442 WINAPI
443 DECLSPEC_HOTPATCH
444 CreateSemaphoreW(IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes  OPTIONAL,
445                  IN LONG lInitialCount,
446                  IN LONG lMaximumCount,
447                  IN LPCWSTR lpName  OPTIONAL)
448 {
449     CreateNtObjectFromWin32Api(Semaphore, Semaphore, SEMAPHORE,
450                                lpSemaphoreAttributes,
451                                lpName,
452                                lInitialCount,
453                                lMaximumCount);
454 }
455 
456 /*
457  * @implemented
458  */
459 HANDLE
460 WINAPI
461 DECLSPEC_HOTPATCH
462 OpenSemaphoreA(IN DWORD dwDesiredAccess,
463                IN BOOL bInheritHandle,
464                IN LPCSTR lpName)
465 {
466     ConvertOpenWin32AnsiObjectApiToUnicodeApi(Semaphore, dwDesiredAccess, bInheritHandle, lpName);
467 }
468 
469 /*
470  * @implemented
471  */
472 HANDLE
473 WINAPI
474 DECLSPEC_HOTPATCH
475 OpenSemaphoreW(IN DWORD dwDesiredAccess,
476                IN BOOL bInheritHandle,
477                IN LPCWSTR lpName)
478 {
479     OpenNtObjectFromWin32Api(Semaphore, dwDesiredAccess, bInheritHandle, lpName);
480 }
481 
482 /*
483  * @implemented
484  */
485 BOOL
486 WINAPI
487 DECLSPEC_HOTPATCH
488 ReleaseSemaphore(IN HANDLE hSemaphore,
489                  IN LONG lReleaseCount,
490                  IN LPLONG lpPreviousCount)
491 {
492     NTSTATUS Status;
493 
494     /* Release the semaphore */
495     Status = NtReleaseSemaphore(hSemaphore, lReleaseCount, lpPreviousCount);
496     if (NT_SUCCESS(Status)) return TRUE;
497 
498     /* If we got here, then we failed */
499     BaseSetLastNTError(Status);
500     return FALSE;
501 }
502 
503 /*
504  * @implemented
505  */
506 HANDLE
507 WINAPI
508 DECLSPEC_HOTPATCH
509 CreateMutexA(IN LPSECURITY_ATTRIBUTES lpMutexAttributes  OPTIONAL,
510              IN BOOL bInitialOwner,
511              IN LPCSTR lpName  OPTIONAL)
512 {
513     ConvertWin32AnsiObjectApiToUnicodeApi(Mutex, lpName, lpMutexAttributes, bInitialOwner);
514 }
515 
516 /*
517  * @implemented
518  */
519 HANDLE
520 WINAPI
521 DECLSPEC_HOTPATCH
522 CreateMutexW(IN LPSECURITY_ATTRIBUTES lpMutexAttributes  OPTIONAL,
523              IN BOOL bInitialOwner,
524              IN LPCWSTR lpName  OPTIONAL)
525 {
526     CreateNtObjectFromWin32Api(Mutex, Mutant, MUTEX,
527                                lpMutexAttributes,
528                                lpName,
529                                bInitialOwner);
530 }
531 
532 /*
533  * @implemented
534  */
535 HANDLE
536 WINAPI
537 DECLSPEC_HOTPATCH
538 OpenMutexA(IN DWORD dwDesiredAccess,
539            IN BOOL bInheritHandle,
540            IN LPCSTR lpName)
541 {
542     ConvertOpenWin32AnsiObjectApiToUnicodeApi(Mutex, dwDesiredAccess, bInheritHandle, lpName);
543 }
544 
545 /*
546  * @implemented
547  */
548 HANDLE
549 WINAPI
550 DECLSPEC_HOTPATCH
551 OpenMutexW(IN DWORD dwDesiredAccess,
552            IN BOOL bInheritHandle,
553            IN LPCWSTR lpName)
554 {
555     OpenNtObjectFromWin32Api(Mutant, dwDesiredAccess, bInheritHandle, lpName);
556 }
557 
558 /*
559  * @implemented
560  */
561 BOOL
562 WINAPI
563 DECLSPEC_HOTPATCH
564 ReleaseMutex(IN HANDLE hMutex)
565 {
566     NTSTATUS Status;
567 
568     /* Release the mutant */
569     Status = NtReleaseMutant(hMutex, NULL);
570     if (NT_SUCCESS(Status)) return TRUE;
571 
572     /* If we got here, then we failed */
573     BaseSetLastNTError(Status);
574     return FALSE;
575 }
576 
577 /*
578  * @implemented
579  */
580 HANDLE
581 WINAPI
582 DECLSPEC_HOTPATCH
583 CreateEventA(IN LPSECURITY_ATTRIBUTES lpEventAttributes  OPTIONAL,
584              IN BOOL bManualReset,
585              IN BOOL bInitialState,
586              IN LPCSTR lpName OPTIONAL)
587 {
588     ConvertWin32AnsiObjectApiToUnicodeApi(Event, lpName, lpEventAttributes, bManualReset, bInitialState);
589 }
590 
591 /*
592  * @implemented
593  */
594 HANDLE
595 WINAPI
596 DECLSPEC_HOTPATCH
597 CreateEventW(IN LPSECURITY_ATTRIBUTES lpEventAttributes  OPTIONAL,
598              IN BOOL bManualReset,
599              IN BOOL bInitialState,
600              IN LPCWSTR lpName  OPTIONAL)
601 {
602     CreateNtObjectFromWin32Api(Event, Event, EVENT,
603                                lpEventAttributes,
604                                lpName,
605                                bManualReset ? NotificationEvent : SynchronizationEvent,
606                                bInitialState);
607 }
608 
609 /*
610  * @implemented
611  */
612 HANDLE
613 WINAPI
614 DECLSPEC_HOTPATCH
615 OpenEventA(IN DWORD dwDesiredAccess,
616            IN BOOL bInheritHandle,
617            IN LPCSTR lpName)
618 {
619     ConvertOpenWin32AnsiObjectApiToUnicodeApi(Event, dwDesiredAccess, bInheritHandle, lpName);
620 }
621 
622 /*
623  * @implemented
624  */
625 HANDLE
626 WINAPI
627 DECLSPEC_HOTPATCH
628 OpenEventW(IN DWORD dwDesiredAccess,
629            IN BOOL bInheritHandle,
630            IN LPCWSTR lpName)
631 {
632     OpenNtObjectFromWin32Api(Event, dwDesiredAccess, bInheritHandle, lpName);
633 }
634 
635 /*
636  * @implemented
637  */
638 BOOL
639 WINAPI
640 DECLSPEC_HOTPATCH
641 PulseEvent(IN HANDLE hEvent)
642 {
643     NTSTATUS Status;
644 
645     /* Pulse the event */
646     Status = NtPulseEvent(hEvent, NULL);
647     if (NT_SUCCESS(Status)) return TRUE;
648 
649     /* If we got here, then we failed */
650     BaseSetLastNTError(Status);
651     return FALSE;
652 }
653 
654 /*
655  * @implemented
656  */
657 BOOL
658 WINAPI
659 DECLSPEC_HOTPATCH
660 ResetEvent(IN HANDLE hEvent)
661 {
662     NTSTATUS Status;
663 
664     /* Clear the event */
665     Status = NtResetEvent(hEvent, NULL);
666     if (NT_SUCCESS(Status)) return TRUE;
667 
668     /* If we got here, then we failed */
669     BaseSetLastNTError(Status);
670     return FALSE;
671 }
672 
673 /*
674  * @implemented
675  */
676 BOOL
677 WINAPI
678 DECLSPEC_HOTPATCH
679 SetEvent(IN HANDLE hEvent)
680 {
681     NTSTATUS Status;
682 
683     /* Set the event */
684     Status = NtSetEvent(hEvent, NULL);
685     if (NT_SUCCESS(Status)) return TRUE;
686 
687     /* If we got here, then we failed */
688     BaseSetLastNTError(Status);
689     return FALSE;
690 }
691 
692 /*
693  * @implemented
694  */
695 VOID
696 WINAPI
697 InitializeCriticalSection(OUT LPCRITICAL_SECTION lpCriticalSection)
698 {
699     NTSTATUS Status;
700 
701     /* Initialize the critical section and raise an exception if we failed */
702     Status = RtlInitializeCriticalSection((PVOID)lpCriticalSection);
703     if (!NT_SUCCESS(Status)) RtlRaiseStatus(Status);
704 }
705 
706 /*
707  * @implemented
708  */
709 BOOL
710 WINAPI
711 InitializeCriticalSectionAndSpinCount(OUT LPCRITICAL_SECTION lpCriticalSection,
712                                       IN DWORD dwSpinCount)
713 {
714     NTSTATUS Status;
715 
716     /* Initialize the critical section */
717     Status = RtlInitializeCriticalSectionAndSpinCount((PVOID)lpCriticalSection,
718                                                       dwSpinCount);
719     if (!NT_SUCCESS(Status))
720     {
721         /* Set failure code */
722         BaseSetLastNTError(Status);
723         return FALSE;
724     }
725 
726     /* Success */
727     return TRUE;
728 }
729 
730 /*
731  * @implemented
732  */
733 VOID
734 WINAPI
735 DECLSPEC_HOTPATCH
736 Sleep(IN DWORD dwMilliseconds)
737 {
738     /* Call the new API */
739     SleepEx(dwMilliseconds, FALSE);
740 }
741 
742 
743 /*
744  * @implemented
745  */
746 DWORD
747 WINAPI
748 SleepEx(IN DWORD dwMilliseconds,
749         IN BOOL bAlertable)
750 {
751     LARGE_INTEGER Time;
752     PLARGE_INTEGER TimePtr;
753     NTSTATUS errCode;
754     RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActCtx;
755 
756     /* APCs must execute with the default activation context */
757     if (bAlertable)
758     {
759         /* Setup the frame */
760         RtlZeroMemory(&ActCtx, sizeof(ActCtx));
761         ActCtx.Size = sizeof(ActCtx);
762         ActCtx.Format = RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER;
763         RtlActivateActivationContextUnsafeFast(&ActCtx, NULL);
764     }
765 
766     /* Convert the timeout */
767     TimePtr = BaseFormatTimeOut(&Time, dwMilliseconds);
768     if (!TimePtr)
769     {
770         /* Turn an infinite wait into a really long wait */
771         Time.LowPart = 0;
772         Time.HighPart = 0x80000000;
773         TimePtr = &Time;
774     }
775 
776     /* Loop the delay while APCs are alerting us */
777     do
778     {
779         /* Do the delay */
780         errCode = NtDelayExecution((BOOLEAN)bAlertable, TimePtr);
781     }
782     while ((bAlertable) && (errCode == STATUS_ALERTED));
783 
784     /* Cleanup the activation context */
785     if (bAlertable) RtlDeactivateActivationContextUnsafeFast(&ActCtx);
786 
787     /* Return the correct code */
788     return (errCode == STATUS_USER_APC) ? WAIT_IO_COMPLETION : 0;
789 }
790 
791 /*
792  * @implemented
793  */
794 BOOL
795 WINAPI
796 RegisterWaitForSingleObject(OUT PHANDLE phNewWaitObject,
797                             IN HANDLE hObject,
798                             IN WAITORTIMERCALLBACK Callback,
799                             IN PVOID Context,
800                             IN ULONG dwMilliseconds,
801                             IN ULONG dwFlags)
802 {
803     NTSTATUS Status;
804 
805     /* Get real handle */
806     hObject = TranslateStdHandle(hObject);
807 
808     /* Check for console handle */
809     if ((IsConsoleHandle(hObject)) && (VerifyConsoleIoHandle(hObject)))
810     {
811         /* Get the real wait handle */
812         hObject = GetConsoleInputWaitHandle();
813     }
814 
815     /* Register the wait now */
816     Status = RtlRegisterWait(phNewWaitObject,
817                              hObject,
818                              Callback,
819                              Context,
820                              dwMilliseconds,
821                              dwFlags);
822     if (!NT_SUCCESS(Status))
823     {
824         /* Return failure */
825         BaseSetLastNTError(Status);
826         return FALSE;
827     }
828 
829     /* All good */
830     return TRUE;
831 }
832 
833 /*
834  * @implemented
835  */
836 HANDLE
837 WINAPI
838 RegisterWaitForSingleObjectEx(IN HANDLE hObject,
839                               IN WAITORTIMERCALLBACK Callback,
840                               IN PVOID Context,
841                               IN ULONG dwMilliseconds,
842                               IN ULONG dwFlags)
843 {
844     NTSTATUS Status;
845     HANDLE hNewWaitObject;
846 
847     /* Get real handle */
848     hObject = TranslateStdHandle(hObject);
849 
850     /* Check for console handle */
851     if ((IsConsoleHandle(hObject)) && (VerifyConsoleIoHandle(hObject)))
852     {
853         /* Get the real wait handle */
854         hObject = GetConsoleInputWaitHandle();
855     }
856 
857     /* Register the wait */
858     Status = RtlRegisterWait(&hNewWaitObject,
859                              hObject,
860                              Callback,
861                              Context,
862                              dwMilliseconds,
863                              dwFlags);
864     if (!NT_SUCCESS(Status))
865     {
866         /* Return failure */
867         BaseSetLastNTError(Status);
868         return NULL;
869     }
870 
871     /* Return the object */
872     return hNewWaitObject;
873 }
874 
875 /*
876  * @implemented
877  */
878 BOOL
879 WINAPI
880 UnregisterWait(IN HANDLE WaitHandle)
881 {
882     NTSTATUS Status;
883 
884     /* Check for invalid handle */
885     if (!WaitHandle)
886     {
887         /* Fail */
888         SetLastError(ERROR_INVALID_HANDLE);
889         return FALSE;
890     }
891 
892     /* Deregister the wait and check status */
893     Status = RtlDeregisterWaitEx(WaitHandle, NULL);
894     if (!(NT_SUCCESS(Status)) || (Status == STATUS_PENDING))
895     {
896         /* Failure or non-blocking call */
897         BaseSetLastNTError(Status);
898         return FALSE;
899     }
900 
901     /* All good */
902     return TRUE;
903 }
904 
905 /*
906  * @implemented
907  */
908 BOOL
909 WINAPI
910 UnregisterWaitEx(IN HANDLE WaitHandle,
911                  IN HANDLE CompletionEvent)
912 {
913     NTSTATUS Status;
914 
915     /* Check for invalid handle */
916     if (!WaitHandle)
917     {
918         /* Fail */
919         SetLastError(ERROR_INVALID_HANDLE);
920         return FALSE;
921     }
922 
923     /* Deregister the wait and check status */
924     Status = RtlDeregisterWaitEx(WaitHandle, CompletionEvent);
925     if (!(NT_SUCCESS(Status)) ||
926         ((CompletionEvent != INVALID_HANDLE_VALUE) && (Status == STATUS_PENDING)))
927     {
928         /* Failure or non-blocking call */
929         BaseSetLastNTError(Status);
930         return FALSE;
931     }
932 
933     /* All good */
934     return TRUE;
935 }
936 
937 /* EOF */
938