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 /* FUNCTIONS *****************************************************************/
22 WaitForSingleObject(IN HANDLE hHandle
,
23 IN DWORD dwMilliseconds
)
25 /* Call the extended API */
26 return WaitForSingleObjectEx(hHandle
, dwMilliseconds
, FALSE
);
34 WaitForSingleObjectEx(IN HANDLE hHandle
,
35 IN DWORD dwMilliseconds
,
38 PLARGE_INTEGER TimePtr
;
41 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActCtx
;
43 /* APCs must execute with the default activation context */
47 RtlZeroMemory(&ActCtx
, sizeof(ActCtx
));
48 ActCtx
.Size
= sizeof(ActCtx
);
49 ActCtx
.Format
= RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER
;
50 RtlActivateActivationContextUnsafeFast(&ActCtx
, NULL
);
54 hHandle
= TranslateStdHandle(hHandle
);
56 /* Check for console handle */
57 if ((IsConsoleHandle(hHandle
)) && (VerifyConsoleIoHandle(hHandle
)))
59 /* Get the real wait handle */
60 hHandle
= GetConsoleInputWaitHandle();
63 /* Convert the timeout */
64 TimePtr
= BaseFormatTimeOut(&Time
, dwMilliseconds
);
70 Status
= NtWaitForSingleObject(hHandle
, (BOOLEAN
)bAlertable
, TimePtr
);
71 if (!NT_SUCCESS(Status
))
74 BaseSetLastNTError(Status
);
77 } while ((Status
== STATUS_ALERTED
) && (bAlertable
));
79 /* Cleanup the activation context */
80 if (bAlertable
) RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
82 /* Return wait status */
91 WaitForMultipleObjects(IN DWORD nCount
,
92 IN CONST HANDLE
*lpHandles
,
94 IN DWORD dwMilliseconds
)
96 /* Call the extended API */
97 return WaitForMultipleObjectsEx(nCount
,
109 WaitForMultipleObjectsEx(IN DWORD nCount
,
110 IN CONST HANDLE
*lpHandles
,
112 IN DWORD dwMilliseconds
,
115 PLARGE_INTEGER TimePtr
;
117 PHANDLE HandleBuffer
;
121 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActCtx
;
123 /* APCs must execute with the default activation context */
126 /* Setup the frame */
127 RtlZeroMemory(&ActCtx
, sizeof(ActCtx
));
128 ActCtx
.Size
= sizeof(ActCtx
);
129 ActCtx
.Format
= RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER
;
130 RtlActivateActivationContextUnsafeFast(&ActCtx
, NULL
);
133 /* Check if we have more handles then we locally optimize */
136 /* Allocate a buffer for them */
137 HandleBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
139 nCount
* sizeof(HANDLE
));
142 /* No buffer, fail the wait */
143 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
144 if (bAlertable
) RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
150 /* Otherwise, use our local buffer */
151 HandleBuffer
= Handle
;
154 /* Copy the handles into our buffer and loop them all */
155 RtlCopyMemory(HandleBuffer
, (LPVOID
)lpHandles
, nCount
* sizeof(HANDLE
));
156 for (i
= 0; i
< nCount
; i
++)
158 /* Check what kind of handle this is */
159 HandleBuffer
[i
] = TranslateStdHandle(HandleBuffer
[i
]);
161 /* Check for console handle */
162 if ((IsConsoleHandle(HandleBuffer
[i
])) &&
163 (VerifyConsoleIoHandle(HandleBuffer
[i
])))
165 /* Get the real wait handle */
166 HandleBuffer
[i
] = GetConsoleInputWaitHandle();
170 /* Convert the timeout */
171 TimePtr
= BaseFormatTimeOut(&Time
, dwMilliseconds
);
173 /* Start wait loop */
177 Status
= NtWaitForMultipleObjects(nCount
,
179 bWaitAll
? WaitAll
: WaitAny
,
182 if (!NT_SUCCESS(Status
))
185 BaseSetLastNTError(Status
);
186 Status
= WAIT_FAILED
;
188 } while ((Status
== STATUS_ALERTED
) && (bAlertable
));
190 /* Check if we didn't use our local buffer */
191 if (HandleBuffer
!= Handle
)
193 /* Free the allocated one */
194 RtlFreeHeap(RtlGetProcessHeap(), 0, HandleBuffer
);
197 /* Cleanup the activation context */
198 if (bAlertable
) RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
200 /* Return wait status */
209 SignalObjectAndWait(IN HANDLE hObjectToSignal
,
210 IN HANDLE hObjectToWaitOn
,
211 IN DWORD dwMilliseconds
,
214 PLARGE_INTEGER TimePtr
;
217 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActCtx
;
219 /* APCs must execute with the default activation context */
222 /* Setup the frame */
223 RtlZeroMemory(&ActCtx
, sizeof(ActCtx
));
224 ActCtx
.Size
= sizeof(ActCtx
);
225 ActCtx
.Format
= RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER
;
226 RtlActivateActivationContextUnsafeFast(&ActCtx
, NULL
);
229 /* Get real handle */
230 hObjectToWaitOn
= TranslateStdHandle(hObjectToWaitOn
);
232 /* Check for console handle */
233 if ((IsConsoleHandle(hObjectToWaitOn
)) &&
234 (VerifyConsoleIoHandle(hObjectToWaitOn
)))
236 /* Get the real wait handle */
237 hObjectToWaitOn
= GetConsoleInputWaitHandle();
240 /* Convert the timeout */
241 TimePtr
= BaseFormatTimeOut(&Time
, dwMilliseconds
);
243 /* Start wait loop */
247 Status
= NtSignalAndWaitForSingleObject(hObjectToSignal
,
251 if (!NT_SUCCESS(Status
))
253 /* The wait failed */
254 BaseSetLastNTError(Status
);
255 Status
= WAIT_FAILED
;
257 } while ((Status
== STATUS_ALERTED
) && (bAlertable
));
259 /* Cleanup the activation context */
260 if (bAlertable
) RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
262 /* Return wait status */
271 CreateWaitableTimerW(IN LPSECURITY_ATTRIBUTES lpTimerAttributes OPTIONAL
,
272 IN BOOL bManualReset
,
273 IN LPCWSTR lpTimerName OPTIONAL
)
275 CreateNtObjectFromWin32Api(WaitableTimer
, Timer
, TIMER
,
278 bManualReset
? NotificationTimer
: SynchronizationTimer
);
286 CreateWaitableTimerA(IN LPSECURITY_ATTRIBUTES lpTimerAttributes OPTIONAL
,
287 IN BOOL bManualReset
,
288 IN LPCSTR lpTimerName OPTIONAL
)
290 ConvertWin32AnsiObjectApiToUnicodeApi(WaitableTimer
, lpTimerName
, lpTimerAttributes
, bManualReset
);
298 OpenWaitableTimerW(IN DWORD dwDesiredAccess
,
299 IN BOOL bInheritHandle
,
300 IN LPCWSTR lpTimerName
)
302 OpenNtObjectFromWin32Api(Timer
, dwDesiredAccess
, bInheritHandle
, lpTimerName
);
310 OpenWaitableTimerA(IN DWORD dwDesiredAccess
,
311 IN BOOL bInheritHandle
,
312 IN LPCSTR lpTimerName
)
314 ConvertOpenWin32AnsiObjectApiToUnicodeApi(WaitableTimer
, dwDesiredAccess
, bInheritHandle
, lpTimerName
);
322 SetWaitableTimer(IN HANDLE hTimer
,
323 IN
const LARGE_INTEGER
*pDueTime
,
325 IN PTIMERAPCROUTINE pfnCompletionRoutine OPTIONAL
,
326 IN OPTIONAL LPVOID lpArgToCompletionRoutine
,
332 Status
= NtSetTimer(hTimer
,
333 (PLARGE_INTEGER
)pDueTime
,
334 (PTIMER_APC_ROUTINE
)pfnCompletionRoutine
,
335 lpArgToCompletionRoutine
,
339 if (NT_SUCCESS(Status
)) return TRUE
;
341 /* If we got here, then we failed */
342 BaseSetLastNTError(Status
);
351 CancelWaitableTimer(IN HANDLE hTimer
)
355 /* Cancel the timer */
356 Status
= NtCancelTimer(hTimer
, NULL
);
357 if (NT_SUCCESS(Status
)) return TRUE
;
359 /* If we got here, then we failed */
360 BaseSetLastNTError(Status
);
369 CreateSemaphoreA(IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes OPTIONAL
,
370 IN LONG lInitialCount
,
371 IN LONG lMaximumCount
,
372 IN LPCSTR lpName OPTIONAL
)
374 ConvertWin32AnsiObjectApiToUnicodeApi(Semaphore
, lpName
, lpSemaphoreAttributes
, lInitialCount
, lMaximumCount
);
382 CreateSemaphoreW(IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes OPTIONAL
,
383 IN LONG lInitialCount
,
384 IN LONG lMaximumCount
,
385 IN LPCWSTR lpName OPTIONAL
)
387 CreateNtObjectFromWin32Api(Semaphore
, Semaphore
, SEMAPHORE
,
388 lpSemaphoreAttributes
,
399 OpenSemaphoreA(IN DWORD dwDesiredAccess
,
400 IN BOOL bInheritHandle
,
403 ConvertOpenWin32AnsiObjectApiToUnicodeApi(Semaphore
, dwDesiredAccess
, bInheritHandle
, lpName
);
411 OpenSemaphoreW(IN DWORD dwDesiredAccess
,
412 IN BOOL bInheritHandle
,
415 OpenNtObjectFromWin32Api(Semaphore
, dwDesiredAccess
, bInheritHandle
, lpName
);
423 ReleaseSemaphore(IN HANDLE hSemaphore
,
424 IN LONG lReleaseCount
,
425 IN LPLONG lpPreviousCount
)
429 /* Release the semaphore */
430 Status
= NtReleaseSemaphore(hSemaphore
, lReleaseCount
, lpPreviousCount
);
431 if (NT_SUCCESS(Status
)) return TRUE
;
433 /* If we got here, then we failed */
434 BaseSetLastNTError(Status
);
443 CreateMutexA(IN LPSECURITY_ATTRIBUTES lpMutexAttributes OPTIONAL
,
444 IN BOOL bInitialOwner
,
445 IN LPCSTR lpName OPTIONAL
)
447 ConvertWin32AnsiObjectApiToUnicodeApi(Mutex
, lpName
, lpMutexAttributes
, bInitialOwner
);
455 CreateMutexW(IN LPSECURITY_ATTRIBUTES lpMutexAttributes OPTIONAL
,
456 IN BOOL bInitialOwner
,
457 IN LPCWSTR lpName OPTIONAL
)
459 CreateNtObjectFromWin32Api(Mutex
, Mutant
, MUTEX
,
470 OpenMutexA(IN DWORD dwDesiredAccess
,
471 IN BOOL bInheritHandle
,
474 ConvertOpenWin32AnsiObjectApiToUnicodeApi(Mutex
, dwDesiredAccess
, bInheritHandle
, lpName
);
482 OpenMutexW(IN DWORD dwDesiredAccess
,
483 IN BOOL bInheritHandle
,
486 OpenNtObjectFromWin32Api(Mutant
, dwDesiredAccess
, bInheritHandle
, lpName
);
494 ReleaseMutex(IN HANDLE hMutex
)
498 /* Release the mutant */
499 Status
= NtReleaseMutant(hMutex
, NULL
);
500 if (NT_SUCCESS(Status
)) return TRUE
;
502 /* If we got here, then we failed */
503 BaseSetLastNTError(Status
);
512 CreateEventA(IN LPSECURITY_ATTRIBUTES lpEventAttributes OPTIONAL
,
513 IN BOOL bManualReset
,
514 IN BOOL bInitialState
,
515 IN LPCSTR lpName OPTIONAL
)
517 ConvertWin32AnsiObjectApiToUnicodeApi(Event
, lpName
, lpEventAttributes
, bManualReset
, bInitialState
);
525 CreateEventW(IN LPSECURITY_ATTRIBUTES lpEventAttributes OPTIONAL
,
526 IN BOOL bManualReset
,
527 IN BOOL bInitialState
,
528 IN LPCWSTR lpName OPTIONAL
)
530 CreateNtObjectFromWin32Api(Event
, Event
, EVENT
,
533 bManualReset
? NotificationTimer
: SynchronizationTimer
,
542 OpenEventA(IN DWORD dwDesiredAccess
,
543 IN BOOL bInheritHandle
,
546 ConvertOpenWin32AnsiObjectApiToUnicodeApi(Event
, dwDesiredAccess
, bInheritHandle
, lpName
);
554 OpenEventW(IN DWORD dwDesiredAccess
,
555 IN BOOL bInheritHandle
,
558 OpenNtObjectFromWin32Api(Event
, dwDesiredAccess
, bInheritHandle
, lpName
);
566 PulseEvent(IN HANDLE hEvent
)
570 /* Pulse the event */
571 Status
= NtPulseEvent(hEvent
, NULL
);
572 if (NT_SUCCESS(Status
)) return TRUE
;
574 /* If we got here, then we failed */
575 BaseSetLastNTError(Status
);
584 ResetEvent(IN HANDLE hEvent
)
588 /* Clear the event */
589 Status
= NtResetEvent(hEvent
, NULL
);
590 if (NT_SUCCESS(Status
)) return TRUE
;
592 /* If we got here, then we failed */
593 BaseSetLastNTError(Status
);
602 SetEvent(IN HANDLE hEvent
)
607 Status
= NtSetEvent(hEvent
, NULL
);
608 if (NT_SUCCESS(Status
)) return TRUE
;
610 /* If we got here, then we failed */
611 BaseSetLastNTError(Status
);
620 InitializeCriticalSection(OUT LPCRITICAL_SECTION lpCriticalSection
)
624 /* Initialize the critical section and raise an exception if we failed */
625 Status
= RtlInitializeCriticalSection((PVOID
)lpCriticalSection
);
626 if (!NT_SUCCESS(Status
)) RtlRaiseStatus(Status
);
634 InitializeCriticalSectionAndSpinCount(OUT LPCRITICAL_SECTION lpCriticalSection
,
635 IN DWORD dwSpinCount
)
639 /* Initialize the critical section */
640 Status
= RtlInitializeCriticalSectionAndSpinCount((PVOID
)lpCriticalSection
,
642 if (!NT_SUCCESS(Status
))
644 /* Set failure code */
645 BaseSetLastNTError(Status
);
658 Sleep(IN DWORD dwMilliseconds
)
660 /* Call the new API */
661 SleepEx(dwMilliseconds
, FALSE
);
670 SleepEx(IN DWORD dwMilliseconds
,
674 PLARGE_INTEGER TimePtr
;
676 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActCtx
;
678 /* APCs must execute with the default activation context */
681 /* Setup the frame */
682 RtlZeroMemory(&ActCtx
, sizeof(ActCtx
));
683 ActCtx
.Size
= sizeof(ActCtx
);
684 ActCtx
.Format
= RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER
;
685 RtlActivateActivationContextUnsafeFast(&ActCtx
, NULL
);
688 /* Convert the timeout */
689 TimePtr
= BaseFormatTimeOut(&Time
, dwMilliseconds
);
692 /* Turn an infinite wait into a really long wait */
694 Time
.HighPart
= 0x80000000;
698 /* Loop the delay while APCs are alerting us */
702 errCode
= NtDelayExecution((BOOLEAN
)bAlertable
, TimePtr
);
704 while ((bAlertable
) && (errCode
== STATUS_ALERTED
));
706 /* Cleanup the activation context */
707 if (bAlertable
) RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
709 /* Return the correct code */
710 return (errCode
== STATUS_USER_APC
) ? WAIT_IO_COMPLETION
: 0;
718 RegisterWaitForSingleObject(OUT PHANDLE phNewWaitObject
,
720 IN WAITORTIMERCALLBACK Callback
,
722 IN ULONG dwMilliseconds
,
727 /* Get real handle */
728 hObject
= TranslateStdHandle(hObject
);
730 /* Check for console handle */
731 if ((IsConsoleHandle(hObject
)) && (VerifyConsoleIoHandle(hObject
)))
733 /* Get the real wait handle */
734 hObject
= GetConsoleInputWaitHandle();
737 /* Register the wait now */
738 Status
= RtlRegisterWait(phNewWaitObject
,
744 if (!NT_SUCCESS(Status
))
747 BaseSetLastNTError(Status
);
760 RegisterWaitForSingleObjectEx(IN HANDLE hObject
,
761 IN WAITORTIMERCALLBACK Callback
,
763 IN ULONG dwMilliseconds
,
767 HANDLE hNewWaitObject
;
769 /* Get real handle */
770 hObject
= TranslateStdHandle(hObject
);
772 /* Check for console handle */
773 if ((IsConsoleHandle(hObject
)) && (VerifyConsoleIoHandle(hObject
)))
775 /* Get the real wait handle */
776 hObject
= GetConsoleInputWaitHandle();
779 /* Register the wait */
780 Status
= RtlRegisterWait(&hNewWaitObject
,
786 if (!NT_SUCCESS(Status
))
789 BaseSetLastNTError(Status
);
793 /* Return the object */
794 return hNewWaitObject
;
802 UnregisterWait(IN HANDLE WaitHandle
)
806 /* Check for invalid handle */
810 SetLastError(ERROR_INVALID_HANDLE
);
814 /* Deregister the wait and check status */
815 Status
= RtlDeregisterWaitEx(WaitHandle
, NULL
);
816 if (!(NT_SUCCESS(Status
)) || (Status
== STATUS_PENDING
))
818 /* Failure or non-blocking call */
819 BaseSetLastNTError(Status
);
832 UnregisterWaitEx(IN HANDLE WaitHandle
,
833 IN HANDLE CompletionEvent
)
837 /* Check for invalid handle */
841 SetLastError(ERROR_INVALID_HANDLE
);
845 /* Deregister the wait and check status */
846 Status
= RtlDeregisterWaitEx(WaitHandle
, CompletionEvent
);
847 if (!(NT_SUCCESS(Status
)) ||
848 ((CompletionEvent
!= INVALID_HANDLE_VALUE
) && (Status
== STATUS_PENDING
)))
850 /* Failure or non-blocking call */
851 BaseSetLastNTError(Status
);