[PATCH 1/2] ntdll: Implement RtlWaitOnAddress functions.

Daniel Lehman dlehman25 at gmail.com
Fri Oct 26 01:50:14 CDT 2018


Signed-off-by: Daniel Lehman <dlehman25 at gmail.com>
---
 dlls/ntdll/ntdll.spec |  3 ++
 dlls/ntdll/sync.c     | 64 +++++++++++++++++++++++++++++++++
 dlls/ntdll/tests/om.c | 83 +++++++++++++++++++++++++++++++++++++++++++
 include/winternl.h    |  3 ++
 4 files changed, 153 insertions(+)

diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index 247f05f561..818ae0090c 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 4ae8e36ce0..dc6f7ecf32 100644
--- a/dlls/ntdll/sync.c
+++ b/dlls/ntdll/sync.c
@@ -1955,3 +1955,67 @@ NTSTATUS WINAPI RtlSleepConditionVariableSRW( RTL_CONDITION_VARIABLE *variable,
         RtlAcquireSRWLockExclusive( lock );
     return status;
 }
+
+static HANDLE woa_event;
+static RTL_RUN_ONCE init_once_woa = RTL_RUN_ONCE_INIT;
+static DWORD WINAPI init_woa( RTL_RUN_ONCE *once, void *param, void **context )
+{
+    NtCreateKeyedEvent( &woa_event, GENERIC_READ|GENERIC_WRITE, NULL, 0 );
+    return TRUE;
+}
+
+/***********************************************************************
+ *           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;
+    }
+
+    RtlRunOnceExecuteOnce( &init_once_woa, init_woa, NULL, NULL );
+    return NtWaitForKeyedEvent( woa_event, addr, 0, timeout );
+}
+
+/***********************************************************************
+ *           RtlWakeAddressAll    (NTDLL.@)
+ */
+void WINAPI RtlWakeAddressAll( const void *addr )
+{
+    LARGE_INTEGER now;
+
+    RtlRunOnceExecuteOnce( &init_once_woa, init_woa, NULL, NULL );
+    NtQuerySystemTime( &now );
+    while (NtReleaseKeyedEvent( woa_event, addr, 0, &now ) == STATUS_SUCCESS) {}
+}
+
+/***********************************************************************
+ *           RtlWakeAddressSingle (NTDLL.@)
+ */
+void WINAPI RtlWakeAddressSingle( const void *addr )
+{
+    LARGE_INTEGER now;
+
+    RtlRunOnceExecuteOnce( &init_once_woa, init_woa, NULL, NULL );
+    NtQuerySystemTime( &now );
+    NtReleaseKeyedEvent( woa_event, addr, 0, &now );
+}
diff --git a/dlls/ntdll/tests/om.c b/dlls/ntdll/tests/om.c
index 524085474d..b83a8fc841 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,80 @@ 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 += (LONGLONG)1000*10000;
+    ticks = GetTickCount();
+    status = pRtlWaitOnAddress(&address, &compare, 8, &timeout);
+    ticks = GetTickCount() - ticks;
+    ok(status == STATUS_TIMEOUT, "got 0x%08x\n", status);
+    ok(ticks >= 1000 && ticks <= 1500, "got %u\n", ticks);
+    ok(address == 0, "got %ld\n", address);
+    ok(compare == 0, "got %ld\n", compare);
+
+    /* different address size */
+    for (size = 1; size <= 4; size <<= 1)
+    {
+        compare = ~0;
+        compare <<= size * 8;
+
+        pNtQuerySystemTime(&timeout);
+        timeout.QuadPart += (LONGLONG)1000 * 10000;
+        ticks = GetTickCount();
+        status = pRtlWaitOnAddress(&address, &compare, size, &timeout);
+        ticks = GetTickCount() - ticks;
+        ok(status == STATUS_TIMEOUT, "got 0x%08x\n", status);
+        ok(ticks >= 1000 && ticks <= 1500, "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 %ld\n", address);
+    pRtlWakeAddressAll(&address);
+    ok(address == 0, "got %ld\n", address);
+}
+
 START_TEST(om)
 {
     HMODULE hntdll = GetModuleHandleA("ntdll.dll");
@@ -2117,6 +2195,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 +2212,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 1cec3cfc96..9c8861334a 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);
-- 
2.17.1




More information about the wine-devel mailing list