[PATCH] ntdll: Wake one waiter in RtlWakeAddressSingle in futex path.

Daniel Lehman dlehman25 at gmail.com
Mon Sep 9 22:39:50 CDT 2019


Signed-off-by: Daniel Lehman <dlehman25 at gmail.com>
---
 dlls/ntdll/sync.c     | 10 ++++-----
 dlls/ntdll/tests/om.c | 48 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+), 5 deletions(-)

diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c
index 35b89df52e..88fb979b2c 100644
--- a/dlls/ntdll/sync.c
+++ b/dlls/ntdll/sync.c
@@ -2416,7 +2416,7 @@ static inline NTSTATUS fast_wait_addr( const void *addr, const void *cmp, SIZE_T
     return STATUS_SUCCESS;
 }
 
-static inline NTSTATUS fast_wake_addr( const void *addr )
+static inline NTSTATUS fast_wake_addr( const void *addr, int waiters )
 {
     int *futex;
 
@@ -2427,7 +2427,7 @@ static inline NTSTATUS fast_wake_addr( const void *addr )
 
     interlocked_xchg_add( futex, 1 );
 
-    futex_wake( futex, INT_MAX );
+    futex_wake( futex, waiters );
     return STATUS_SUCCESS;
 }
 #else
@@ -2437,7 +2437,7 @@ static inline NTSTATUS fast_wait_addr( const void *addr, const void *cmp, SIZE_T
     return STATUS_NOT_IMPLEMENTED;
 }
 
-static inline NTSTATUS fast_wake_addr( const void *addr )
+static inline NTSTATUS fast_wake_addr( const void *addr, int waiters )
 {
     return STATUS_NOT_IMPLEMENTED;
 }
@@ -2518,7 +2518,7 @@ NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size
  */
 void WINAPI RtlWakeAddressAll( const void *addr )
 {
-    if (fast_wake_addr( addr ) != STATUS_NOT_IMPLEMENTED)
+    if (fast_wake_addr( addr, INT_MAX ) != STATUS_NOT_IMPLEMENTED)
         return;
 
     RtlEnterCriticalSection( &addr_section );
@@ -2531,7 +2531,7 @@ void WINAPI RtlWakeAddressAll( const void *addr )
  */
 void WINAPI RtlWakeAddressSingle( const void *addr )
 {
-    if (fast_wake_addr( addr ) != STATUS_NOT_IMPLEMENTED)
+    if (fast_wake_addr( addr, 1 ) != STATUS_NOT_IMPLEMENTED)
         return;
 
     RtlEnterCriticalSection( &addr_section );
diff --git a/dlls/ntdll/tests/om.c b/dlls/ntdll/tests/om.c
index c17b6ffa8d..8fbcc89718 100644
--- a/dlls/ntdll/tests/om.c
+++ b/dlls/ntdll/tests/om.c
@@ -2148,6 +2148,53 @@ static void test_wait_on_address(void)
     ok(address == 0, "got %s\n", wine_dbgstr_longlong(address));
 }
 
+static LONG wake_single_addr;
+DWORD WINAPI wake_single_thread(void *arg)
+{
+    LONG value;
+    NTSTATUS status;
+
+    value = 0;
+    status = pRtlWaitOnAddress(&wake_single_addr, &value, sizeof(value), NULL);
+    ok(status == STATUS_SUCCESS, "got %x\n", status);
+    return 0;
+}
+
+static void test_wake_single(void)
+{
+    HANDLE threads[16];
+    DWORD ret, nthreads;
+    int i;
+
+    if (!pRtlWaitOnAddress)
+    {
+        win_skip("RtlWaitOnAddress not supported, skipping test\n");
+        return;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(threads); i++)
+        threads[i] = CreateThread(NULL, 0, wake_single_thread, NULL, 0, NULL);
+
+    Sleep(1000); /* wait for threads to enter RtlWaitOnAddress */
+
+    wake_single_addr = 1;
+    nthreads = ARRAY_SIZE(threads);
+    while (nthreads)
+    {
+        pRtlWakeAddressSingle(&wake_single_addr);
+        ret = WaitForMultipleObjects(nthreads, threads, FALSE, 2000);
+        ok(ret < WAIT_OBJECT_0 + nthreads, "got %u\n", ret);
+        CloseHandle(threads[ret]);
+        memmove(&threads[ret], &threads[ret+1], (nthreads - ret - 1) * sizeof(threads[0]));
+        if (--nthreads)
+        {
+            /* make sure other threads are still waiting */
+            ret = WaitForMultipleObjects(nthreads, threads, FALSE, 0);
+            ok(ret == WAIT_TIMEOUT, "got %u\n", ret);
+        }
+    }
+}
+
 START_TEST(om)
 {
     HMODULE hntdll = GetModuleHandleA("ntdll.dll");
@@ -2221,4 +2268,5 @@ START_TEST(om)
     test_keyed_events();
     test_null_device();
     test_wait_on_address();
+    test_wake_single();
 }
-- 
2.17.1




More information about the wine-devel mailing list