https://git.reactos.org/?p=reactos.git;a=commitdiff;h=f491d7cc99ecaf156b47baf33e3d9933a7f49e6e

commit f491d7cc99ecaf156b47baf33e3d9933a7f49e6e
Author:     Ratin Gao <ra...@knsoft.org>
AuthorDate: Thu Sep 7 06:40:53 2023 +0800
Commit:     GitHub <nore...@github.com>
CommitDate: Wed Sep 6 15:40:53 2023 -0700

    [KERNEL32][RTL] Implement One-Time initialization API and improve RTL 
support (#5046)
    
    * [KERNEL32][RTL] Implement One-Time initialization API and improve RTL 
support
---
 dll/win32/kernel32/kernel32.spec                   |   6 +-
 dll/win32/kernel32/kernel32_vista/CMakeLists.txt   |   2 +-
 dll/win32/kernel32/kernel32_vista/InitOnce.c       |  62 +++++
 .../kernel32/kernel32_vista/InitOnceExecuteOnce.c  |  19 --
 .../kernel32/kernel32_vista/kernel32_vista.spec    |   4 +
 modules/rostests/apitests/kernel32/CMakeLists.txt  |   1 +
 modules/rostests/apitests/kernel32/InitOnce.c      | 280 +++++++++++++++++++++
 modules/rostests/apitests/kernel32/testlist.c      |   2 +
 sdk/include/ndk/rtlfuncs.h                         |  37 +++
 sdk/include/psdk/winbase.h                         |  37 ++-
 sdk/include/xdk/winnt_old.h                        |  10 +-
 sdk/lib/rtl/runonce.c                              |  77 +++---
 12 files changed, 472 insertions(+), 65 deletions(-)

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 <ra...@knsoft.org>
+ */
+
+#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 <ndk/exfuncs.h>
-#include <wine/config.h>
-#include <wine/port.h>
-
-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 <ra...@knsoft.org>
+ */
+
+#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 );
 }

Reply via email to