[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