From 25acfbb40b5316a8c87989d4e61ce9edef2a04aa Mon Sep 17 00:00:00 2001 From: Daniel Lehman Date: Thu, 25 Oct 2018 23:50:14 -0700 Subject: [PATCH] ntdll: Implement RtlWaitOnAddress functions. Signed-off-by: Daniel Lehman Signed-off-by: Alexandre Julliard --- dlls/ntdll/ntdll.spec | 3 ++ dlls/ntdll/sync.c | 49 ++++++++++++++++++++++++++ dlls/ntdll/tests/om.c | 82 +++++++++++++++++++++++++++++++++++++++++++ include/winternl.h | 3 ++ 4 files changed, 137 insertions(+) diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 247f05f5619..818ae0090cf 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -978,6 +978,9 @@ # @ stub RtlValidateUnicodeString @ stdcall RtlVerifyVersionInfo(ptr long int64) @ stdcall -arch=x86_64 RtlVirtualUnwind(long long long ptr ptr ptr ptr ptr) +@ stdcall RtlWaitOnAddress(ptr ptr long ptr) +@ stdcall RtlWakeAddressAll(ptr) +@ stdcall RtlWakeAddressSingle(ptr) @ stdcall RtlWakeAllConditionVariable(ptr) @ stdcall RtlWakeConditionVariable(ptr) @ stub RtlWalkFrameChain diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c index 4ae8e36ce04..1bfaaab60e4 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c @@ -61,6 +61,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(ntdll); HANDLE keyed_event = NULL; +static const LARGE_INTEGER zero_timeout; + static inline int interlocked_dec_if_nonzero( int *dest ) { int val, tmp; @@ -1955,3 +1957,50 @@ NTSTATUS WINAPI RtlSleepConditionVariableSRW( RTL_CONDITION_VARIABLE *variable, RtlAcquireSRWLockExclusive( lock ); return status; } + +/*********************************************************************** + * RtlWaitOnAddress (NTDLL.@) + */ +NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size, + const LARGE_INTEGER *timeout ) +{ + switch (size) + { + case 1: + if (*(const UCHAR *)addr != *(const UCHAR *)cmp) + return STATUS_SUCCESS; + break; + case 2: + if (*(const USHORT *)addr != *(const USHORT *)cmp) + return STATUS_SUCCESS; + break; + case 4: + if (*(const ULONG *)addr != *(const ULONG *)cmp) + return STATUS_SUCCESS; + break; + case 8: + if (*(const ULONG64 *)addr != *(const ULONG64 *)cmp) + return STATUS_SUCCESS; + break; + default: + return STATUS_INVALID_PARAMETER; + } + + return NtWaitForKeyedEvent( keyed_event, addr, 0, timeout ); +} + +/*********************************************************************** + * RtlWakeAddressAll (NTDLL.@) + */ +void WINAPI RtlWakeAddressAll( const void *addr ) +{ + while (NtReleaseKeyedEvent( keyed_event, addr, 0, &zero_timeout ) == STATUS_SUCCESS) {} +} + +/*********************************************************************** + * RtlWakeAddressSingle (NTDLL.@) + */ +void WINAPI RtlWakeAddressSingle( const void *addr ) +{ + NtReleaseKeyedEvent( keyed_event, addr, 0, &zero_timeout ); +} diff --git a/dlls/ntdll/tests/om.c b/dlls/ntdll/tests/om.c index 524085474d7..4d879b00c32 100644 --- a/dlls/ntdll/tests/om.c +++ b/dlls/ntdll/tests/om.c @@ -70,6 +70,10 @@ static NTSTATUS (WINAPI *pNtReleaseKeyedEvent)( HANDLE, const void *, BOOLEAN, c static NTSTATUS (WINAPI *pNtCreateIoCompletion)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, ULONG); static NTSTATUS (WINAPI *pNtOpenIoCompletion)( PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES ); static NTSTATUS (WINAPI *pNtQueryInformationFile)(HANDLE, PIO_STATUS_BLOCK, void *, ULONG, FILE_INFORMATION_CLASS); +static NTSTATUS (WINAPI *pNtQuerySystemTime)( LARGE_INTEGER * ); +static NTSTATUS (WINAPI *pRtlWaitOnAddress)( const void *, const void *, SIZE_T, const LARGE_INTEGER * ); +static void (WINAPI *pRtlWakeAddressAll)( const void * ); +static void (WINAPI *pRtlWakeAddressSingle)( const void * ); #define KEYEDEVENT_WAIT 0x0001 #define KEYEDEVENT_WAKE 0x0002 @@ -2064,6 +2068,79 @@ static void test_mutant(void) NtClose( mutant ); } +static void test_wait_on_address(void) +{ + DWORD ticks; + SIZE_T size; + NTSTATUS status; + LARGE_INTEGER timeout; + LONG64 address, compare; + + if (!pRtlWaitOnAddress) + { + win_skip("RtlWaitOnAddress not supported, skipping test\n"); + return; + } + + if (0) /* crash on Windows */ + { + pRtlWaitOnAddress(&address, NULL, 8, NULL); + pRtlWaitOnAddress(NULL, &compare, 8, NULL); + pRtlWaitOnAddress(NULL, NULL, 8, NULL); + } + + /* don't crash */ + pRtlWakeAddressSingle(NULL); + pRtlWakeAddressAll(NULL); + + /* invalid values */ + address = 0; + compare = 0; + status = pRtlWaitOnAddress(&address, &compare, 5, NULL); + ok(status == STATUS_INVALID_PARAMETER, "got %x\n", status); + + /* values match */ + address = 0; + compare = 0; + pNtQuerySystemTime(&timeout); + timeout.QuadPart += 100*10000; + ticks = GetTickCount(); + status = pRtlWaitOnAddress(&address, &compare, 8, &timeout); + ticks = GetTickCount() - ticks; + ok(status == STATUS_TIMEOUT, "got 0x%08x\n", status); + ok(ticks >= 100 && ticks <= 1000, "got %u\n", ticks); + ok(address == 0, "got %s\n", wine_dbgstr_longlong(address)); + ok(compare == 0, "got %s\n", wine_dbgstr_longlong(compare)); + + /* different address size */ + for (size = 1; size <= 4; size <<= 1) + { + compare = ~0; + compare <<= size * 8; + + timeout.QuadPart = -100 * 10000; + ticks = GetTickCount(); + status = pRtlWaitOnAddress(&address, &compare, size, &timeout); + ticks = GetTickCount() - ticks; + ok(status == STATUS_TIMEOUT, "got 0x%08x\n", status); + ok(ticks >= 100 && ticks <= 1000, "got %u\n", ticks); + + status = pRtlWaitOnAddress(&address, &compare, size << 1, &timeout); + ok(!status, "got 0x%08x\n", status); + } + address = 0; + compare = 1; + status = pRtlWaitOnAddress(&address, &compare, 8, NULL); + ok(!status, "got 0x%08x\n", status); + + /* no waiters */ + address = 0; + pRtlWakeAddressSingle(&address); + ok(address == 0, "got %s\n", wine_dbgstr_longlong(address)); + pRtlWakeAddressAll(&address); + ok(address == 0, "got %s\n", wine_dbgstr_longlong(address)); +} + START_TEST(om) { HMODULE hntdll = GetModuleHandleA("ntdll.dll"); @@ -2117,6 +2194,10 @@ START_TEST(om) pNtCreateIoCompletion = (void *)GetProcAddress(hntdll, "NtCreateIoCompletion"); pNtOpenIoCompletion = (void *)GetProcAddress(hntdll, "NtOpenIoCompletion"); pNtQueryInformationFile = (void *)GetProcAddress(hntdll, "NtQueryInformationFile"); + pNtQuerySystemTime = (void *)GetProcAddress(hntdll, "NtQuerySystemTime"); + pRtlWaitOnAddress = (void *)GetProcAddress(hntdll, "RtlWaitOnAddress"); + pRtlWakeAddressAll = (void *)GetProcAddress(hntdll, "RtlWakeAddressAll"); + pRtlWakeAddressSingle = (void *)GetProcAddress(hntdll, "RtlWakeAddressSingle"); test_case_sensitive(); test_namespace_pipe(); @@ -2130,4 +2211,5 @@ START_TEST(om) test_mutant(); test_keyed_events(); test_null_device(); + test_wait_on_address(); } diff --git a/include/winternl.h b/include/winternl.h index 1cec3cfc966..9c8861334a1 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -2865,6 +2865,9 @@ NTSYSAPI BOOLEAN WINAPI RtlValidAcl(PACL); NTSYSAPI BOOLEAN WINAPI RtlValidSid(PSID); NTSYSAPI BOOLEAN WINAPI RtlValidateHeap(HANDLE,ULONG,LPCVOID); NTSYSAPI NTSTATUS WINAPI RtlVerifyVersionInfo(const RTL_OSVERSIONINFOEXW*,DWORD,DWORDLONG); +NTSYSAPI NTSTATUS WINAPI RtlWaitOnAddress(const void *,const void *,SIZE_T,const LARGE_INTEGER *); +NTSYSAPI void WINAPI RtlWakeAddressAll(const void *); +NTSYSAPI void WINAPI RtlWakeAddressSingle(const void *); NTSYSAPI void WINAPI RtlWakeAllConditionVariable(RTL_CONDITION_VARIABLE *); NTSYSAPI void WINAPI RtlWakeConditionVariable(RTL_CONDITION_VARIABLE *); NTSYSAPI NTSTATUS WINAPI RtlWalkHeap(HANDLE,PVOID);