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
);
430 CreateSemaphoreA(IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes OPTIONAL
,
431 IN LONG lInitialCount
,
432 IN LONG lMaximumCount
,
433 IN LPCSTR lpName OPTIONAL
)
435 ConvertWin32AnsiObjectApiToUnicodeApi(Semaphore
, lpName
, lpSemaphoreAttributes
, lInitialCount
, lMaximumCount
);
444 CreateSemaphoreW(IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes OPTIONAL
,
445 IN LONG lInitialCount
,
446 IN LONG lMaximumCount
,
447 IN LPCWSTR lpName OPTIONAL
)
449 CreateNtObjectFromWin32Api(Semaphore
, Semaphore
, SEMAPHORE
,
450 lpSemaphoreAttributes
,
462 OpenSemaphoreA(IN DWORD dwDesiredAccess
,
463 IN BOOL bInheritHandle
,
466 ConvertOpenWin32AnsiObjectApiToUnicodeApi(Semaphore
, dwDesiredAccess
, bInheritHandle
, lpName
);
475 OpenSemaphoreW(IN DWORD dwDesiredAccess
,
476 IN BOOL bInheritHandle
,
479 OpenNtObjectFromWin32Api(Semaphore
, dwDesiredAccess
, bInheritHandle
, lpName
);
488 ReleaseSemaphore(IN HANDLE hSemaphore
,
489 IN LONG lReleaseCount
,
490 IN LPLONG lpPreviousCount
)
494 /* Release the semaphore */
495 Status
= NtReleaseSemaphore(hSemaphore
, lReleaseCount
, lpPreviousCount
);
496 if (NT_SUCCESS(Status
)) return TRUE
;
498 /* If we got here, then we failed */
499 BaseSetLastNTError(Status
);
509 CreateMutexA(IN LPSECURITY_ATTRIBUTES lpMutexAttributes OPTIONAL
,
510 IN BOOL bInitialOwner
,
511 IN LPCSTR lpName OPTIONAL
)
513 ConvertWin32AnsiObjectApiToUnicodeApi(Mutex
, lpName
, lpMutexAttributes
, bInitialOwner
);
522 CreateMutexW(IN LPSECURITY_ATTRIBUTES lpMutexAttributes OPTIONAL
,
523 IN BOOL bInitialOwner
,
524 IN LPCWSTR lpName OPTIONAL
)
526 CreateNtObjectFromWin32Api(Mutex
, Mutant
, MUTEX
,
538 OpenMutexA(IN DWORD dwDesiredAccess
,
539 IN BOOL bInheritHandle
,
542 ConvertOpenWin32AnsiObjectApiToUnicodeApi(Mutex
, dwDesiredAccess
, bInheritHandle
, lpName
);
551 OpenMutexW(IN DWORD dwDesiredAccess
,
552 IN BOOL bInheritHandle
,
555 OpenNtObjectFromWin32Api(Mutant
, dwDesiredAccess
, bInheritHandle
, lpName
);
564 ReleaseMutex(IN HANDLE hMutex
)
568 /* Release the mutant */
569 Status
= NtReleaseMutant(hMutex
, NULL
);
570 if (NT_SUCCESS(Status
)) return TRUE
;
572 /* If we got here, then we failed */
573 BaseSetLastNTError(Status
);
583 CreateEventA(IN LPSECURITY_ATTRIBUTES lpEventAttributes OPTIONAL
,
584 IN BOOL bManualReset
,
585 IN BOOL bInitialState
,
586 IN LPCSTR lpName OPTIONAL
)
588 ConvertWin32AnsiObjectApiToUnicodeApi(Event
, lpName
, lpEventAttributes
, bManualReset
, bInitialState
);
597 CreateEventW(IN LPSECURITY_ATTRIBUTES lpEventAttributes OPTIONAL
,
598 IN BOOL bManualReset
,
599 IN BOOL bInitialState
,
600 IN LPCWSTR lpName OPTIONAL
)
602 CreateNtObjectFromWin32Api(Event
, Event
, EVENT
,
605 bManualReset
? NotificationEvent
: SynchronizationEvent
,
615 OpenEventA(IN DWORD dwDesiredAccess
,
616 IN BOOL bInheritHandle
,
619 ConvertOpenWin32AnsiObjectApiToUnicodeApi(Event
, dwDesiredAccess
, bInheritHandle
, lpName
);
628 OpenEventW(IN DWORD dwDesiredAccess
,
629 IN BOOL bInheritHandle
,
632 OpenNtObjectFromWin32Api(Event
, dwDesiredAccess
, bInheritHandle
, lpName
);
641 PulseEvent(IN HANDLE hEvent
)
645 /* Pulse the event */
646 Status
= NtPulseEvent(hEvent
, NULL
);
647 if (NT_SUCCESS(Status
)) return TRUE
;
649 /* If we got here, then we failed */
650 BaseSetLastNTError(Status
);
660 ResetEvent(IN HANDLE hEvent
)
664 /* Clear the event */
665 Status
= NtResetEvent(hEvent
, NULL
);
666 if (NT_SUCCESS(Status
)) return TRUE
;
668 /* If we got here, then we failed */
669 BaseSetLastNTError(Status
);
679 SetEvent(IN HANDLE hEvent
)
684 Status
= NtSetEvent(hEvent
, NULL
);
685 if (NT_SUCCESS(Status
)) return TRUE
;
687 /* If we got here, then we failed */
688 BaseSetLastNTError(Status
);
697 InitializeCriticalSection(OUT LPCRITICAL_SECTION lpCriticalSection
)
701 /* Initialize the critical section and raise an exception if we failed */
702 Status
= RtlInitializeCriticalSection((PVOID
)lpCriticalSection
);
703 if (!NT_SUCCESS(Status
)) RtlRaiseStatus(Status
);
711 InitializeCriticalSectionAndSpinCount(OUT LPCRITICAL_SECTION lpCriticalSection
,
712 IN DWORD dwSpinCount
)
716 /* Initialize the critical section */
717 Status
= RtlInitializeCriticalSectionAndSpinCount((PVOID
)lpCriticalSection
,
719 if (!NT_SUCCESS(Status
))
721 /* Set failure code */
722 BaseSetLastNTError(Status
);
736 Sleep(IN DWORD dwMilliseconds
)
738 /* Call the new API */
739 SleepEx(dwMilliseconds
, FALSE
);
748 SleepEx(IN DWORD dwMilliseconds
,
752 PLARGE_INTEGER TimePtr
;
754 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActCtx
;
756 /* APCs must execute with the default activation context */
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
);
766 /* Convert the timeout */
767 TimePtr
= BaseFormatTimeOut(&Time
, dwMilliseconds
);
770 /* Turn an infinite wait into a really long wait */
772 Time
.HighPart
= 0x80000000;
776 /* Loop the delay while APCs are alerting us */
780 errCode
= NtDelayExecution((BOOLEAN
)bAlertable
, TimePtr
);
782 while ((bAlertable
) && (errCode
== STATUS_ALERTED
));
784 /* Cleanup the activation context */
785 if (bAlertable
) RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
787 /* Return the correct code */
788 return (errCode
== STATUS_USER_APC
) ? WAIT_IO_COMPLETION
: 0;
796 RegisterWaitForSingleObject(OUT PHANDLE phNewWaitObject
,
798 IN WAITORTIMERCALLBACK Callback
,
800 IN ULONG dwMilliseconds
,
805 /* Get real handle */
806 hObject
= TranslateStdHandle(hObject
);
808 /* Check for console handle */
809 if ((IsConsoleHandle(hObject
)) && (VerifyConsoleIoHandle(hObject
)))
811 /* Get the real wait handle */
812 hObject
= GetConsoleInputWaitHandle();
815 /* Register the wait now */
816 Status
= RtlRegisterWait(phNewWaitObject
,
822 if (!NT_SUCCESS(Status
))
825 BaseSetLastNTError(Status
);
838 RegisterWaitForSingleObjectEx(IN HANDLE hObject
,
839 IN WAITORTIMERCALLBACK Callback
,
841 IN ULONG dwMilliseconds
,
845 HANDLE hNewWaitObject
;
847 /* Get real handle */
848 hObject
= TranslateStdHandle(hObject
);
850 /* Check for console handle */
851 if ((IsConsoleHandle(hObject
)) && (VerifyConsoleIoHandle(hObject
)))
853 /* Get the real wait handle */
854 hObject
= GetConsoleInputWaitHandle();
857 /* Register the wait */
858 Status
= RtlRegisterWait(&hNewWaitObject
,
864 if (!NT_SUCCESS(Status
))
867 BaseSetLastNTError(Status
);
871 /* Return the object */
872 return hNewWaitObject
;
880 UnregisterWait(IN HANDLE WaitHandle
)
884 /* Check for invalid handle */
888 SetLastError(ERROR_INVALID_HANDLE
);
892 /* Deregister the wait and check status */
893 Status
= RtlDeregisterWaitEx(WaitHandle
, NULL
);
894 if (!(NT_SUCCESS(Status
)) || (Status
== STATUS_PENDING
))
896 /* Failure or non-blocking call */
897 BaseSetLastNTError(Status
);
910 UnregisterWaitEx(IN HANDLE WaitHandle
,
911 IN HANDLE CompletionEvent
)
915 /* Check for invalid handle */
919 SetLastError(ERROR_INVALID_HANDLE
);
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
)))
928 /* Failure or non-blocking call */
929 BaseSetLastNTError(Status
);