mirror of
https://github.com/reactos/reactos.git
synced 2025-06-17 00:58:30 +00:00
[KERNEL32][RTL] Implement One-Time initialization API and improve RTL support (#5046)
* [KERNEL32][RTL] Implement One-Time initialization API and improve RTL support
This commit is contained in:
parent
583be404dd
commit
f491d7cc99
12 changed files with 472 additions and 65 deletions
|
@ -708,10 +708,10 @@
|
||||||
@ stdcall -stub -version=0x600+ IdnToNameprepUnicode(long wstr long ptr long)
|
@ stdcall -stub -version=0x600+ IdnToNameprepUnicode(long wstr long ptr long)
|
||||||
@ stdcall -stub -version=0x600+ IdnToUnicode(long wstr long ptr long)
|
@ stdcall -stub -version=0x600+ IdnToUnicode(long wstr long ptr long)
|
||||||
@ stdcall InitAtomTable(long)
|
@ stdcall InitAtomTable(long)
|
||||||
@ stdcall -stub -version=0x600+ InitOnceBeginInitialize(ptr long ptr ptr)
|
@ stdcall -version=0x600+ InitOnceBeginInitialize(ptr long ptr ptr)
|
||||||
@ stdcall -stub -version=0x600+ InitOnceComplete(ptr long ptr)
|
@ stdcall -version=0x600+ InitOnceComplete(ptr long ptr)
|
||||||
@ stdcall -version=0x600+ InitOnceExecuteOnce(ptr ptr ptr 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 -version=0x600+ InitializeConditionVariable(ptr) ntdll.RtlInitializeConditionVariable
|
||||||
@ stdcall InitializeCriticalSection(ptr)
|
@ stdcall InitializeCriticalSection(ptr)
|
||||||
@ stdcall InitializeCriticalSectionAndSpinCount(ptr long)
|
@ stdcall InitializeCriticalSectionAndSpinCount(ptr long)
|
||||||
|
|
|
@ -9,7 +9,7 @@ spec2def(kernel32_vista.dll kernel32_vista.spec ADD_IMPORTLIB)
|
||||||
list(APPEND SOURCE
|
list(APPEND SOURCE
|
||||||
GetFileInformationByHandleEx.c
|
GetFileInformationByHandleEx.c
|
||||||
GetTickCount64.c
|
GetTickCount64.c
|
||||||
InitOnceExecuteOnce.c
|
InitOnce.c
|
||||||
sync.c
|
sync.c
|
||||||
vista.c)
|
vista.c)
|
||||||
|
|
||||||
|
|
62
dll/win32/kernel32/kernel32_vista/InitOnce.c
Normal file
62
dll/win32/kernel32/kernel32_vista/InitOnce.c
Normal file
|
@ -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@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;
|
||||||
|
}
|
|
@ -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 );
|
|
||||||
}
|
|
|
@ -1,5 +1,9 @@
|
||||||
|
|
||||||
|
@ stdcall InitOnceBeginInitialize(ptr long ptr ptr)
|
||||||
|
@ stdcall InitOnceComplete(ptr long ptr)
|
||||||
@ stdcall InitOnceExecuteOnce(ptr ptr ptr ptr)
|
@ stdcall InitOnceExecuteOnce(ptr ptr ptr ptr)
|
||||||
|
@ stdcall InitOnceInitialize(ptr) NTDLL.RtlRunOnceInitialize
|
||||||
|
|
||||||
@ stdcall GetFileInformationByHandleEx(long long ptr long)
|
@ stdcall GetFileInformationByHandleEx(long long ptr long)
|
||||||
@ stdcall -ret64 GetTickCount64()
|
@ stdcall -ret64 GetTickCount64()
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ list(APPEND SOURCE
|
||||||
GetDriveType.c
|
GetDriveType.c
|
||||||
GetModuleFileName.c
|
GetModuleFileName.c
|
||||||
GetVolumeInformation.c
|
GetVolumeInformation.c
|
||||||
|
InitOnce.c
|
||||||
interlck.c
|
interlck.c
|
||||||
IsDBCSLeadByteEx.c
|
IsDBCSLeadByteEx.c
|
||||||
JapaneseCalendar.c
|
JapaneseCalendar.c
|
||||||
|
|
280
modules/rostests/apitests/kernel32/InitOnce.c
Normal file
280
modules/rostests/apitests/kernel32/InitOnce.c
Normal file
|
@ -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@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;
|
||||||
|
}
|
|
@ -18,6 +18,7 @@ extern void func_GetCurrentDirectory(void);
|
||||||
extern void func_GetDriveType(void);
|
extern void func_GetDriveType(void);
|
||||||
extern void func_GetModuleFileName(void);
|
extern void func_GetModuleFileName(void);
|
||||||
extern void func_GetVolumeInformation(void);
|
extern void func_GetVolumeInformation(void);
|
||||||
|
extern void func_InitOnce(void);
|
||||||
extern void func_interlck(void);
|
extern void func_interlck(void);
|
||||||
extern void func_IsDBCSLeadByteEx(void);
|
extern void func_IsDBCSLeadByteEx(void);
|
||||||
extern void func_JapaneseCalendar(void);
|
extern void func_JapaneseCalendar(void);
|
||||||
|
@ -53,6 +54,7 @@ const struct test winetest_testlist[] =
|
||||||
{ "GetDriveType", func_GetDriveType },
|
{ "GetDriveType", func_GetDriveType },
|
||||||
{ "GetModuleFileName", func_GetModuleFileName },
|
{ "GetModuleFileName", func_GetModuleFileName },
|
||||||
{ "GetVolumeInformation", func_GetVolumeInformation },
|
{ "GetVolumeInformation", func_GetVolumeInformation },
|
||||||
|
{ "InitOnce", func_InitOnce },
|
||||||
{ "interlck", func_interlck },
|
{ "interlck", func_interlck },
|
||||||
{ "IsDBCSLeadByteEx", func_IsDBCSLeadByteEx },
|
{ "IsDBCSLeadByteEx", func_IsDBCSLeadByteEx },
|
||||||
{ "JapaneseCalendar", func_JapaneseCalendar },
|
{ "JapaneseCalendar", func_JapaneseCalendar },
|
||||||
|
|
|
@ -4961,6 +4961,43 @@ RtlGetNativeSystemInformation(
|
||||||
_Out_opt_ PULONG ReturnLength
|
_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_))
|
#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA) || (defined(__REACTOS__) && defined(_NTDLLBUILD_))
|
||||||
/* Put NTSYSAPI back when this will be really exported. Only statically linked for now */
|
/* Put NTSYSAPI back when this will be really exported. Only statically linked for now */
|
||||||
// NTSYSAPI
|
// NTSYSAPI
|
||||||
|
|
|
@ -3837,6 +3837,8 @@ typedef PRTL_RUN_ONCE LPINIT_ONCE;
|
||||||
#define INIT_ONCE_ASYNC RTL_RUN_ONCE_ASYNC
|
#define INIT_ONCE_ASYNC RTL_RUN_ONCE_ASYNC
|
||||||
#define INIT_ONCE_INIT_FAILED RTL_RUN_ONCE_INIT_FAILED
|
#define INIT_ONCE_INIT_FAILED RTL_RUN_ONCE_INIT_FAILED
|
||||||
|
|
||||||
|
#define INIT_ONCE_CTX_RESERVED_BITS RTL_RUN_ONCE_CTX_RESERVED_BITS
|
||||||
|
|
||||||
typedef BOOL
|
typedef BOOL
|
||||||
(WINAPI *PINIT_ONCE_FN)(
|
(WINAPI *PINIT_ONCE_FN)(
|
||||||
_Inout_ PINIT_ONCE InitOnce,
|
_Inout_ PINIT_ONCE InitOnce,
|
||||||
|
@ -3961,14 +3963,41 @@ CopyFile2(
|
||||||
|
|
||||||
#endif /* _WIN32_WINNT >= 0x0601 */
|
#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
|
WINBASEAPI
|
||||||
BOOL
|
BOOL
|
||||||
WINAPI
|
WINAPI
|
||||||
InitOnceExecuteOnce(
|
InitOnceExecuteOnce(
|
||||||
_Inout_ PINIT_ONCE InitOnce,
|
_Inout_ PINIT_ONCE InitOnce,
|
||||||
_In_ __callback PINIT_ONCE_FN InitFn,
|
_In_ __callback PINIT_ONCE_FN InitFn,
|
||||||
_Inout_opt_ PVOID Parameter,
|
_Inout_opt_ PVOID Parameter,
|
||||||
_Outptr_opt_result_maybenull_ LPVOID *Context);
|
_Outptr_opt_result_maybenull_ LPVOID *Context);
|
||||||
|
|
||||||
|
|
||||||
#if defined(_SLIST_HEADER_) && !defined(_NTOS_) && !defined(_NTOSP_)
|
#if defined(_SLIST_HEADER_) && !defined(_NTOS_) && !defined(_NTOSP_)
|
||||||
|
|
|
@ -2778,6 +2778,8 @@ RtlQueryDepthSList(
|
||||||
#define RTL_RUN_ONCE_ASYNC 0x00000002UL
|
#define RTL_RUN_ONCE_ASYNC 0x00000002UL
|
||||||
#define RTL_RUN_ONCE_INIT_FAILED 0x00000004UL
|
#define RTL_RUN_ONCE_INIT_FAILED 0x00000004UL
|
||||||
|
|
||||||
|
#define RTL_RUN_ONCE_CTX_RESERVED_BITS 2
|
||||||
|
|
||||||
#define RTL_RUN_ONCE_INIT {0}
|
#define RTL_RUN_ONCE_INIT {0}
|
||||||
|
|
||||||
typedef union _RTL_RUN_ONCE {
|
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 DWORD WINAPI RTL_RUN_ONCE_INIT_FN(PRTL_RUN_ONCE, PVOID, PVOID*);
|
||||||
typedef RTL_RUN_ONCE_INIT_FN *PRTL_RUN_ONCE_INIT_FN;
|
typedef RTL_RUN_ONCE_INIT_FN *PRTL_RUN_ONCE_INIT_FN;
|
||||||
|
|
||||||
NTSYSAPI
|
|
||||||
DWORD
|
|
||||||
WINAPI
|
|
||||||
RtlRunOnceComplete(
|
|
||||||
PRTL_RUN_ONCE,
|
|
||||||
DWORD,
|
|
||||||
PVOID);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define RTL_CONDITION_VARIABLE_INIT {0}
|
#define RTL_CONDITION_VARIABLE_INIT {0}
|
||||||
|
|
|
@ -8,52 +8,58 @@
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
* RtlRunOnceInitialize (NTDLL.@)
|
* 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.@)
|
* 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 ((val & 3) != 2) return STATUS_UNSUCCESSFUL;
|
||||||
if (context) *context = (void *)(val & ~3);
|
if (Context) *Context = (void *)(val & ~3);
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
ULONG_PTR next, val = (ULONG_PTR)once->Ptr;
|
ULONG_PTR next, val = (ULONG_PTR)RunOnce->Ptr;
|
||||||
|
|
||||||
switch (val & 3)
|
switch (val & 3)
|
||||||
{
|
{
|
||||||
case 0: /* first time */
|
case 0: /* first time */
|
||||||
if (!interlocked_cmpxchg_ptr( &once->Ptr,
|
if (!interlocked_cmpxchg_ptr( &RunOnce->Ptr,
|
||||||
(flags & RTL_RUN_ONCE_ASYNC) ? (void *)3 : (void *)1, 0 ))
|
(Flags & RTL_RUN_ONCE_ASYNC) ? (void *)3 : (void *)1, 0))
|
||||||
return STATUS_PENDING;
|
return STATUS_PENDING;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1: /* in progress, wait */
|
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;
|
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)
|
(void *)val ) == (void *)val)
|
||||||
NtWaitForKeyedEvent( 0, &next, FALSE, NULL );
|
NtWaitForKeyedEvent( 0, &next, FALSE, NULL );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2: /* done */
|
case 2: /* done */
|
||||||
if (context) *context = (void *)(val & ~3);
|
if (Context) *Context = (void *)(val & ~3);
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
|
|
||||||
case 3: /* in progress, async */
|
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;
|
return STATUS_PENDING;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,25 +68,30 @@ DWORD WINAPI RtlRunOnceBeginInitialize( RTL_RUN_ONCE *once, ULONG flags, void **
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
* RtlRunOnceComplete (NTDLL.@)
|
* 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 (Context) return STATUS_INVALID_PARAMETER;
|
||||||
if (flags & RTL_RUN_ONCE_ASYNC) 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 (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
ULONG_PTR val = (ULONG_PTR)once->Ptr;
|
ULONG_PTR val = (ULONG_PTR)RunOnce->Ptr;
|
||||||
|
|
||||||
switch (val & 3)
|
switch (val & 3)
|
||||||
{
|
{
|
||||||
case 1: /* in progress */
|
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;
|
val &= ~3;
|
||||||
while (val)
|
while (val)
|
||||||
{
|
{
|
||||||
|
@ -91,8 +102,8 @@ DWORD WINAPI RtlRunOnceComplete( RTL_RUN_ONCE *once, ULONG flags, void *context
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
|
|
||||||
case 3: /* in progress, async */
|
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;
|
||||||
if (interlocked_cmpxchg_ptr( &once->Ptr, context, (void *)val ) != (void *)val) break;
|
if (interlocked_cmpxchg_ptr( &RunOnce->Ptr, Context, (void *)val) != (void *)val) break;
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -104,18 +115,24 @@ DWORD WINAPI RtlRunOnceComplete( RTL_RUN_ONCE *once, ULONG flags, void *context
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
* RtlRunOnceExecuteOnce (NTDLL.@)
|
* RtlRunOnceExecuteOnce (NTDLL.@)
|
||||||
*/
|
*/
|
||||||
DWORD WINAPI RtlRunOnceExecuteOnce( RTL_RUN_ONCE *once, PRTL_RUN_ONCE_INIT_FN func,
|
_Maybe_raises_SEH_exception_
|
||||||
void *param, void **context )
|
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 (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 STATUS_UNSUCCESSFUL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return RtlRunOnceComplete( once, 0, context ? *context : NULL );
|
return RtlRunOnceComplete( RunOnce, 0, Context ? *Context : NULL );
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue