https://git.reactos.org/?p=reactos.git;a=commitdiff;h=f491d7cc99ecaf156b47b…
commit f491d7cc99ecaf156b47baf33e3d9933a7f49e6e
Author: Ratin Gao <ratin(a)knsoft.org>
AuthorDate: Thu Sep 7 06:40:53 2023 +0800
Commit: GitHub <noreply(a)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 <ratin(a)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 <ratin(a)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 );
}