diff --git a/dll/win32/kernel32/kernel32.spec b/dll/win32/kernel32/kernel32.spec index e72f99fb295..c4583be816f 100644 --- a/dll/win32/kernel32/kernel32.spec +++ b/dll/win32/kernel32/kernel32.spec @@ -708,10 +708,10 @@ @ stdcall -stub -version=0x600+ IdnToNameprepUnicode(long wstr long ptr long) @ stdcall -stub -version=0x600+ IdnToUnicode(long wstr long ptr long) @ stdcall InitAtomTable(long) -@ stdcall -stub -version=0x600+ InitOnceBeginInitialize(ptr long ptr ptr) -@ stdcall -stub -version=0x600+ InitOnceComplete(ptr long ptr) +@ stdcall -version=0x600+ InitOnceBeginInitialize(ptr long ptr ptr) +@ stdcall -version=0x600+ InitOnceComplete(ptr long ptr) @ stdcall -version=0x600+ InitOnceExecuteOnce(ptr ptr ptr ptr) -@ stdcall -stub -version=0x600+ InitOnceInitialize(ptr) +@ stdcall -version=0x600+ InitOnceInitialize(ptr) NTDLL.RtlRunOnceInitialize @ stdcall -version=0x600+ InitializeConditionVariable(ptr) ntdll.RtlInitializeConditionVariable @ stdcall InitializeCriticalSection(ptr) @ stdcall InitializeCriticalSectionAndSpinCount(ptr long) diff --git a/dll/win32/kernel32/kernel32_vista/CMakeLists.txt b/dll/win32/kernel32/kernel32_vista/CMakeLists.txt index acc53b9d80a..3b2b8e735b7 100644 --- a/dll/win32/kernel32/kernel32_vista/CMakeLists.txt +++ b/dll/win32/kernel32/kernel32_vista/CMakeLists.txt @@ -9,7 +9,7 @@ spec2def(kernel32_vista.dll kernel32_vista.spec ADD_IMPORTLIB) list(APPEND SOURCE GetFileInformationByHandleEx.c GetTickCount64.c - InitOnceExecuteOnce.c + InitOnce.c sync.c vista.c) diff --git a/dll/win32/kernel32/kernel32_vista/InitOnce.c b/dll/win32/kernel32/kernel32_vista/InitOnce.c new file mode 100644 index 00000000000..339c157286c --- /dev/null +++ b/dll/win32/kernel32/kernel32_vista/InitOnce.c @@ -0,0 +1,62 @@ +/* + * PROJECT: ReactOS Win32 Base API + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: One-Time initialization API + * COPYRIGHT: Copyright 2023 Ratin Gao + */ + +#include "k32_vista.h" + +BOOL +WINAPI +InitOnceExecuteOnce( + _Inout_ PINIT_ONCE InitOnce, + _In_ __callback PINIT_ONCE_FN InitFn, + _Inout_opt_ PVOID Parameter, + _Outptr_opt_result_maybenull_ LPVOID *Context) +{ + return NT_SUCCESS(RtlRunOnceExecuteOnce(InitOnce, + (PRTL_RUN_ONCE_INIT_FN)InitFn, + Parameter, + Context)); +} + +BOOL +WINAPI +InitOnceBeginInitialize( + _Inout_ LPINIT_ONCE lpInitOnce, + _In_ DWORD dwFlags, + _Out_ PBOOL fPending, + _Outptr_opt_result_maybenull_ LPVOID *lpContext) +{ + NTSTATUS Status; + + Status = RtlRunOnceBeginInitialize(lpInitOnce, dwFlags, lpContext); + if (!NT_SUCCESS(Status)) + { + BaseSetLastNTError(Status); + return FALSE; + } + + *fPending = (Status == STATUS_PENDING); + return TRUE; +} + +BOOL +WINAPI +InitOnceComplete( + _Inout_ LPINIT_ONCE lpInitOnce, + _In_ DWORD dwFlags, + _In_opt_ LPVOID lpContext) +{ + NTSTATUS Status; + + Status = RtlRunOnceComplete(lpInitOnce, dwFlags, lpContext); + if (!NT_SUCCESS(Status)) + { + BaseSetLastNTError(Status); + return FALSE; + } + + return TRUE; +} diff --git a/dll/win32/kernel32/kernel32_vista/InitOnceExecuteOnce.c b/dll/win32/kernel32/kernel32_vista/InitOnceExecuteOnce.c deleted file mode 100644 index 1ef59160aef..00000000000 --- a/dll/win32/kernel32/kernel32_vista/InitOnceExecuteOnce.c +++ /dev/null @@ -1,19 +0,0 @@ - -#include "k32_vista.h" - -#include -#include -#include - -DWORD WINAPI RtlRunOnceExecuteOnce( RTL_RUN_ONCE *once, PRTL_RUN_ONCE_INIT_FN func, - void *param, void **context ); - -/* Taken from Wine kernel32/sync.c */ - -/* - * @implemented - */ -BOOL NTAPI InitOnceExecuteOnce( INIT_ONCE *once, PINIT_ONCE_FN func, void *param, void **context ) -{ - return !RtlRunOnceExecuteOnce( once, (PRTL_RUN_ONCE_INIT_FN)func, param, context ); -} diff --git a/dll/win32/kernel32/kernel32_vista/kernel32_vista.spec b/dll/win32/kernel32/kernel32_vista/kernel32_vista.spec index 02c1cb05739..bf074328323 100644 --- a/dll/win32/kernel32/kernel32_vista/kernel32_vista.spec +++ b/dll/win32/kernel32/kernel32_vista/kernel32_vista.spec @@ -1,5 +1,9 @@ +@ stdcall InitOnceBeginInitialize(ptr long ptr ptr) +@ stdcall InitOnceComplete(ptr long ptr) @ stdcall InitOnceExecuteOnce(ptr ptr ptr ptr) +@ stdcall InitOnceInitialize(ptr) NTDLL.RtlRunOnceInitialize + @ stdcall GetFileInformationByHandleEx(long long ptr long) @ stdcall -ret64 GetTickCount64() diff --git a/modules/rostests/apitests/kernel32/CMakeLists.txt b/modules/rostests/apitests/kernel32/CMakeLists.txt index 9aebaa979a5..8c26b340edc 100644 --- a/modules/rostests/apitests/kernel32/CMakeLists.txt +++ b/modules/rostests/apitests/kernel32/CMakeLists.txt @@ -18,6 +18,7 @@ list(APPEND SOURCE GetDriveType.c GetModuleFileName.c GetVolumeInformation.c + InitOnce.c interlck.c IsDBCSLeadByteEx.c JapaneseCalendar.c diff --git a/modules/rostests/apitests/kernel32/InitOnce.c b/modules/rostests/apitests/kernel32/InitOnce.c new file mode 100644 index 00000000000..586e87bac9d --- /dev/null +++ b/modules/rostests/apitests/kernel32/InitOnce.c @@ -0,0 +1,280 @@ +/* + * PROJECT: ReactOS API tests + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Tests for One-Time initialization APIs + * COPYRIGHT: Copyright 2023 Ratin Gao + */ + +#include "precomp.h" + +typedef +VOID +WINAPI +FN_InitOnceInitialize(_Out_ PINIT_ONCE InitOnce); + +typedef +BOOL +WINAPI +FN_InitOnceExecuteOnce( + _Inout_ PINIT_ONCE InitOnce, + _In_ __callback PINIT_ONCE_FN InitFn, + _Inout_opt_ PVOID Parameter, + _Outptr_opt_result_maybenull_ LPVOID *Context); + +typedef +BOOL +WINAPI +FN_InitOnceBeginInitialize( + _Inout_ LPINIT_ONCE lpInitOnce, + _In_ DWORD dwFlags, + _Out_ PBOOL fPending, + _Outptr_opt_result_maybenull_ LPVOID *lpContext); + +typedef +BOOL +WINAPI +FN_InitOnceComplete( + _Inout_ LPINIT_ONCE lpInitOnce, + _In_ DWORD dwFlags, + _In_opt_ LPVOID lpContext); + +static ULONG g_ulRandom; + +static +VOID +InitWorker(_Inout_ PULONG InitCount, _Out_ PULONG_PTR Context) +{ + /* Increase the initialization count */ + (*InitCount)++; + + /* Output context data */ + *Context = (ULONG_PTR)g_ulRandom; +} + +static +_Success_(return != FALSE) +BOOL +WINAPI +InitOnceProc( + _Inout_ PINIT_ONCE InitOnce, + _Inout_opt_ PVOID Parameter, + _Outptr_opt_result_maybenull_ PVOID* Context) +{ + if (!Parameter || !Context) + { + return FALSE; + } + + InitWorker(Parameter, (PULONG_PTR)Context); + return TRUE; +} + +START_TEST(InitOnce) +{ + BOOL bRet, fPending; + ULONG i, ulInitCount, ulSeed, ulContextData; + ULONG_PTR ulTempContext; + DWORD dwError; + + HMODULE hKernel32; + FN_InitOnceInitialize* pfnInitOnceInitialize; + FN_InitOnceExecuteOnce* pfnInitOnceExecuteOnce; + FN_InitOnceBeginInitialize* pfnInitOnceBeginInitialize; + FN_InitOnceComplete* pfnInitOnceComplete; + + /* Load functions */ + hKernel32 = GetModuleHandleW(L"kernel32.dll"); + if (!hKernel32) + { + skip("Module kernel32 not found\n"); + return; + } + pfnInitOnceInitialize = (FN_InitOnceInitialize*)GetProcAddress(hKernel32, "InitOnceInitialize"); + pfnInitOnceExecuteOnce = (FN_InitOnceExecuteOnce*)GetProcAddress(hKernel32, "InitOnceExecuteOnce"); + pfnInitOnceBeginInitialize = (FN_InitOnceBeginInitialize*)GetProcAddress(hKernel32, "InitOnceBeginInitialize"); + pfnInitOnceComplete = (FN_InitOnceComplete*)GetProcAddress(hKernel32, "InitOnceComplete"); + + /* + * Use a random as output context data, + * which the low-order INIT_ONCE_CTX_RESERVED_BITS bits should be zero. + */ + ulSeed = (ULONG)(ULONG_PTR)&ulSeed ^ GetTickCount(); + g_ulRandom = RtlRandom(&ulSeed); + for (i = 0; i < INIT_ONCE_CTX_RESERVED_BITS; i++) + { + g_ulRandom &= (~(1 << i)); + } + + /* Initialize One-Time initialization structure */ + INIT_ONCE InitOnce = { (PVOID)(ULONG_PTR)0xDEADBEEF }; + if (pfnInitOnceInitialize) + { + pfnInitOnceInitialize(&InitOnce); + } + else + { + skip("InitOnceInitialize not found\n"); + InitOnce = (INIT_ONCE)INIT_ONCE_STATIC_INIT; + } + + if (!pfnInitOnceExecuteOnce) + { + skip("InitOnceExecuteOnce not found\n"); + goto _test_sync; + } + + /* + * Perform synchronous initialization by using InitOnceExecuteOnce, + * which executes user-defined callback to initialize. + * Call InitOnceExecuteOnce twice will success, + * initialization count should be 1 and retrieve correct context data. + */ + ulInitCount = 0; + ulContextData = MAXULONG; + bRet = pfnInitOnceExecuteOnce(&InitOnce, InitOnceProc, &ulInitCount, (LPVOID*)&ulContextData); + ok(bRet, "InitOnceExecuteOnce failed with %lu\n", GetLastError()); + if (bRet) + { + /* Call InitOnceExecuteOnce again and check output values if the first call succeeded */ + bRet = pfnInitOnceExecuteOnce(&InitOnce, + InitOnceProc, + &ulInitCount, + (LPVOID*)&ulContextData); + ok(bRet, "InitOnceExecuteOnce failed with %lu\n", GetLastError()); + ok(ulInitCount == 1, "ulInitCount is not 1\n"); + ok(ulContextData == g_ulRandom, "Output ulContextData is incorrect\n"); + } + +_test_sync: + if (!pfnInitOnceBeginInitialize || !pfnInitOnceComplete) + { + skip("InitOnceBeginInitialize or InitOnceComplete not found\n"); + return; + } + + /* Re-initialize One-Time initialization structure by using INIT_ONCE_STATIC_INIT */ + InitOnce = (INIT_ONCE)INIT_ONCE_STATIC_INIT; + + /* Perform synchronous initialization by using InitOnceBeginInitialize */ + fPending = FALSE; + bRet = pfnInitOnceBeginInitialize(&InitOnce, 0, &fPending, (LPVOID*)&ulContextData); + ok(bRet, "InitOnceBeginInitialize failed with %lu\n", GetLastError()); + if (!bRet) + { + goto _test_async; + } + ok(fPending, "fPending is not TRUE after the first success InitOnceBeginInitialize\n"); + if (!fPending) + { + goto _test_async; + } + + /* Complete the initialization */ + InitWorker(&ulInitCount, &ulTempContext); + bRet = pfnInitOnceComplete(&InitOnce, 0, (LPVOID)ulTempContext); + ok(bRet, "InitOnceComplete failed with %lu\n", GetLastError()); + if (!bRet) + { + goto _test_async; + } + + /* + * Initialization is completed, call InitOnceBeginInitialize with + * INIT_ONCE_CHECK_ONLY should retrieve status and context data successfully + */ + bRet = pfnInitOnceBeginInitialize(&InitOnce, + INIT_ONCE_CHECK_ONLY, + &fPending, + (LPVOID*)&ulContextData); + ok(bRet && !fPending && ulContextData == g_ulRandom, + "InitOnceBeginInitialize returns incorrect result for a completed initialization\n"); + +_test_async: + InitOnce = (INIT_ONCE)INIT_ONCE_STATIC_INIT; + + /* Perform asynchronous initialization */ + fPending = FALSE; + bRet = pfnInitOnceBeginInitialize(&InitOnce, + INIT_ONCE_ASYNC, + &fPending, + (LPVOID*)&ulContextData); + ok(bRet, "InitOnceBeginInitialize failed with %lu\n", GetLastError()); + if (!bRet) + { + return; + } + ok(fPending, "fPending is not TRUE after a success InitOnceBeginInitialize\n"); + if (!fPending) + { + return; + } + + /* + * Now the initialization is in progress but not completed yet, + * call InitOnceBeginInitialize again without INIT_ONCE_ASYNC is invalid, + * should fail with ERROR_INVALID_PARAMETER + */ + bRet = pfnInitOnceBeginInitialize(&InitOnce, 0, &fPending, (LPVOID*)&ulContextData); + ok(!bRet, "InitOnceBeginInitialize should not success\n"); + if (!bRet) + { + dwError = GetLastError(); + ok(dwError == ERROR_INVALID_PARAMETER, + "Last error is %lu, but %u is expected\n", + dwError, + ERROR_INVALID_PARAMETER); + } + + /* + * Call InitOnceBeginInitialize again with INIT_ONCE_ASYNC + * should success because initialization could be executed in parallel + */ + bRet = pfnInitOnceBeginInitialize(&InitOnce, + INIT_ONCE_ASYNC, + &fPending, + (LPVOID*)&ulContextData); + ok(bRet, "InitOnceBeginInitialize failed with %lu\n", GetLastError()); + if (!bRet) + { + return; + } + ok(fPending, "fPending is not TRUE after a success InitOnceBeginInitialize\n"); + if (!fPending) + { + return; + } + + /* Complete the initialization once */ + InitWorker(&ulInitCount, &ulTempContext); + bRet = pfnInitOnceComplete(&InitOnce, INIT_ONCE_ASYNC, (LPVOID)ulTempContext); + ok(bRet, "InitOnceComplete failed with %lu\n", GetLastError()); + if (!bRet) + { + return; + } + + /* Subsequent InitOnceComplete should fail with ERROR_GEN_FAILURE */ + bRet = pfnInitOnceComplete(&InitOnce, INIT_ONCE_ASYNC, (LPVOID)ulTempContext); + ok(!bRet, "InitOnceComplete should not success\n"); + if (!bRet) + { + dwError = GetLastError(); + ok(dwError == ERROR_GEN_FAILURE, + "Last error is %lu, but %u is expected\n", + dwError, + ERROR_GEN_FAILURE); + } + + /* + * Initialization is completed, call InitOnceBeginInitialize with + * INIT_ONCE_CHECK_ONLY should retrieve status and context data successfully + */ + bRet = pfnInitOnceBeginInitialize(&InitOnce, + INIT_ONCE_CHECK_ONLY, + &fPending, + (LPVOID*)&ulContextData); + ok(bRet && !fPending && ulContextData == g_ulRandom, + "InitOnceBeginInitialize returns incorrect result for a completed initialization\n"); + + return; +} diff --git a/modules/rostests/apitests/kernel32/testlist.c b/modules/rostests/apitests/kernel32/testlist.c index b96dfa956f0..4802d88079c 100644 --- a/modules/rostests/apitests/kernel32/testlist.c +++ b/modules/rostests/apitests/kernel32/testlist.c @@ -18,6 +18,7 @@ extern void func_GetCurrentDirectory(void); extern void func_GetDriveType(void); extern void func_GetModuleFileName(void); extern void func_GetVolumeInformation(void); +extern void func_InitOnce(void); extern void func_interlck(void); extern void func_IsDBCSLeadByteEx(void); extern void func_JapaneseCalendar(void); @@ -53,6 +54,7 @@ const struct test winetest_testlist[] = { "GetDriveType", func_GetDriveType }, { "GetModuleFileName", func_GetModuleFileName }, { "GetVolumeInformation", func_GetVolumeInformation }, + { "InitOnce", func_InitOnce }, { "interlck", func_interlck }, { "IsDBCSLeadByteEx", func_IsDBCSLeadByteEx }, { "JapaneseCalendar", func_JapaneseCalendar }, diff --git a/sdk/include/ndk/rtlfuncs.h b/sdk/include/ndk/rtlfuncs.h index 47830b87990..41aedeb7e2d 100644 --- a/sdk/include/ndk/rtlfuncs.h +++ b/sdk/include/ndk/rtlfuncs.h @@ -4961,6 +4961,43 @@ RtlGetNativeSystemInformation( _Out_opt_ PULONG ReturnLength ); +#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA) || (DLL_EXPORT_VERSION >= _WIN32_WINNT_VISTA) + +NTSYSAPI +VOID +NTAPI +RtlRunOnceInitialize( + _Out_ PRTL_RUN_ONCE RunOnce); + +_Maybe_raises_SEH_exception_ +NTSYSAPI +NTSTATUS +NTAPI +RtlRunOnceExecuteOnce( + _Inout_ PRTL_RUN_ONCE RunOnce, + _In_ __inner_callback PRTL_RUN_ONCE_INIT_FN InitFn, + _Inout_opt_ PVOID Parameter, + _Outptr_opt_result_maybenull_ PVOID *Context); + +_Must_inspect_result_ +NTSYSAPI +NTSTATUS +NTAPI +RtlRunOnceBeginInitialize( + _Inout_ PRTL_RUN_ONCE RunOnce, + _In_ ULONG Flags, + _Outptr_opt_result_maybenull_ PVOID *Context); + +NTSYSAPI +NTSTATUS +NTAPI +RtlRunOnceComplete( + _Inout_ PRTL_RUN_ONCE RunOnce, + _In_ ULONG Flags, + _In_opt_ PVOID Context); + +#endif + #if (_WIN32_WINNT >= _WIN32_WINNT_VISTA) || (defined(__REACTOS__) && defined(_NTDLLBUILD_)) /* Put NTSYSAPI back when this will be really exported. Only statically linked for now */ // NTSYSAPI diff --git a/sdk/include/psdk/winbase.h b/sdk/include/psdk/winbase.h index 4872e40d98b..6b616b07b39 100644 --- a/sdk/include/psdk/winbase.h +++ b/sdk/include/psdk/winbase.h @@ -3837,6 +3837,8 @@ typedef PRTL_RUN_ONCE LPINIT_ONCE; #define INIT_ONCE_ASYNC RTL_RUN_ONCE_ASYNC #define INIT_ONCE_INIT_FAILED RTL_RUN_ONCE_INIT_FAILED +#define INIT_ONCE_CTX_RESERVED_BITS RTL_RUN_ONCE_CTX_RESERVED_BITS + typedef BOOL (WINAPI *PINIT_ONCE_FN)( _Inout_ PINIT_ONCE InitOnce, @@ -3961,14 +3963,41 @@ CopyFile2( #endif /* _WIN32_WINNT >= 0x0601 */ +#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA) || (DLL_EXPORT_VERSION >= _WIN32_WINNT_VISTA) + +WINBASEAPI +VOID +WINAPI +InitOnceInitialize( + _Out_ PINIT_ONCE InitOnce); + +WINBASEAPI +BOOL +WINAPI +InitOnceBeginInitialize( + _Inout_ LPINIT_ONCE lpInitOnce, + _In_ DWORD dwFlags, + _Out_ PBOOL fPending, + _Outptr_opt_result_maybenull_ LPVOID *lpContext); + +WINBASEAPI +BOOL +WINAPI +InitOnceComplete( + _Inout_ LPINIT_ONCE lpInitOnce, + _In_ DWORD dwFlags, + _In_opt_ LPVOID lpContext); + +#endif /* (_WIN32_WINNT >= _WIN32_WINNT_VISTA) || (DLL_EXPORT_VERSION >= _WIN32_WINNT_VISTA) */ + WINBASEAPI BOOL WINAPI InitOnceExecuteOnce( - _Inout_ PINIT_ONCE InitOnce, - _In_ __callback PINIT_ONCE_FN InitFn, - _Inout_opt_ PVOID Parameter, - _Outptr_opt_result_maybenull_ LPVOID *Context); + _Inout_ PINIT_ONCE InitOnce, + _In_ __callback PINIT_ONCE_FN InitFn, + _Inout_opt_ PVOID Parameter, + _Outptr_opt_result_maybenull_ LPVOID *Context); #if defined(_SLIST_HEADER_) && !defined(_NTOS_) && !defined(_NTOSP_) diff --git a/sdk/include/xdk/winnt_old.h b/sdk/include/xdk/winnt_old.h index 8e0de26a3da..7e564277b9a 100644 --- a/sdk/include/xdk/winnt_old.h +++ b/sdk/include/xdk/winnt_old.h @@ -2778,6 +2778,8 @@ RtlQueryDepthSList( #define RTL_RUN_ONCE_ASYNC 0x00000002UL #define RTL_RUN_ONCE_INIT_FAILED 0x00000004UL +#define RTL_RUN_ONCE_CTX_RESERVED_BITS 2 + #define RTL_RUN_ONCE_INIT {0} typedef union _RTL_RUN_ONCE { @@ -2787,14 +2789,6 @@ typedef union _RTL_RUN_ONCE { typedef DWORD WINAPI RTL_RUN_ONCE_INIT_FN(PRTL_RUN_ONCE, PVOID, PVOID*); typedef RTL_RUN_ONCE_INIT_FN *PRTL_RUN_ONCE_INIT_FN; -NTSYSAPI -DWORD -WINAPI -RtlRunOnceComplete( - PRTL_RUN_ONCE, - DWORD, - PVOID); - #endif #define RTL_CONDITION_VARIABLE_INIT {0} diff --git a/sdk/lib/rtl/runonce.c b/sdk/lib/rtl/runonce.c index 0ffa49b9fa4..da970e9febd 100644 --- a/sdk/lib/rtl/runonce.c +++ b/sdk/lib/rtl/runonce.c @@ -8,52 +8,58 @@ /****************************************************************** * RtlRunOnceInitialize (NTDLL.@) */ -void WINAPI RtlRunOnceInitialize( RTL_RUN_ONCE *once ) +VOID NTAPI RtlRunOnceInitialize(_Out_ PRTL_RUN_ONCE RunOnce) { - once->Ptr = NULL; + RunOnce->Ptr = NULL; } /****************************************************************** * RtlRunOnceBeginInitialize (NTDLL.@) */ -DWORD WINAPI RtlRunOnceBeginInitialize( RTL_RUN_ONCE *once, ULONG flags, void **context ) +_Must_inspect_result_ +NTSTATUS +NTAPI +RtlRunOnceBeginInitialize( + _Inout_ PRTL_RUN_ONCE RunOnce, + _In_ ULONG Flags, + _Outptr_opt_result_maybenull_ PVOID *Context) { - if (flags & RTL_RUN_ONCE_CHECK_ONLY) + if (Flags & RTL_RUN_ONCE_CHECK_ONLY) { - ULONG_PTR val = (ULONG_PTR)once->Ptr; + ULONG_PTR val = (ULONG_PTR)RunOnce->Ptr; - if (flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER; + if (Flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER; if ((val & 3) != 2) return STATUS_UNSUCCESSFUL; - if (context) *context = (void *)(val & ~3); + if (Context) *Context = (void *)(val & ~3); return STATUS_SUCCESS; } for (;;) { - ULONG_PTR next, val = (ULONG_PTR)once->Ptr; + ULONG_PTR next, val = (ULONG_PTR)RunOnce->Ptr; switch (val & 3) { case 0: /* first time */ - if (!interlocked_cmpxchg_ptr( &once->Ptr, - (flags & RTL_RUN_ONCE_ASYNC) ? (void *)3 : (void *)1, 0 )) + if (!interlocked_cmpxchg_ptr( &RunOnce->Ptr, + (Flags & RTL_RUN_ONCE_ASYNC) ? (void *)3 : (void *)1, 0)) return STATUS_PENDING; break; case 1: /* in progress, wait */ - if (flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER; + if (Flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER; next = val & ~3; - if (interlocked_cmpxchg_ptr( &once->Ptr, (void *)((ULONG_PTR)&next | 1), + if (interlocked_cmpxchg_ptr( &RunOnce->Ptr, (void *)((ULONG_PTR)&next | 1), (void *)val ) == (void *)val) NtWaitForKeyedEvent( 0, &next, FALSE, NULL ); break; case 2: /* done */ - if (context) *context = (void *)(val & ~3); + if (Context) *Context = (void *)(val & ~3); return STATUS_SUCCESS; case 3: /* in progress, async */ - if (!(flags & RTL_RUN_ONCE_ASYNC)) return STATUS_INVALID_PARAMETER; + if (!(Flags & RTL_RUN_ONCE_ASYNC)) return STATUS_INVALID_PARAMETER; return STATUS_PENDING; } } @@ -62,25 +68,30 @@ DWORD WINAPI RtlRunOnceBeginInitialize( RTL_RUN_ONCE *once, ULONG flags, void ** /****************************************************************** * RtlRunOnceComplete (NTDLL.@) */ -DWORD WINAPI RtlRunOnceComplete( RTL_RUN_ONCE *once, ULONG flags, void *context ) +NTSTATUS +NTAPI +RtlRunOnceComplete( + _Inout_ PRTL_RUN_ONCE RunOnce, + _In_ ULONG Flags, + _In_opt_ PVOID Context) { - if ((ULONG_PTR)context & 3) return STATUS_INVALID_PARAMETER; + if ((ULONG_PTR)Context & 3) return STATUS_INVALID_PARAMETER; - if (flags & RTL_RUN_ONCE_INIT_FAILED) + if (Flags & RTL_RUN_ONCE_INIT_FAILED) { - if (context) return STATUS_INVALID_PARAMETER; - if (flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER; + if (Context) return STATUS_INVALID_PARAMETER; + if (Flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER; } - else context = (void *)((ULONG_PTR)context | 2); + else Context = (void *)((ULONG_PTR)Context | 2); for (;;) { - ULONG_PTR val = (ULONG_PTR)once->Ptr; + ULONG_PTR val = (ULONG_PTR)RunOnce->Ptr; switch (val & 3) { case 1: /* in progress */ - if (interlocked_cmpxchg_ptr( &once->Ptr, context, (void *)val ) != (void *)val) break; + if (interlocked_cmpxchg_ptr( &RunOnce->Ptr, Context, (void *)val ) != (void *)val) break; val &= ~3; while (val) { @@ -91,8 +102,8 @@ DWORD WINAPI RtlRunOnceComplete( RTL_RUN_ONCE *once, ULONG flags, void *context return STATUS_SUCCESS; case 3: /* in progress, async */ - if (!(flags & RTL_RUN_ONCE_ASYNC)) return STATUS_INVALID_PARAMETER; - if (interlocked_cmpxchg_ptr( &once->Ptr, context, (void *)val ) != (void *)val) break; + if (!(Flags & RTL_RUN_ONCE_ASYNC)) return STATUS_INVALID_PARAMETER; + if (interlocked_cmpxchg_ptr( &RunOnce->Ptr, Context, (void *)val) != (void *)val) break; return STATUS_SUCCESS; default: @@ -104,18 +115,24 @@ DWORD WINAPI RtlRunOnceComplete( RTL_RUN_ONCE *once, ULONG flags, void *context /****************************************************************** * RtlRunOnceExecuteOnce (NTDLL.@) */ -DWORD WINAPI RtlRunOnceExecuteOnce( RTL_RUN_ONCE *once, PRTL_RUN_ONCE_INIT_FN func, - void *param, void **context ) +_Maybe_raises_SEH_exception_ +NTSTATUS +NTAPI +RtlRunOnceExecuteOnce( + _Inout_ PRTL_RUN_ONCE RunOnce, + _In_ __inner_callback PRTL_RUN_ONCE_INIT_FN InitFn, + _Inout_opt_ PVOID Parameter, + _Outptr_opt_result_maybenull_ PVOID *Context) { - DWORD ret = RtlRunOnceBeginInitialize( once, 0, context ); + DWORD ret = RtlRunOnceBeginInitialize( RunOnce, 0, Context ); if (ret != STATUS_PENDING) return ret; - if (!func( once, param, context )) + if (!InitFn( RunOnce, Parameter, Context )) { - RtlRunOnceComplete( once, RTL_RUN_ONCE_INIT_FAILED, NULL ); + RtlRunOnceComplete( RunOnce, RTL_RUN_ONCE_INIT_FAILED, NULL ); return STATUS_UNSUCCESSFUL; } - return RtlRunOnceComplete( once, 0, context ? *context : NULL ); + return RtlRunOnceComplete( RunOnce, 0, Context ? *Context : NULL ); }