[PATCH] ntoskrnl.exe/tests: Move kernel test utils to wine/test.h.

Rémi Bernon rbernon at codeweavers.com
Thu Jul 1 08:33:05 CDT 2021


So that we can have full featured wine test with thread local data and
context.

Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---

I don't know what was going on with [1] and following patches but Marvin
reported a succeeded todo_wine on a test that isn't even marked todo.

I suspect there's some sort of thread conflict happening and this should
fix such issues, see [2] without vs [3] with this patch.

We also miss winetest_push_context / winetest_pop_context and all the
possible improvements done to winetest, so I think it's good to have
this factored together.

I've left winetest_elapsed aside, as it requires KeQueryTickCount, which
isn't exported on Windows. I don't think it's very important to have it
anyway, as we don't even pass winetest_time yet to the driver.

Sorry in advance for the amount of time this will take if Marvin decides
to run everything...

[1] https://testbot.winehq.org/JobDetails.pl?Key=93428
[2] https://testbot.winehq.org/JobDetails.pl?Key=93447
[3] https://testbot.winehq.org/JobDetails.pl?Key=93452

 dlls/ntoskrnl.exe/tests/Makefile.in    |  16 +-
 dlls/ntoskrnl.exe/tests/driver.c       |  36 ++--
 dlls/ntoskrnl.exe/tests/driver.h       |   8 -
 dlls/ntoskrnl.exe/tests/driver_hid.c   |   2 +-
 dlls/ntoskrnl.exe/tests/driver_netio.c |   6 +-
 dlls/ntoskrnl.exe/tests/driver_pnp.c   |   2 +-
 dlls/ntoskrnl.exe/tests/ntoskrnl.c     |  49 +----
 dlls/ntoskrnl.exe/tests/utils.h        | 257 ------------------------
 include/wine/test.h                    | 260 +++++++++++++++++++++++--
 9 files changed, 287 insertions(+), 349 deletions(-)
 delete mode 100644 dlls/ntoskrnl.exe/tests/utils.h

diff --git a/dlls/ntoskrnl.exe/tests/Makefile.in b/dlls/ntoskrnl.exe/tests/Makefile.in
index 863fad30f63..037f0fda637 100644
--- a/dlls/ntoskrnl.exe/tests/Makefile.in
+++ b/dlls/ntoskrnl.exe/tests/Makefile.in
@@ -1,17 +1,23 @@
 TESTDLL   = ntoskrnl.exe
 IMPORTS   = advapi32 crypt32 newdev setupapi user32 wintrust ws2_32 hid
 
-driver_IMPORTS = winecrt0 ntoskrnl
+driver_IMPORTS = winecrt0 ntoskrnl hal
+driver_EXTRADEFS = -DSTANDALONE -DWINETEST_KERNEL
 driver_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native
-driver2_IMPORTS = winecrt0 ntoskrnl
+driver2_IMPORTS = winecrt0 ntoskrnl hal
+driver2_EXTRADEFS = -DSTANDALONE -DWINETEST_KERNEL
 driver2_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native
-driver3_IMPORTS = winecrt0 ntoskrnl
+driver3_IMPORTS = winecrt0 ntoskrnl hal
+driver3_EXTRADEFS = -DSTANDALONE -DWINETEST_KERNEL
 driver3_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native
-driver_hid_IMPORTS = winecrt0 ntoskrnl hidclass
+driver_hid_IMPORTS = winecrt0 ntoskrnl hal hidclass
+driver_hid_EXTRADEFS = -DSTANDALONE -DWINETEST_KERNEL
 driver_hid_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native
-driver_netio_IMPORTS = winecrt0 ntoskrnl netio
+driver_netio_IMPORTS = winecrt0 ntoskrnl hal netio
+driver_netio_EXTRADEFS = -DSTANDALONE -DWINETEST_KERNEL
 driver_netio_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native
 driver_pnp_IMPORTS = winecrt0 ntoskrnl hal
+driver_pnp_EXTRADEFS = -DSTANDALONE -DWINETEST_KERNEL
 driver_pnp_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native
 
 SOURCES = \
diff --git a/dlls/ntoskrnl.exe/tests/driver.c b/dlls/ntoskrnl.exe/tests/driver.c
index 94139b4b654..8c5ac6d89d4 100644
--- a/dlls/ntoskrnl.exe/tests/driver.c
+++ b/dlls/ntoskrnl.exe/tests/driver.c
@@ -33,9 +33,9 @@
 #include "ddk/ntifs.h"
 #include "ddk/wdm.h"
 
-#include "driver.h"
+#include "wine/test.h"
 
-#include "utils.h"
+#include "driver.h"
 
 /* memcmp() isn't exported from ntoskrnl on i386 */
 static int kmemcmp( const void *ptr1, const void *ptr2, size_t n )
@@ -999,41 +999,41 @@ static void test_call_driver(DEVICE_OBJECT *device)
     irp = IoBuildAsynchronousFsdRequest(IRP_MJ_FLUSH_BUFFERS, device, NULL, 0, NULL, &iosb);
     ok(irp->UserIosb == &iosb, "unexpected UserIosb\n");
     ok(!irp->Cancel, "Cancel = %x\n", irp->Cancel);
-    ok(!irp->CancelRoutine, "CancelRoutine = %x\n", irp->CancelRoutine);
+    ok(!irp->CancelRoutine, "CancelRoutine = %p\n", irp->CancelRoutine);
     ok(!irp->UserEvent, "UserEvent = %p\n", irp->UserEvent);
     ok(irp->CurrentLocation == 2, "CurrentLocation = %u\n", irp->CurrentLocation);
     ok(irp->Tail.Overlay.Thread == (PETHREAD)KeGetCurrentThread(),
        "IRP thread is not the current thread\n");
     ok(!irp->IoStatus.Status, "got status %#x\n", irp->IoStatus.Status);
