[PATCH 2/2] kernelbase: Add WaitOnAddress functions.

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


Signed-off-by: Daniel Lehman <dlehman25 at gmail.com>
---
 dlls/kernelbase/kernelbase.spec   |   6 +-
 dlls/kernelbase/main.c            |  29 +++++
 dlls/kernelbase/tests/Makefile.in |   3 +-
 dlls/kernelbase/tests/sync.c      | 186 ++++++++++++++++++++++++++++++
 include/synchapi.h                |  34 ++++++
 include/winbase.h                 |   1 +
 6 files changed, 255 insertions(+), 4 deletions(-)
 create mode 100644 dlls/kernelbase/tests/sync.c
 create mode 100644 include/synchapi.h

diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec
index e12f14bf42..e01f109823 100644
--- a/dlls/kernelbase/kernelbase.spec
+++ b/dlls/kernelbase/kernelbase.spec
@@ -1696,10 +1696,10 @@
 @ stdcall WaitForThreadpoolWorkCallbacks(ptr long) kernel32.WaitForThreadpoolWorkCallbacks
 # @ stub WaitForUserPolicyForegroundProcessingInternal
 @ stdcall WaitNamedPipeW(wstr long) kernel32.WaitNamedPipeW
-# @ stub WaitOnAddress
+@ stdcall WaitOnAddress(ptr ptr long long)
 @ stdcall WakeAllConditionVariable(ptr) kernel32.WakeAllConditionVariable
-# @ stub WakeByAddressAll
-# @ stub WakeByAddressSingle
+@ stdcall WakeByAddressAll(ptr) ntdll.RtlWakeAddressAll
+@ stdcall WakeByAddressSingle(ptr) ntdll.RtlWakeAddressSingle
 @ stdcall WakeConditionVariable(ptr) kernel32.WakeConditionVariable
 # @ stub WerGetFlags
 @ stdcall WerRegisterFile(wstr long long) kernel32.WerRegisterFile
diff --git a/dlls/kernelbase/main.c b/dlls/kernelbase/main.c
index 6871aca41a..031a00d63a 100644
--- a/dlls/kernelbase/main.c
+++ b/dlls/kernelbase/main.c
@@ -17,10 +17,13 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
 #include "windows.h"
 #include "appmodel.h"
 
 #include "wine/debug.h"
+#include "winternl.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(kernelbase);
 
@@ -97,3 +100,29 @@ BOOL WINAPI QuirkIsEnabled3(void *unk1, void *unk2)
 
     return FALSE;
 }
+
+/***********************************************************************
+ *           WaitOnAddress   (KERNELBASE.@)
+ */
+BOOL WINAPI WaitOnAddress(volatile void *addr, void *cmp, SIZE_T size, DWORD timeout)
+{
+    LARGE_INTEGER to;
+    NTSTATUS status;
+
+    if (timeout != INFINITE)
+    {
+        NtQuerySystemTime(&to);
+        to.QuadPart += (LONGLONG)timeout*10000;
+        status = RtlWaitOnAddress((const void *)addr, cmp, size, &to);
+    }
+    else
+        status = RtlWaitOnAddress((const void *)addr, cmp, size, NULL);
+
+    if (status != STATUS_SUCCESS)
+    {
+        SetLastError( RtlNtStatusToDosError(status) );
+        return FALSE;
+    }
+
+    return TRUE;
+}
diff --git a/dlls/kernelbase/tests/Makefile.in b/dlls/kernelbase/tests/Makefile.in
index ac8e1fcaa6..22e4a17a58 100644
--- a/dlls/kernelbase/tests/Makefile.in
+++ b/dlls/kernelbase/tests/Makefile.in
@@ -1,4 +1,5 @@
 TESTDLL   = kernelbase.dll
 
 C_SRCS = \
