2 * PROJECT: ReactOS Win32 Base API
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/kernel32/synch/wait.c
5 * PURPOSE: Wrappers for the NT Wait Implementation
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES *****************************************************************/
15 #undef InterlockedIncrement
16 #undef InterlockedDecrement
17 #undef InterlockedExchange
18 #undef InterlockedExchangeAdd
19 #undef InterlockedCompareExchange
21 /* FUNCTIONS *****************************************************************/
28 InterlockedIncrement(IN OUT LONG
volatile *lpAddend
)
30 return _InterlockedIncrement(lpAddend
);
38 InterlockedDecrement(IN OUT LONG
volatile *lpAddend
)
40 return _InterlockedDecrement(lpAddend
);
48 InterlockedExchange(IN OUT LONG
volatile *Target
,
51 return _InterlockedExchange(Target
, Value
);
59 InterlockedExchangeAdd(IN OUT LONG
volatile *Addend
,
62 return _InterlockedExchangeAdd(Addend
, Value
);
70 InterlockedCompareExchange(IN OUT LONG
volatile *Destination
,
74 return _InterlockedCompareExchange(Destination
, Exchange
, Comperand
);
82 WaitForSingleObject(IN HANDLE hHandle
,
83 IN DWORD dwMilliseconds
)
85 /* Call the extended API */
86 return WaitForSingleObjectEx(hHandle
, dwMilliseconds
, FALSE
);
94 WaitForSingleObjectEx(IN HANDLE hHandle
,
95 IN DWORD dwMilliseconds
,
98 PLARGE_INTEGER TimePtr
;
101 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActCtx
;
103 /* APCs must execute with the default activation context */
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
);
113 /* Get real handle */
114 hHandle
= TranslateStdHandle(hHandle
);
116 /* Check for console handle */
117 if ((IsConsoleHandle(hHandle
)) && (VerifyConsoleIoHandle(hHandle
)))
119 /* Get the real wait handle */
120 hHandle
= GetConsoleInputWaitHandle();
123 /* Convert the timeout */
124 TimePtr
= BaseFormatTimeOut(&Time
, dwMilliseconds
);
126 /* Start wait loop */
130 Status
= NtWaitForSingleObject(hHandle
, (BOOLEAN
)bAlertable
, TimePtr
);
131 if (!NT_SUCCESS(Status
))
133 /* The wait failed */
134 BaseSetLastNTError(Status
);
135 Status
= WAIT_FAILED
;
137 } while ((Status
== STATUS_ALERTED
) && (bAlertable
));
139 /* Cleanup the activation context */
140 if (bAlertable
) RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
142 /* Return wait status */
151 WaitForMultipleObjects(IN DWORD nCount
,
152 IN CONST HANDLE
*lpHandles
,
154 IN DWORD dwMilliseconds
)
156 /* Call the extended API */
157 return WaitForMultipleObjectsEx(nCount
,
169 WaitForMultipleObjectsEx(IN DWORD nCount
,
170 IN CONST HANDLE
*lpHandles
,
172 IN DWORD dwMilliseconds
,
175 PLARGE_INTEGER TimePtr
;
177 PHANDLE HandleBuffer
;
181 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActCtx
;
183 /* APCs must execute with the default activation context */
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
);
193 /* Check if we have more handles then we locally optimize */
196 /* Allocate a buffer for them */
197 HandleBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
199 nCount
* sizeof(HANDLE
));
202 /* No buffer, fail the wait */
203 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
204 if (bAlertable
) RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
210 /* Otherwise, use our local buffer */
211 HandleBuffer
= Handle
;
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
++)
218 /* Check what kind of handle this is */
219 HandleBuffer
[i
] = TranslateStdHandle(HandleBuffer
[i
]);
221 /* Check for console handle */
222 if ((IsConsoleHandle(HandleBuffer
[i
])) &&
223 (VerifyConsoleIoHandle(HandleBuffer
[i
])))
225 /* Get the real wait handle */
226 HandleBuffer
[i
] = GetConsoleInputWaitHandle();
230 /* Convert the timeout */
231 TimePtr
= BaseFormatTimeOut(&Time
, dwMilliseconds
);
233 /* Start wait loop */
237 Status
= NtWaitForMultipleObjects(nCount
,
239 bWaitAll
? WaitAll
: WaitAny
,
242 if (!NT_SUCCESS(Status
))
245 BaseSetLastNTError(Status
);
246 Status
= WAIT_FAILED
;
248 } while ((Status
== STATUS_ALERTED
) && (bAlertable
));
250 /* Check if we didn't use our local buffer */
251 if (HandleBuffer
!= Handle
)
253 /* Free the allocated one */
254 RtlFreeHeap(RtlGetProcessHeap(), 0, HandleBuffer
);
257 /* Cleanup the activation context */
258 if (bAlertable
) RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
260 /* Return wait status */
269 SignalObjectAndWait(IN HANDLE hObjectToSignal
,
270 IN HANDLE hObjectToWaitOn
,
271 IN DWORD dwMilliseconds
,
274 PLARGE_INTEGER TimePtr
;
277 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActCtx
;
279 /* APCs must execute with the default activation context */
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
);
289 /* Get real handle */
290 hObjectToWaitOn
= TranslateStdHandle(hObjectToWaitOn
);
292 /* Check for console handle */
293 if ((IsConsoleHandle(hObjectToWaitOn
)) &&
294 (VerifyConsoleIoHandle(hObjectToWaitOn
)))
296 /* Get the real wait handle */
297 hObjectToWaitOn
= GetConsoleInputWaitHandle();
300 /* Convert the timeout */
301 TimePtr
= BaseFormatTimeOut(&Time
, dwMilliseconds
);
303 /* Start wait loop */
307 Status
= NtSignalAndWaitForSingleObject(hObjectToSignal
,
311 if (!NT_SUCCESS(Status
))
313 /* The wait failed */
314 BaseSetLastNTError(Status
);
315 Status
= WAIT_FAILED
;
317 } while ((Status
== STATUS_ALERTED
) && (bAlertable
));
319 /* Cleanup the activation context */
320 if (bAlertable
) RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
322 /* Return wait status */
331 CreateWaitableTimerW(IN LPSECURITY_ATTRIBUTES lpTimerAttributes OPTIONAL
,
332 IN BOOL bManualReset
,
333 IN LPCWSTR lpTimerName OPTIONAL
)
335 CreateNtObjectFromWin32Api(WaitableTimer
, Timer
, TIMER
,
338 bManualReset
? NotificationTimer
: SynchronizationTimer
);
346 CreateWaitableTimerA(IN LPSECURITY_ATTRIBUTES lpTimerAttributes OPTIONAL
,
347 IN BOOL bManualReset
,
348 IN LPCSTR lpTimerName OPTIONAL
)
350 ConvertWin32AnsiObjectApiToUnicodeApi(WaitableTimer
, lpTimerName
, lpTimerAttributes
, bManualReset
);
358 OpenWaitableTimerW(IN DWORD dwDesiredAccess
,
359 IN BOOL bInheritHandle
,
360 IN LPCWSTR lpTimerName
)
362 OpenNtObjectFromWin32Api(Timer
, dwDesiredAccess
, bInheritHandle
, lpTimerName
);
370 OpenWaitableTimerA(IN DWORD dwDesiredAccess
,
371 IN BOOL bInheritHandle
,
372 IN LPCSTR lpTimerName
)
374 ConvertOpenWin32AnsiObjectApiToUnicodeApi(WaitableTimer
, dwDesiredAccess
, bInheritHandle
, lpTimerName
);
382 SetWaitableTimer(IN HANDLE hTimer
,
383 IN
const LARGE_INTEGER
*pDueTime
,
385 IN PTIMERAPCROUTINE pfnCompletionRoutine OPTIONAL
,
386 IN OPTIONAL LPVOID lpArgToCompletionRoutine
,
392 Status
= NtSetTimer(hTimer
,
393 (PLARGE_INTEGER
)pDueTime
,
394 (PTIMER_APC_ROUTINE
)pfnCompletionRoutine
,
395 lpArgToCompletionRoutine
,
399 if (NT_SUCCESS(Status
)) return TRUE
;
401 /* If we got here, then we failed */
402 BaseSetLastNTError(Status
);
411 CancelWaitableTimer(IN HANDLE hTimer
)
415 /* Cancel the timer */
416 Status
= NtCancelTimer(hTimer
, NULL
);
417 if (NT_SUCCESS(Status
)) return TRUE
;
419 /* If we got here, then we failed */
420 BaseSetLastNTError(Status
);
429 CreateSemaphoreA(IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes OPTIONAL
,
430 IN LONG lInitialCount
,
431 IN LONG lMaximumCount
,
432 IN LPCSTR lpName OPTIONAL
)
434 ConvertWin32AnsiObjectApiToUnicodeApi(Semaphore
, lpName
, lpSemaphoreAttributes
, lInitialCount
, lMaximumCount
);
442 CreateSemaphoreW(IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes OPTIONAL
,
443 IN LONG lInitialCount
,
444 IN LONG lMaximumCount
,
445 IN LPCWSTR lpName OPTIONAL
)
447 CreateNtObjectFromWin32Api(Semaphore
, Semaphore
, SEMAPHORE
,
448 lpSemaphoreAttributes
,
459 OpenSemaphoreA(IN DWORD dwDesiredAccess
,
460 IN BOOL bInheritHandle
,
463 ConvertOpenWin32AnsiObjectApiToUnicodeApi(Semaphore
, dwDesiredAccess
, bInheritHandle
, lpName
);
471 OpenSemaphoreW(IN DWORD dwDesiredAccess
,
472 IN BOOL bInheritHandle
,
475 OpenNtObjectFromWin32Api(Semaphore
, dwDesiredAccess
, bInheritHandle
, lpName
);
483 ReleaseSemaphore(IN HANDLE hSemaphore
,
484 IN LONG lReleaseCount
,
485 IN LPLONG lpPreviousCount
)
489 /* Release the semaphore */
490 Status
= NtReleaseSemaphore(hSemaphore
, lReleaseCount
, lpPreviousCount
);
491 if (NT_SUCCESS(Status
)) return TRUE
;
493 /* If we got here, then we failed */
494 BaseSetLastNTError(Status
);
503 CreateMutexA(IN LPSECURITY_ATTRIBUTES lpMutexAttributes OPTIONAL
,
504 IN BOOL bInitialOwner
,
505 IN LPCSTR lpName OPTIONAL
)
507 ConvertWin32AnsiObjectApiToUnicodeApi(Mutex
, lpName
, lpMutexAttributes
, bInitialOwner
);
515 CreateMutexW(IN LPSECURITY_ATTRIBUTES lpMutexAttributes OPTIONAL
,
516 IN BOOL bInitialOwner
,
517 IN LPCWSTR lpName OPTIONAL
)
519 CreateNtObjectFromWin32Api(Mutex
, Mutant
, MUTEX
,
530 OpenMutexA(IN DWORD dwDesiredAccess
,
531 IN BOOL bInheritHandle
,
534 ConvertOpenWin32AnsiObjectApiToUnicodeApi(Mutex
, dwDesiredAccess
, bInheritHandle
, lpName
);
542 OpenMutexW(IN DWORD dwDesiredAccess
,
543 IN BOOL bInheritHandle
,
546 OpenNtObjectFromWin32Api(Mutant
, dwDesiredAccess
, bInheritHandle
, lpName
);
554 ReleaseMutex(IN HANDLE hMutex
)
558 /* Release the mutant */
559 Status
= NtReleaseMutant(hMutex
, NULL
);
560 if (NT_SUCCESS(Status
)) return TRUE
;
562 /* If we got here, then we failed */
563 BaseSetLastNTError(Status
);
572 CreateEventA(IN LPSECURITY_ATTRIBUTES lpEventAttributes OPTIONAL
,
573 IN BOOL bManualReset
,
574 IN BOOL bInitialState
,
575 IN LPCSTR lpName OPTIONAL
)
577 ConvertWin32AnsiObjectApiToUnicodeApi(Event
, lpName
, lpEventAttributes
, bManualReset
, bInitialState
);
585 CreateEventW(IN LPSECURITY_ATTRIBUTES lpEventAttributes OPTIONAL
,
586 IN BOOL bManualReset
,
587 IN BOOL bInitialState
,
588 IN LPCWSTR lpName OPTIONAL
)
590 CreateNtObjectFromWin32Api(Event
, Event
, EVENT
,
593 bManualReset
? NotificationEvent
: SynchronizationEvent
,
602 OpenEventA(IN DWORD dwDesiredAccess
,
603 IN BOOL bInheritHandle
,
606 ConvertOpenWin32AnsiObjectApiToUnicodeApi(Event
, dwDesiredAccess
, bInheritHandle
, lpName
);
614 OpenEventW(IN DWORD dwDesiredAccess
,
615 IN BOOL bInheritHandle
,
618 OpenNtObjectFromWin32Api(Event
, dwDesiredAccess
, bInheritHandle
, lpName
);
626 PulseEvent(IN HANDLE hEvent
)
630 /* Pulse the event */
631 Status
= NtPulseEvent(hEvent
, NULL
);
632 if (NT_SUCCESS(Status
)) return TRUE
;
634 /* If we got here, then we failed */
635 BaseSetLastNTError(Status
);
644 ResetEvent(IN HANDLE hEvent
)
648 /* Clear the event */
649 Status
= NtResetEvent(hEvent
, NULL
);
650 if (NT_SUCCESS(Status
)) return TRUE
;
652 /* If we got here, then we failed */
653 BaseSetLastNTError(Status
);
662 SetEvent(IN HANDLE hEvent
)
667 Status
= NtSetEvent(hEvent
, NULL
);
668 if (NT_SUCCESS(Status
)) return TRUE
;
670 /* If we got here, then we failed */
671 BaseSetLastNTError(Status
);
680 InitializeCriticalSection(OUT LPCRITICAL_SECTION lpCriticalSection
)
684 /* Initialize the critical section and raise an exception if we failed */
685 Status
= RtlInitializeCriticalSection((PVOID
)lpCriticalSection
);
686 if (!NT_SUCCESS(Status
)) RtlRaiseStatus(Status
);
694 InitializeCriticalSectionAndSpinCount(OUT LPCRITICAL_SECTION lpCriticalSection
,
695 IN DWORD dwSpinCount
)
699 /* Initialize the critical section */
700 Status
= RtlInitializeCriticalSectionAndSpinCount((PVOID
)lpCriticalSection
,
702 if (!NT_SUCCESS(Status
))
704 /* Set failure code */
705 BaseSetLastNTError(Status
);
718 Sleep(IN DWORD dwMilliseconds
)
720 /* Call the new API */
721 SleepEx(dwMilliseconds
, FALSE
);
730 SleepEx(IN DWORD dwMilliseconds
,
734 PLARGE_INTEGER TimePtr
;
736 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActCtx
;
738 /* APCs must execute with the default activation context */
741 /* Setup the frame */
742 RtlZeroMemory(&ActCtx
, sizeof(ActCtx
));
743 ActCtx
.Size
= sizeof(ActCtx
);
744 ActCtx
.Format
= RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER
;
745 RtlActivateActivationContextUnsafeFast(&ActCtx
, NULL
);
748 /* Convert the timeout */
749 TimePtr
= BaseFormatTimeOut(&Time
, dwMilliseconds
);
752 /* Turn an infinite wait into a really long wait */
754 Time
.HighPart
= 0x80000000;
758 /* Loop the delay while APCs are alerting us */
762 errCode
= NtDelayExecution((BOOLEAN
)bAlertable
, TimePtr
);
764 while ((bAlertable
) && (errCode
== STATUS_ALERTED
));
766 /* Cleanup the activation context */
767 if (bAlertable
) RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
769 /* Return the correct code */
770 return (errCode
== STATUS_USER_APC
) ? WAIT_IO_COMPLETION
: 0;
778 RegisterWaitForSingleObject(OUT PHANDLE phNewWaitObject
,
780 IN WAITORTIMERCALLBACK Callback
,
782 IN ULONG dwMilliseconds
,
787 /* Get real handle */
788 hObject
= TranslateStdHandle(hObject
);
790 /* Check for console handle */
791 if ((IsConsoleHandle(hObject
)) && (VerifyConsoleIoHandle(hObject
)))
793 /* Get the real wait handle */
794 hObject
= GetConsoleInputWaitHandle();
797 /* Register the wait now */
798 Status
= RtlRegisterWait(phNewWaitObject
,
804 if (!NT_SUCCESS(Status
))
807 BaseSetLastNTError(Status
);
820 RegisterWaitForSingleObjectEx(IN HANDLE hObject
,
821 IN WAITORTIMERCALLBACK Callback
,
823 IN ULONG dwMilliseconds
,
827 HANDLE hNewWaitObject
;
829 /* Get real handle */
830 hObject
= TranslateStdHandle(hObject
);
832 /* Check for console handle */
833 if ((IsConsoleHandle(hObject
)) && (VerifyConsoleIoHandle(hObject
)))
835 /* Get the real wait handle */
836 hObject
= GetConsoleInputWaitHandle();
839 /* Register the wait */
840 Status
= RtlRegisterWait(&hNewWaitObject
,
846 if (!NT_SUCCESS(Status
))
849 BaseSetLastNTError(Status
);
853 /* Return the object */
854 return hNewWaitObject
;
862 UnregisterWait(IN HANDLE WaitHandle
)
866 /* Check for invalid handle */
870 SetLastError(ERROR_INVALID_HANDLE
);
874 /* Deregister the wait and check status */
875 Status
= RtlDeregisterWaitEx(WaitHandle
, NULL
);
876 if (!(NT_SUCCESS(Status
)) || (Status
== STATUS_PENDING
))
878 /* Failure or non-blocking call */
879 BaseSetLastNTError(Status
);
892 UnregisterWaitEx(IN HANDLE WaitHandle
,
893 IN HANDLE CompletionEvent
)
897 /* Check for invalid handle */
901 SetLastError(ERROR_INVALID_HANDLE
);
905 /* Deregister the wait and check status */
906 Status
= RtlDeregisterWaitEx(WaitHandle
, CompletionEvent
);
907 if (!(NT_SUCCESS(Status
)) ||
908 ((CompletionEvent
!= INVALID_HANDLE_VALUE
) && (Status
== STATUS_PENDING
)))
910 /* Failure or non-blocking call */
911 BaseSetLastNTError(Status
);