-    ok(!irp->IoStatus.Information, "got information %#x\n", irp->IoStatus.Information);
+    ok(!irp->IoStatus.Information, "got information %#I64x\n", (UINT64)irp->IoStatus.Information);
     ok(iosb.Status == 0xdeadbeef, "got status %#x\n", iosb.Status);
-    ok(iosb.Information == 0xdeadbeef, "got information %#x\n", iosb.Information);
+    ok(iosb.Information == 0xdeadbeef, "got information %#I64x\n", (UINT64)iosb.Information);
 
     irpsp = IoGetNextIrpStackLocation(irp);
     ok(irpsp->MajorFunction == IRP_MJ_FLUSH_BUFFERS, "MajorFunction = %u\n", irpsp->MajorFunction);
-    ok(!irpsp->DeviceObject, "DeviceObject = %u\n", irpsp->DeviceObject);
-    ok(!irpsp->FileObject, "FileObject = %u\n", irpsp->FileObject);
+    ok(!irpsp->DeviceObject, "DeviceObject = %p\n", irpsp->DeviceObject);
+    ok(!irpsp->FileObject, "FileObject = %p\n", irpsp->FileObject);
     ok(!irpsp->CompletionRoutine, "CompletionRoutine = %p\n", irpsp->CompletionRoutine);
 
     status = IoCallDriver(device, irp);
     ok(status == STATUS_PENDING, "IoCallDriver returned %#x\n", status);
     ok(!irp->IoStatus.Status, "got status %#x\n", irp->IoStatus.Status);
-    ok(!irp->IoStatus.Information, "got information %#x\n", irp->IoStatus.Information);
+    ok(!irp->IoStatus.Information, "got information %#I64x\n", (UINT64)irp->IoStatus.Information);
     ok(iosb.Status == 0xdeadbeef, "got status %#x\n", iosb.Status);
-    ok(iosb.Information == 0xdeadbeef, "got information %#x\n", iosb.Information);
+    ok(iosb.Information == 0xdeadbeef, "got information %#I64x\n", (UINT64)iosb.Information);
 
     irp->IoStatus.Status = STATUS_SUCCESS;
     irp->IoStatus.Information = 123;
     IoCompleteRequest(irp, IO_NO_INCREMENT);
     ok(iosb.Status == STATUS_SUCCESS, "got status %#x\n", iosb.Status);
-    ok(iosb.Information == 123, "got information %#x\n", iosb.Information);
+    ok(iosb.Information == 123, "got information %#I64x\n", (UINT64)iosb.Information);
 
     KeInitializeEvent(&event, NotificationEvent, FALSE);
 
     irp = IoBuildSynchronousFsdRequest(IRP_MJ_FLUSH_BUFFERS, device, NULL, 0, NULL, &event, &iosb);
     ok(irp->UserIosb == &iosb, "unexpected UserIosb\n");
     ok(!irp->Cancel, "Cancel = %x\n", irp->Cancel);