-	path.c
+	path.c \
+	sync.c
diff --git a/dlls/kernelbase/tests/sync.c b/dlls/kernelbase/tests/sync.c
new file mode 100644
index 0000000000..7b80a7e61d
--- /dev/null
+++ b/dlls/kernelbase/tests/sync.c
@@ -0,0 +1,186 @@
+/*
+ * Synchronization tests
+ *
+ * Copyright 2018 Daniel Lehman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+#include <windef.h>
+#include <winbase.h>
+#include <stdlib.h>
+#include <winerror.h>
+
+#include "wine/test.h"
+
+static BOOL (WINAPI *pWaitOnAddress)(volatile void *, void *, SIZE_T, DWORD);
+static void (WINAPI *pWakeByAddressAll)(void *);
+static void (WINAPI *pWakeByAddressSingle)(void *);
+
+static LONG64 address;
+static LONG64 compare;
+static DWORD WINAPI test_WaitOnAddress_func(void *arg)
+{
+    BOOL ret = FALSE;
+    DWORD gle;
+    while (address == compare)
+    {
+        SetLastError(0xdeadbeef);
+        ret = pWaitOnAddress(&address, &compare, sizeof(compare), INFINITE);
+        gle = GetLastError();
+        ok(gle == 0xdeadbeef || broken(gle == ERROR_SUCCESS) /* Win 8 */, "got %d\n", gle);
+    }
+    ok(ret, "got %d\n", ret);
+    return 0;
+}
+
+static void test_WaitOnAddress(void)
+{
+    DWORD gle, val, nthreads;
+    HANDLE threads[8];
+    BOOL ret;
+
+    if (!pWaitOnAddress)
+    {
+        win_skip("WaitOnAddress not supported, skipping test\n");
+        return;
+    }
+
+    address = 0;
+    compare = 0;
+    if (0) /* crash on Windows */
+    {
+        ret = pWaitOnAddress(&address, NULL, 8, 0);
+        ret = pWaitOnAddress(NULL, &compare, 8, 0);
+    }
+
+    /* invalid arguments */
+    SetLastError(0xdeadbeef);
+    pWakeByAddressSingle(NULL);
+    gle = GetLastError();
+    ok(gle == 0xdeadbeef, "got %d\n", gle);
+
+    SetLastError(0xdeadbeef);
+    pWakeByAddressAll(NULL);
+    gle = GetLastError();
+    ok(gle == 0xdeadbeef, "got %d\n", gle);
+
+    SetLastError(0xdeadbeef);
+    ret = pWaitOnAddress(NULL, NULL, 0, 0);
+    gle = GetLastError();
+    ok(gle == ERROR_INVALID_PARAMETER, "got %d\n", gle);
+    ok(!ret, "got %d\n", ret);
+
+    address = 0;
+    compare = 0;
+    SetLastError(0xdeadbeef);
+    ret = pWaitOnAddress(&address, &compare, 5, 0);
+    gle = GetLastError();
+    ok(gle == ERROR_INVALID_PARAMETER, "got %d\n", gle);
+    ok(!ret, "got %d\n", ret);
+    ok(address == 0, "got %ld\n", address);
+    ok(compare == 0, "got %ld\n", compare);
+
+    /* no waiters */
+    address = 0;
+    SetLastError(0xdeadbeef);
+    pWakeByAddressSingle(&address);
+    gle = GetLastError();
+    ok(gle == 0xdeadbeef, "got %d\n", gle);
+    ok(address == 0, "got %ld\n", address);
+
+    SetLastError(0xdeadbeef);
+    pWakeByAddressAll(&address);
+    gle = GetLastError();
+    ok(gle == 0xdeadbeef, "got %d\n", gle);
+    ok(address == 0, "got %ld\n", address);
+
+    /* different address size */
+    address = 0;
+    compare = 0xffff0000;
+    SetLastError(0xdeadbeef);
+    ret = pWaitOnAddress(&address, &compare, 4, 0);
+    gle = GetLastError();
+    ok(gle == 0xdeadbeef || broken(gle == ERROR_SUCCESS) /* Win 8 */, "got %d\n", gle);
+    ok(ret, "got %d\n", ret);
+
+    SetLastError(0xdeadbeef);
+    ret = pWaitOnAddress(&address, &compare, 2, 0);
+    gle = GetLastError();
+    ok(gle == ERROR_TIMEOUT, "got %d\n", gle);
+    ok(!ret, "got %d\n", ret);
+
+    /* simple wait case */
+    address = 0;
+    compare = 1;
+    SetLastError(0xdeadbeef);
+    ret = pWaitOnAddress(&address, &compare, 8, 0);
+    gle = GetLastError();
+    ok(gle == 0xdeadbeef || broken(gle == ERROR_SUCCESS) /* Win 8 */, "got %d\n", gle);
+    ok(ret, "got %d\n", ret);
+
+    /* WakeByAddressAll */
+    address = 0;
+    compare = 0;
+    for (int i = 0; i < ARRAY_SIZE(threads); i++)
+        threads[i] = CreateThread(NULL, 0, test_WaitOnAddress_func, NULL, 0, NULL);
+
+    Sleep(1000);
+    address = ~0;
+    pWakeByAddressAll(&address);
+    val = WaitForMultipleObjects(ARRAY_SIZE(threads), threads, TRUE, 5000);
+    ok(val == WAIT_OBJECT_0, "got %d\n", val);
+    for (int i = 0; i < ARRAY_SIZE(threads); i++)
+        CloseHandle(threads[i]);
+
+    /* WakeByAddressSingle */
+    address = 0;
+    for (int i = 0; i < ARRAY_SIZE(threads); i++)
+        threads[i] = CreateThread(NULL, 0, test_WaitOnAddress_func, NULL, 0, NULL);
+
+    Sleep(1000);
+    address = 1;
+    nthreads = ARRAY_SIZE(threads);
+    while (nthreads)
+    {
+        val = WaitForMultipleObjects(nthreads, threads, FALSE, 0);
+        ok(val == STATUS_TIMEOUT, "got %u\n", val);
+
+        pWakeByAddressSingle(&address);
+        val = WaitForMultipleObjects(nthreads, threads, FALSE, 2000);
+        ok(val < WAIT_OBJECT_0 + nthreads, "got %u\n", val);
+        CloseHandle(threads[val]);
+        memmove(&threads[val], &threads[val+1], (nthreads - val - 1) * sizeof(threads[0]));
+        nthreads--;
+    }
+
+}
+
+START_TEST(sync)
+{
+    HMODULE hmod;
+
+    hmod = LoadLibraryA("kernel32.dll");
+    pWaitOnAddress       = (void *)GetProcAddress(hmod, "WaitOnAddress");
+    ok(!pWaitOnAddress, "expected only in kernelbase.dll\n");
+
+    hmod = LoadLibraryA("kernelbase.dll");
+    pWaitOnAddress       = (void *)GetProcAddress(hmod, "WaitOnAddress");
+    pWakeByAddressAll    = (void *)GetProcAddress(hmod, "WakeByAddressAll");
+    pWakeByAddressSingle = (void *)GetProcAddress(hmod, "WakeByAddressSingle");
+
+    test_WaitOnAddress();
+}
diff --git a/include/synchapi.h b/include/synchapi.h
new file mode 100644
index 0000000000..124a53a8b2
--- /dev/null
+++ b/include/synchapi.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2018 Daniel Lehman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __WINE_SYNCHAPI_H
+#define __WINE_SYNCHAPI_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+BOOL WINAPI WaitOnAddress(volatile void*, void*, SIZE_T, DWORD);
+void WINAPI WakeByAddressAll(void*);
+void WINAPI WakeByAddressSingle(void*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* __WINE_SYNCHAPI_H */
diff --git a/include/winbase.h b/include/winbase.h
index c38da9c158..d4fc108534 100644
--- a/include/winbase.h
+++ b/include/winbase.h
@@ -38,6 +38,7 @@ extern "C" {
 #endif
 
 #include <libloaderapi.h>
+#include <synchapi.h>
 
   /* Windows Exit Procedure flag values */
 #define	WEP_FREE_DLL        0
-- 
2.17.1




More information about the wine-devel mailing list