Signed-off-by: Daniel Lehman dlehman25@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(); }