-    ok(!irp->CancelRoutine, "CancelRoutine = %x\n", irp->CancelRoutine);
+    ok(!irp->CancelRoutine, "CancelRoutine = %p\n", irp->CancelRoutine);
     ok(irp->UserEvent == &event, "UserEvent = %p\n", irp->UserEvent);
     ok(irp->CurrentLocation == 2, "CurrentLocation = %u\n", irp->CurrentLocation);
     ok(irp->Tail.Overlay.Thread == (PETHREAD)KeGetCurrentThread(),
@@ -1041,8 +1041,8 @@ static void test_call_driver(DEVICE_OBJECT *device)
 
     irpsp = IoGetNextIrpStackLocation(irp);
     ok(irpsp->MajorFunction == IRP_MJ_FLUSH_BUFFERS, "MajorFunction = %u\n", irpsp->MajorFunction);
-    ok(!irpsp->DeviceObject, "DeviceObject = %u\n", irpsp->DeviceObject);
-    ok(!irpsp->FileObject, "FileObject = %u\n", irpsp->FileObject);
+    ok(!irpsp->DeviceObject, "DeviceObject = %p\n", irpsp->DeviceObject);
+    ok(!irpsp->FileObject, "FileObject = %p\n", irpsp->FileObject);
     ok(!irpsp->CompletionRoutine, "CompletionRoutine = %p\n", irpsp->CompletionRoutine);
 
     status = wait_single(&event, 0);
@@ -1118,7 +1118,7 @@ static void test_cancel_irp(DEVICE_OBJECT *device)
 
     ok(irp->CurrentLocation == 1, "CurrentLocation = %u\n", irp->CurrentLocation);
     irpsp = IoGetCurrentIrpStackLocation(irp);
-    ok(irpsp->DeviceObject == device, "DeviceObject = %u\n", irpsp->DeviceObject);
+    ok(irpsp->DeviceObject == device, "DeviceObject = %p\n", irpsp->DeviceObject);
 
     IoSetCancelRoutine(irp, cancel_irp);
     cancel_cnt = 0;
@@ -1432,16 +1432,16 @@ static void check_resource_(int line, ERESOURCE *resource, ULONG exclusive_waite
     ULONG count;
 
     count = ExGetExclusiveWaiterCount(resource);
-    ok_(__FILE__, line, count == exclusive_waiters,
+    ok_(__FILE__, line)(count == exclusive_waiters,
             "expected %u exclusive waiters, got %u\n", exclusive_waiters, count);
     count = ExGetSharedWaiterCount(resource);
-    ok_(__FILE__, line, count == shared_waiters,
+    ok_(__FILE__, line)(count == shared_waiters,
             "expected %u shared waiters, got %u\n", shared_waiters, count);
     ret = ExIsResourceAcquiredExclusiveLite(resource);
-    ok_(__FILE__, line, ret == exclusive,
+    ok_(__FILE__, line)(ret == exclusive,
             "expected exclusive %u, got %u\n", exclusive, ret);
     count = ExIsResourceAcquiredSharedLite(resource);
-    ok_(__FILE__, line, count == shared_count,
+    ok_(__FILE__, line)(count == shared_count,
             "expected shared %u, got %u\n", shared_count, count);
 }
 #define check_resource(a,b,c,d,e) check_resource_(__LINE__,a,b,c,d,e)
diff --git a/dlls/ntoskrnl.exe/tests/driver.h b/dlls/ntoskrnl.exe/tests/driver.h
index 455695ad36b..01d0991a25c 100644
--- a/dlls/ntoskrnl.exe/tests/driver.h
+++ b/dlls/ntoskrnl.exe/tests/driver.h
@@ -49,14 +49,6 @@
 
 static const char teststr[] = "Wine is not an emulator";
 
-struct test_data
-{
-    int running_under_wine;
-    int winetest_report_success;
-    int winetest_debug;
-    int successes, failures, skipped, todo_successes, todo_failures;
-};
-
 struct main_test_input
 {
     DWORD process_id;
diff --git a/dlls/ntoskrnl.exe/tests/driver_hid.c b/dlls/ntoskrnl.exe/tests/driver_hid.c
index 793b25f3189..ed3e5c17d6f 100644
--- a/dlls/ntoskrnl.exe/tests/driver_hid.c
+++ b/dlls/ntoskrnl.exe/tests/driver_hid.c
@@ -32,10 +32,10 @@
 #include "ddk/hidpi.h"
 #include "ddk/hidport.h"
 
+#include "wine/test.h"
 #include "wine/list.h"
 
 #include "driver.h"
-#include "utils.h"
 
 static UNICODE_STRING control_symlink;
 
diff --git a/dlls/ntoskrnl.exe/tests/driver_netio.c b/dlls/ntoskrnl.exe/tests/driver_netio.c
index ea9cfd1a4c5..68dbfd1c5e8 100644
--- a/dlls/ntoskrnl.exe/tests/driver_netio.c
+++ b/dlls/ntoskrnl.exe/tests/driver_netio.c
@@ -32,9 +32,9 @@
 #include "ddk/wdm.h"
 #include "ddk/wsk.h"
 
-#include "driver.h"
+#include "wine/test.h"
 
-#include "utils.h"
+#include "driver.h"
 
 static DRIVER_OBJECT *driver_obj;
 static DEVICE_OBJECT *device_obj;
@@ -141,7 +141,7 @@ static void test_wsk_get_address_info(void)
     {
         struct sockaddr_in *addr = (struct sockaddr_in *)addr_info->ai_addr;
 
-        ok(addr_info->ai_addrlen == sizeof(*addr), "Got unexpected ai_addrlen %u.\n", addr_info->ai_addrlen);
+        ok(addr_info->ai_addrlen == sizeof(*addr), "Got unexpected ai_addrlen %I64u.\n", (UINT64)addr_info->ai_addrlen);
         ok(addr->sin_family == AF_INET, "Got unexpected sin_family %u.\n", addr->sin_family);
         ok(ntohs(addr->sin_port) == 12345, "Got unexpected sin_port %u.\n", ntohs(addr->sin_port));
         ok(ntohl(addr->sin_addr.s_addr) == 0x7f000001, "Got unexpected sin_addr %#x.\n",
diff --git a/dlls/ntoskrnl.exe/tests/driver_pnp.c b/dlls/ntoskrnl.exe/tests/driver_pnp.c
index 98ca2ff7961..cf672f6f397 100644
--- a/dlls/ntoskrnl.exe/tests/driver_pnp.c
+++ b/dlls/ntoskrnl.exe/tests/driver_pnp.c
@@ -29,10 +29,10 @@
 #include "winioctl.h"
 #include "ddk/wdm.h"
 
+#include "wine/test.h"
 #include "wine/list.h"
 
 #include "driver.h"
-#include "utils.h"
 
 static const GUID bus_class     = {0xdeadbeef, 0x29ef, 0x4538, {0xa5, 0xfd, 0xb6, 0x95, 0x73, 0xa3, 0x62, 0xc1}};
 static const GUID child_class   = {0xdeadbeef, 0x29ef, 0x4538, {0xa5, 0xfd, 0xb6, 0x95, 0x73, 0xa3, 0x62, 0xc2}};
diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
index 0ef621011d3..c3456e56274 100644
--- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
@@ -52,8 +52,6 @@ static const GUID GUID_NULL;
 
 static HANDLE device;
 
-static struct test_data *test_data;
-
 static BOOL (WINAPI *pRtlDosPathNameToNtPathName_U)(const WCHAR *, UNICODE_STRING *, WCHAR **, CURDIR *);
 static BOOL (WINAPI *pRtlFreeUnicodeString)(UNICODE_STRING *);
 static BOOL (WINAPI *pCancelIoEx)(HANDLE, OVERLAPPED *);
@@ -367,27 +365,6 @@ static BOOL start_driver(HANDLE service, BOOL vista_plus)
     return TRUE;
 }
 
-static HANDLE okfile;
-
-static void cat_okfile(void)
-{
-    char buffer[512];
-    DWORD size;
-
-    SetFilePointer(okfile, 0, NULL, FILE_BEGIN);
-
-    do
-    {
-        ReadFile(okfile, buffer, sizeof(buffer), &size, NULL);
-        printf("%.*s", size, buffer);
-    } while (size == sizeof(buffer));
-
-    SetFilePointer(okfile, 0, NULL, FILE_BEGIN);
-    SetEndOfFile(okfile);
-
-    winetest_add_failures(InterlockedExchange(&test_data->failures, 0));
-}
-
 static ULONG64 modified_value;
 
 static void main_test(void)
@@ -931,7 +908,7 @@ static void test_driver_netio(struct testsign_context *ctx)
     ret = DeleteFileW(filename);
     ok(ret, "DeleteFile failed: %u\n", GetLastError());
 
-    cat_okfile();
+    winetest_kernel_check();
 }
 
 #ifdef __i386__
@@ -1499,7 +1476,7 @@ static void test_pnp_driver(struct testsign_context *ctx)
     unload_driver(service);
     CloseServiceHandle(manager);
 
-    cat_okfile();
+    winetest_kernel_check();
 
     GetFullPathNameA("winetest.inf", sizeof(path), path, NULL);
     ret = SetupCopyOEMInfA(path, NULL, 0, 0, dest, sizeof(dest), NULL, &filepart);
@@ -2638,7 +2615,7 @@ static void test_hid_driver(struct testsign_context *ctx, DWORD report_id)
     unload_driver(service);
     CloseServiceHandle(manager);
 
-    cat_okfile();
+    winetest_kernel_check();
 
     GetFullPathNameA("winetest.inf", sizeof(path), path, NULL);
     ret = SetupCopyOEMInfA(path, NULL, 0, 0, dest, sizeof(dest), NULL, &filepart);
@@ -2665,7 +2642,6 @@ START_TEST(ntoskrnl)
     struct testsign_context ctx;
     SC_HANDLE service, service2;
     BOOL ret, is_wow64;
-    HANDLE mapping;
     DWORD written;
 
     pRtlDosPathNameToNtPathName_U = (void *)GetProcAddress(GetModuleHandleA("ntdll"), "RtlDosPathNameToNtPathName_U");
@@ -2685,17 +2661,7 @@ START_TEST(ntoskrnl)
     if (!testsign_create_cert(&ctx))
         return;
 
-    mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
-            0, sizeof(*test_data), "Global\\winetest_ntoskrnl_section");
-    ok(!!mapping, "got error %u\n", GetLastError());
-    test_data = MapViewOfFile(mapping, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 1024);
-    test_data->running_under_wine = !strcmp(winetest_platform, "wine");
-    test_data->winetest_report_success = winetest_report_success;
-    test_data->winetest_debug = winetest_debug;
-
-    okfile = CreateFileA("C:\\windows\\winetest_ntoskrnl_okfile", GENERIC_READ | GENERIC_WRITE,
-            FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
-    ok(okfile != INVALID_HANDLE_VALUE, "failed to create file, error %u\n", GetLastError());
+    winetest_kernel_init();
 
     subtest("driver");
     if (!(service = load_driver(&ctx, filename, L"driver.dll", L"WineTestDriver")))
@@ -2737,7 +2703,7 @@ START_TEST(ntoskrnl)
     ret = DeleteFileW(filename2);
     ok(ret, "DeleteFile failed: %u\n", GetLastError());
 
-    cat_okfile();
+    winetest_kernel_check();
 
     test_driver3(&ctx);
     subtest("driver_netio");
@@ -2752,8 +2718,5 @@ START_TEST(ntoskrnl)
 
 out:
     testsign_cleanup(&ctx);
-    UnmapViewOfFile(test_data);
-    CloseHandle(mapping);
-    CloseHandle(okfile);
-    DeleteFileA("C:\\windows\\winetest_ntoskrnl_okfile");
+    winetest_kernel_cleanup();
 }
diff --git a/dlls/ntoskrnl.exe/tests/utils.h b/dlls/ntoskrnl.exe/tests/utils.h
deleted file mode 100644
index 6a0e00428a5..00000000000
--- a/dlls/ntoskrnl.exe/tests/utils.h
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * ntoskrnl.exe testing framework
- *
- * Copyright 2015 Sebastian Lackner
- * Copyright 2015 Michael Müller
- * Copyright 2015 Christian Costa
- * Copyright 2020 Paul Gofman for CodeWeavers
- * Copyright 2020-2021 Zebediah Figura for CodeWeavers
- *
- * 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
- */
-
-static HANDLE okfile;
-static LONG successes;
-static LONG failures;
-static LONG skipped;
-static LONG todo_successes;
-static LONG todo_failures;
-static int todo_level, todo_do_loop;
-static int running_under_wine;
-static int winetest_debug;
-static int winetest_report_success;
-
-static inline void kvprintf(const char *format, __ms_va_list ap)
-{
-    static char buffer[512];
-    IO_STATUS_BLOCK io;
-    int len = vsnprintf(buffer, sizeof(buffer), format, ap);
-    ZwWriteFile(okfile, NULL, NULL, NULL, &io, buffer, len, NULL, NULL);
-}
-
-static inline void WINAPIV kprintf(const char *format, ...)
-{
-    __ms_va_list valist;
-
-    __ms_va_start(valist, format);
-    kvprintf(format, valist);
-    __ms_va_end(valist);
-}
-
-static inline NTSTATUS winetest_init(void)
-{
-    const struct test_data *data;
-    SIZE_T size = sizeof(*data);
-    OBJECT_ATTRIBUTES attr;
-    UNICODE_STRING string;
-    IO_STATUS_BLOCK io;
-    void *addr = NULL;
-    HANDLE section;
-    NTSTATUS ret;
-
-    RtlInitUnicodeString(&string, L"\\BaseNamedObjects\\winetest_ntoskrnl_section");
-    /* OBJ_KERNEL_HANDLE is necessary for the file to be accessible from system threads */
-    InitializeObjectAttributes(&attr, &string, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, NULL);
-    if ((ret = ZwOpenSection(&section, SECTION_MAP_READ, &attr)))
-        return ret;
-
-    if ((ret = ZwMapViewOfSection(section, NtCurrentProcess(), &addr,
-            0, 0, NULL, &size, ViewUnmap, 0, PAGE_READONLY)))
-    {
-        ZwClose(section);
-        return ret;
-    }
-    data = addr;
-    running_under_wine = data->running_under_wine;
-    winetest_debug = data->winetest_debug;
-    winetest_report_success = data->winetest_report_success;
-
-    ZwUnmapViewOfSection(NtCurrentProcess(), addr);
-    ZwClose(section);
-
-    RtlInitUnicodeString(&string, L"\\??\\C:\\windows\\winetest_ntoskrnl_okfile");
-    return ZwOpenFile(&okfile, FILE_APPEND_DATA | SYNCHRONIZE, &attr, &io,
-            FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT);
-}
-
-static inline void winetest_cleanup(void)
-{
-    struct test_data *data;
-    SIZE_T size = sizeof(*data);
-    OBJECT_ATTRIBUTES attr;
-    UNICODE_STRING string;
-    void *addr = NULL;
-    HANDLE section;
-
-    if (winetest_debug)
-    {
-        kprintf("%04x:ntoskrnl: %d tests executed (%d marked as todo, %d %s), %d skipped.\n",
-                PsGetCurrentProcessId(), successes + failures + todo_successes + todo_failures,
-                todo_successes, failures + todo_failures,
-                (failures + todo_failures != 1) ? "failures" : "failure", skipped );
-    }
-
-    RtlInitUnicodeString(&string, L"\\BaseNamedObjects\\winetest_ntoskrnl_section");
-    /* OBJ_KERNEL_HANDLE is necessary for the file to be accessible from system threads */
-    InitializeObjectAttributes(&attr, &string, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, NULL);
-
-    if (!ZwOpenSection(&section, SECTION_MAP_READ | SECTION_MAP_WRITE, &attr))
-    {
-        if (!ZwMapViewOfSection(section, NtCurrentProcess(), &addr,
-                0, 0, NULL, &size, ViewUnmap, 0, PAGE_READWRITE))
-        {
-            data = addr;
-
-            InterlockedExchangeAdd(&data->successes, successes);
-            InterlockedExchangeAdd(&data->failures, failures);
-            InterlockedExchangeAdd(&data->skipped, skipped);
-            InterlockedExchangeAdd(&data->todo_successes, todo_successes);
-            InterlockedExchangeAdd(&data->todo_failures, todo_failures);
-
-            ZwUnmapViewOfSection(NtCurrentProcess(), addr);
-        }
-        ZwClose(section);
-    }
-
-    ZwClose(okfile);
-}
-
-static inline void WINAPIV vok_(const char *file, int line, int condition, const char *msg,  __ms_va_list args)
-{
-    const char *current_file;
-
-    if (!(current_file = drv_strrchr(file, '/')) &&
-        !(current_file = drv_strrchr(file, '\\')))
-        current_file = file;
-    else
-        current_file++;
-
-    if (todo_level)
-    {
-        if (condition)
-        {
-            kprintf("%s:%d: Test succeeded inside todo block: ", current_file, line);
-            kvprintf(msg, args);
-            InterlockedIncrement(&todo_failures);
-        }
-        else
-        {
-            if (winetest_debug > 0)
-            {
-                kprintf("%s:%d: Test marked todo: ", current_file, line);
-                kvprintf(msg, args);
-            }
-            InterlockedIncrement(&todo_successes);
-        }
-    }
-    else
-    {
-        if (!condition)
-        {
-            kprintf("%s:%d: Test failed: ", current_file, line);
-            kvprintf(msg, args);
-            InterlockedIncrement(&failures);
-        }
-        else
-        {
-            if (winetest_report_success)
-                kprintf("%s:%d: Test succeeded\n", current_file, line);
-            InterlockedIncrement(&successes);
-        }
-    }
-}
-
-static inline void WINAPIV ok_(const char *file, int line, int condition, const char *msg, ...)
-{
-    __ms_va_list args;
-    __ms_va_start(args, msg);
-    vok_(file, line, condition, msg, args);
-    __ms_va_end(args);
-}
-
-static inline void vskip_(const char *file, int line, const char *msg, __ms_va_list args)
-{
-    const char *current_file;
-
-    if (!(current_file = drv_strrchr(file, '/')) &&
-        !(current_file = drv_strrchr(file, '\\')))
-        current_file = file;
-    else
-        current_file++;
-
-    kprintf("%s:%d: Tests skipped: ", current_file, line);
-    kvprintf(msg, args);
-    skipped++;
-}
-
-static inline void WINAPIV win_skip_(const char *file, int line, const char *msg, ...)
-{
-    __ms_va_list args;
-    __ms_va_start(args, msg);
-    if (running_under_wine)
-        vok_(file, line, 0, msg, args);
-    else
-        vskip_(file, line, msg, args);
-    __ms_va_end(args);
-}
-
-static inline void WINAPIV trace_(const char *file, int line, const char *msg, ...)
-{
-    const char *current_file;
-    __ms_va_list args;
-
-    if (!(current_file = drv_strrchr(file, '/')) &&
-        !(current_file = drv_strrchr(file, '\\')))
-        current_file = file;
-    else
-        current_file++;
-
-    __ms_va_start(args, msg);
-    kprintf("%s:%d: ", current_file, line);
-    kvprintf(msg, args);
-    __ms_va_end(args);
-}
-
-static inline void winetest_start_todo( int is_todo )
-{
-    todo_level = (todo_level << 1) | (is_todo != 0);
-    todo_do_loop=1;
-}
-
-static inline int winetest_loop_todo(void)
-{
-    int do_loop=todo_do_loop;
-    todo_do_loop=0;
-    return do_loop;
-}
-
-static inline void winetest_end_todo(void)
-{
-    todo_level >>= 1;
-}
-
-static inline int broken(int condition)
-{
-    return !running_under_wine && condition;
-}
-
-#define ok(condition, ...)  ok_(__FILE__, __LINE__, condition, __VA_ARGS__)
-#define todo_if(is_todo) for (winetest_start_todo(is_todo); \
-                              winetest_loop_todo(); \
-                              winetest_end_todo())
-#define todo_wine               todo_if(running_under_wine)
-#define todo_wine_if(is_todo)   todo_if((is_todo) && running_under_wine)
-#define win_skip(...)           win_skip_(__FILE__, __LINE__, __VA_ARGS__)
-#define trace(...)              trace_(__FILE__, __LINE__, __VA_ARGS__)
diff --git a/include/wine/test.h b/include/wine/test.h
index 8073071d262..5513022b9c2 100644
--- a/include/wine/test.h
+++ b/include/wine/test.h
@@ -25,6 +25,9 @@
 #include <stdlib.h>
 #include <windef.h>
 #include <winbase.h>
+#ifdef WINETEST_KERNEL
+#include <ddk/wdm.h>
+#endif /* WINETEST_KERNEL */
 #include <wine/debug.h>
 
 #ifdef __WINE_CONFIG_H
@@ -59,6 +62,9 @@ extern int winetest_mute_threshold;
 /* current platform */
 extern const char *winetest_platform;
 
+/* output file for kernel tests */
+extern HANDLE okfile;
+
 extern void winetest_set_location( const char* file, int line );
 extern void winetest_subtest( const char* name );
 extern void winetest_ignore_exceptions( BOOL ignore );
@@ -68,6 +74,9 @@ extern void winetest_end_todo(void);
 extern int winetest_get_mainargs( char*** pargv );
 extern LONG winetest_get_failures(void);
 extern void winetest_add_failures( LONG new_failures );
+extern void winetest_kernel_init( void );
+extern void winetest_kernel_check( void );
+extern void winetest_kernel_cleanup( void );
 extern void winetest_wait_child_process( HANDLE process );
 
 #ifdef STANDALONE
@@ -214,7 +223,8 @@ DWORD winetest_start_time, winetest_last_time;
 int winetest_interactive = 0;
 
 /* current platform */
-const char *winetest_platform = "windows";
+static char winetest_platform_buf[256] = "windows";
+const char *winetest_platform = winetest_platform_buf;
 
 /* report successful tests (BOOL) */
 int winetest_report_success = 0;
@@ -226,7 +236,9 @@ int winetest_mute_threshold = 42;
 static int winetest_argc;
 static char** winetest_argv;
 
+#ifndef WINETEST_KERNEL
 static const struct test *current_test; /* test currently being run */
+#endif /* WINETEST_KERNEL */
 
 static LONG successes;       /* number of successful tests */
 static LONG failures;        /* number of failures */
@@ -240,9 +252,15 @@ static LONG muted_todo_successes; /* same as todo_successes but silent */
 /* counts how many times a given line printed a message */
 static LONG line_counters[16384];
 
+/* output file for driver tests */
+HANDLE okfile;
+
 /* The following data must be kept track of on a per-thread basis */
 struct tls_data
 {
+#ifdef WINETEST_KERNEL
+    HANDLE thread;
+#endif /* WINETEST_KERNEL */
     const char* current_file;        /* file of current check */
     int current_line;                /* line of current check */
     unsigned int todo_level;         /* current todo nesting level */
@@ -252,6 +270,38 @@ struct tls_data
     char context[8][128];            /* data to print before messages */
     unsigned int context_count;      /* number of context prefixes */
 };
+
+#ifdef WINETEST_KERNEL
+
+static KSPIN_LOCK tls_data_lock;
+static struct tls_data tls_data_pool[128];
+static DWORD tls_data_count;
+
+static struct tls_data *get_tls_data(void)
+{
+    static struct tls_data tls_overflow;
+    struct tls_data *data;
+    HANDLE thread = PsGetCurrentThreadId();
+    KIRQL irql;
+
+    KeAcquireSpinLock(&tls_data_lock, &irql);
+    for (data = tls_data_pool; data != tls_data_pool + tls_data_count; ++data)
+        if (data->thread == thread) break;
+    if (data == tls_data_pool + ARRAY_SIZE(tls_data_pool))
+        data = &tls_overflow;
+    else if (data == tls_data_pool + tls_data_count)
+    {
+        data->thread = thread;
+        data->str_pos = data->strings;
+        tls_data_count++;
+    }
+    KeReleaseSpinLock(&tls_data_lock, irql);
+
+    return data;
+}
+
+#else /* WINETEST_KERNEL */
+
 static DWORD tls_index;
 
 static struct tls_data *get_tls_data(void)
@@ -277,6 +327,7 @@ static void exit_process( int code )
     ExitProcess( code );
 }
 
+#endif /* WINETEST_KERNEL */
 
 void winetest_set_location( const char* file, int line )
 {
@@ -291,6 +342,36 @@ void winetest_set_location( const char* file, int line )
     data->current_line=line;
 }
 
+#ifdef WINETEST_KERNEL
+
+static inline void __winetest_vprintf(const char *format, __ms_va_list ap)
+{
+    static char buffer[512];
+    IO_STATUS_BLOCK io;
+    int len = vsnprintf(buffer, sizeof(buffer), format, ap);
+    ZwWriteFile(okfile, NULL, NULL, NULL, &io, buffer, len, NULL, NULL);
+}
+
+static inline void WINAPIV __winetest_printf(const char *format, ...)
+{
+    __ms_va_list valist;
+
+    __ms_va_start(valist, format);
+    __winetest_vprintf(format, valist);
+    __ms_va_end(valist);
+}
+
+const char *winetest_elapsed(void)
+{
+    if (!winetest_time) return "";
+    return "0.000";
+}
+
+#else /* WINETEST_KERNEL */
+
+#define __winetest_printf printf
+#define __winetest_vprintf vprintf
+
 const char *winetest_elapsed(void)
 {
     DWORD now;
@@ -300,15 +381,17 @@ const char *winetest_elapsed(void)
     return wine_dbg_sprintf( "%.3f", (now - winetest_start_time) / 1000.0);
 }
 
+#endif /* WINETEST_KERNEL */
+
 static void __winetest_cdecl winetest_printf( const char *msg, ... ) __WINE_PRINTF_ATTR(1,2);
 static void __winetest_cdecl winetest_printf( const char *msg, ... )
 {
     struct tls_data *data = get_tls_data();
     __winetest_va_list valist;
 
-    printf( "%s:%d:%s ", data->current_file, data->current_line, winetest_elapsed() );
+    __winetest_printf( "%s:%d:%s ", data->current_file, data->current_line, winetest_elapsed() );
     __winetest_va_start( valist, msg );
-    vprintf( msg, valist );
+    __winetest_vprintf( msg, valist );
     __winetest_va_end( valist );
 }
 static void __winetest_cdecl winetest_print_context( const char *msgtype )
@@ -318,7 +401,7 @@ static void __winetest_cdecl winetest_print_context( const char *msgtype )
 
     winetest_printf( "%s", msgtype );
     for (i = 0; i < data->context_count; ++i)
-        printf( "%s: ", data->context[i] );
+        __winetest_printf( "%s: ", data->context[i] );
 }
 
 void winetest_subtest( const char* name )
@@ -372,7 +455,7 @@ int winetest_vok( int condition, const char *msg, __winetest_va_list args )
         if (condition)
         {
             winetest_print_context( "Test succeeded inside todo block: " );
-            vprintf(msg, args);
+            __winetest_vprintf(msg, args);
             InterlockedIncrement(&todo_failures);
             return 0;
         }
@@ -384,7 +467,7 @@ int winetest_vok( int condition, const char *msg, __winetest_va_list args )
                 if (winetest_debug > 0)
                 {
                     winetest_print_context( "Test marked todo: " );
-                    vprintf(msg, args);
+                    __winetest_vprintf(msg, args);
                 }
                 InterlockedIncrement(&todo_successes);
             }
@@ -398,17 +481,18 @@ int winetest_vok( int condition, const char *msg, __winetest_va_list args )
         if (!condition)
         {
             winetest_print_context( "Test failed: " );
-            vprintf(msg, args);
+            __winetest_vprintf(msg, args);
             InterlockedIncrement(&failures);
             return 0;
         }
         else
         {
-            if (winetest_report_success ||
-                (winetest_time && GetTickCount() >= winetest_last_time + 1000))
-            {
+            if (winetest_report_success)
                 winetest_printf("Test succeeded\n");
-            }
+#ifndef WINETEST_KERNEL
+            else if (winetest_time && GetTickCount() >= winetest_last_time + 1000)
+                winetest_printf("Test succeeded\n");
+#endif /* WINETEST_KERNEL */
             InterlockedIncrement(&successes);
             return 1;
         }
@@ -434,7 +518,7 @@ void __winetest_cdecl winetest_trace( const char *msg, ... )
     {
         winetest_print_context( "" );
         __winetest_va_start(valist, msg);
-        vprintf( msg, valist );
+        __winetest_vprintf( msg, valist );
         __winetest_va_end(valist);
     }
     else
@@ -446,7 +530,7 @@ void winetest_vskip( const char *msg, __winetest_va_list args )
     if (winetest_add_line() < winetest_mute_threshold)
     {
         winetest_print_context( "Tests skipped: " );
-        vprintf(msg, args);
+        __winetest_vprintf(msg, args);
         InterlockedIncrement(&skipped);
     }
     else
@@ -533,6 +617,155 @@ void winetest_add_failures( LONG new_failures )
         InterlockedIncrement( &failures );
 }
 
+struct winetest_kernel_data
+{
+    char winetest_platform[256];
+    int running_under_wine;
+    int winetest_report_success;
+    int winetest_debug;
+    int failures;
+    int todo_failures;
+};
+
+#ifdef WINETEST_KERNEL
+
+static int running_under_wine;
+
+static inline NTSTATUS winetest_init(void)
+{
+    const struct winetest_kernel_data *data;
+    SIZE_T size = sizeof(*data);
+    OBJECT_ATTRIBUTES attr;
+    UNICODE_STRING string;
+    IO_STATUS_BLOCK io;
+    void *addr = NULL;
+    HANDLE section;
+    NTSTATUS ret;
+
+    KeInitializeSpinLock(&tls_data_lock);
+
+    RtlInitUnicodeString(&string, L"\\BaseNamedObjects\\winetest_kernel_section");
+    /* OBJ_KERNEL_HANDLE is necessary for the file to be accessible from system threads */
+    InitializeObjectAttributes(&attr, &string, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, NULL);
+    if ((ret = ZwOpenSection(&section, SECTION_MAP_READ, &attr)))
+        return ret;
+
+    if ((ret = ZwMapViewOfSection(section, NtCurrentProcess(), &addr,
+            0, 0, NULL, &size, ViewUnmap, 0, PAGE_READONLY)))
+    {
+        ZwClose(okfile);
+        ZwClose(section);
+        return ret;
+    }
+    data = addr;
+    running_under_wine = data->running_under_wine;
+    winetest_debug = data->winetest_debug;
+    winetest_report_success = data->winetest_report_success;
+    strcpy(winetest_platform_buf, data->winetest_platform);
+
+    ZwUnmapViewOfSection(NtCurrentProcess(), addr);
+    ZwClose(section);
+
+    RtlInitUnicodeString(&string, L"\\??\\C:\\windows\\winetest_kernel_okfile");
+    return ZwOpenFile(&okfile, FILE_APPEND_DATA | SYNCHRONIZE, &attr, &io,
+            FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT);
+}
+
+static inline void winetest_cleanup(void)
+{
+    struct winetest_kernel_data *data;
+    SIZE_T size = sizeof(*data);
+    OBJECT_ATTRIBUTES attr;
+    UNICODE_STRING string;
+    void *addr = NULL;
+    HANDLE section;
+
+    if (winetest_debug)
+    {
+        if (muted_todo_successes || muted_skipped || muted_traces)
+            __winetest_printf( "%04x:ntoskrnl:%s Silenced %d todos, %d skips and %d traces.\n",
+                    (DWORD)(ULONG_PTR)PsGetCurrentProcessId(), winetest_elapsed(),
+                    muted_todo_successes, muted_skipped, muted_traces);
+        __winetest_printf( "%04x:ntoskrnl:%s %d tests executed (%d marked as todo, %d %s), %d skipped.\n",
+                (DWORD)(ULONG_PTR)PsGetCurrentProcessId(), winetest_elapsed(),
+                successes + failures + todo_successes + todo_failures,
+                todo_successes, failures + todo_failures,
+                (failures + todo_failures != 1) ? "failures" : "failure",
+                skipped );
+    }
+
+    RtlInitUnicodeString(&string, L"\\BaseNamedObjects\\winetest_kernel_section");
+    /* OBJ_KERNEL_HANDLE is necessary for the file to be accessible from system threads */
+    InitializeObjectAttributes(&attr, &string, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, NULL);
+
+    if (!ZwOpenSection(&section, SECTION_MAP_READ | SECTION_MAP_WRITE, &attr))
+    {
+        if (!ZwMapViewOfSection(section, NtCurrentProcess(), &addr,
+                0, 0, NULL, &size, ViewUnmap, 0, PAGE_READWRITE))
+        {
+            data = addr;
+
+            InterlockedExchangeAdd(&data->failures, failures);
+            InterlockedExchangeAdd(&data->todo_failures, todo_failures);
+
+            ZwUnmapViewOfSection(NtCurrentProcess(), addr);
+        }
+        ZwClose(section);
+    }
+
+    ZwClose(okfile);
+}
+
+#else /* WINETEST_KERNEL */
+
+static HANDLE winetest_mapping;
+static struct winetest_kernel_data *kernel_data;
+
+void winetest_kernel_init(void)
+{
+    winetest_mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
+        sizeof(*kernel_data), "Global\\winetest_kernel_section");
+    ok(!!winetest_mapping, "got error %u\n", GetLastError());
+    kernel_data = MapViewOfFile(winetest_mapping, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 1024);
+    ok(strlen(winetest_platform) < 256, "winetest_platform expectedly large!\n");
+    strcpy(kernel_data->winetest_platform, winetest_platform);
+    kernel_data->running_under_wine = !strcmp(winetest_platform, "wine");
+    kernel_data->winetest_report_success = winetest_report_success;
+    kernel_data->winetest_debug = winetest_debug;
+
+    okfile = CreateFileA("C:\\windows\\winetest_kernel_okfile", GENERIC_READ | GENERIC_WRITE,
+            FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
+    ok(okfile != INVALID_HANDLE_VALUE, "failed to create file, error %u\n", GetLastError());
+}
+
+void winetest_kernel_check(void)
+{
+    char buffer[512];
+    DWORD size;
+
+    SetFilePointer(okfile, 0, NULL, FILE_BEGIN);
+
+    do
+    {
+        ReadFile(okfile, buffer, sizeof(buffer), &size, NULL);
+        printf("%.*s", size, buffer);
+    } while (size == sizeof(buffer));
+
+    SetFilePointer(okfile, 0, NULL, FILE_BEGIN);
+    /* SetEndOfFile(okfile); */
+
+    InterlockedExchangeAdd(&failures, InterlockedExchange(&kernel_data->failures, 0));
+    InterlockedExchangeAdd(&todo_failures, InterlockedExchange(&kernel_data->todo_failures, 0));
+}
+
+void winetest_kernel_cleanup(void)
+{
+    UnmapViewOfFile(kernel_data);
+    CloseHandle(winetest_mapping);
+    CloseHandle(okfile);
+    /* DeleteFileA("C:\\windows\\winetest_kernel_okfile"); */
+}
+
 void winetest_wait_child_process( HANDLE process )
 {
     DWORD ret;
@@ -702,6 +935,7 @@ int main( int argc, char **argv )
     return run_test(argv[1]);
 }
 
+#endif /* WINETEST_KERNEL */
 #endif  /* STANDALONE */
 
 #endif  /* __WINE_WINE_TEST_H */
-- 
2.32.0




More information about the wine-devel mailing list