[PATCH 3/3] ntdll/tests: Add tests for kernel32 threadpool I/O functions.

Zebediah Figura z.figura12 at gmail.com
Sat Apr 11 00:16:27 CDT 2020


Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
 dlls/ntdll/tests/threadpool.c | 228 ++++++++++++++++++++++++++++------
 1 file changed, 190 insertions(+), 38 deletions(-)

diff --git a/dlls/ntdll/tests/threadpool.c b/dlls/ntdll/tests/threadpool.c
index 32d4c3eac2..2984983a06 100644
--- a/dlls/ntdll/tests/threadpool.c
+++ b/dlls/ntdll/tests/threadpool.c
@@ -22,7 +22,6 @@
 #define NONAMELESSUNION
 #include "ntdll_test.h"
 
-static HMODULE hntdll = 0;
 static NTSTATUS (WINAPI *pTpAllocCleanupGroup)(TP_CLEANUP_GROUP **);
 static NTSTATUS (WINAPI *pTpAllocIoCompletion)(TP_IO **,HANDLE,PTP_IO_CALLBACK,void *,TP_CALLBACK_ENVIRON *);
 static NTSTATUS (WINAPI *pTpAllocPool)(TP_POOL **,PVOID);
@@ -52,51 +51,58 @@ static VOID     (WINAPI *pTpWaitForTimer)(TP_TIMER *,BOOL);
 static VOID     (WINAPI *pTpWaitForWait)(TP_WAIT *,BOOL);
 static VOID     (WINAPI *pTpWaitForWork)(TP_WORK *,BOOL);
 
-#define NTDLL_GET_PROC(func) \
+static void (WINAPI *pCancelThreadpoolIo)(TP_IO *);
+static void (WINAPI *pCloseThreadpoolIo)(TP_IO *);
+static TP_IO *(WINAPI *pCreateThreadpoolIo)(HANDLE, PTP_WIN32_IO_CALLBACK, void *, TP_CALLBACK_ENVIRON *);
+static void (WINAPI *pStartThreadpoolIo)(TP_IO *);
+static void (WINAPI *pWaitForThreadpoolIoCallbacks)(TP_IO *, BOOL);
+
+#define GET_PROC(func) \
     do \
     { \
-        p ## func = (void *)GetProcAddress(hntdll, #func); \
+        p ## func = (void *)GetProcAddress(module, #func); \
         if (!p ## func) trace("Failed to get address for %s\n", #func); \
     } \
     while (0)
 
 static BOOL init_threadpool(void)
 {
-    hntdll = GetModuleHandleA("ntdll");
-    if (!hntdll)
-    {
-        win_skip("Could not load ntdll\n");
-        return FALSE;
-    }
-
-    NTDLL_GET_PROC(TpAllocCleanupGroup);
-    NTDLL_GET_PROC(TpAllocIoCompletion);
-    NTDLL_GET_PROC(TpAllocPool);
-    NTDLL_GET_PROC(TpAllocTimer);
-    NTDLL_GET_PROC(TpAllocWait);
-    NTDLL_GET_PROC(TpAllocWork);
-    NTDLL_GET_PROC(TpCancelAsyncIoOperation);
-    NTDLL_GET_PROC(TpCallbackMayRunLong);
-    NTDLL_GET_PROC(TpCallbackReleaseSemaphoreOnCompletion);
-    NTDLL_GET_PROC(TpDisassociateCallback);
-    NTDLL_GET_PROC(TpIsTimerSet);
-    NTDLL_GET_PROC(TpPostWork);
-    NTDLL_GET_PROC(TpReleaseCleanupGroup);
-    NTDLL_GET_PROC(TpReleaseCleanupGroupMembers);
-    NTDLL_GET_PROC(TpReleaseIoCompletion);
-    NTDLL_GET_PROC(TpReleasePool);
-    NTDLL_GET_PROC(TpReleaseTimer);
-    NTDLL_GET_PROC(TpReleaseWait);
-    NTDLL_GET_PROC(TpReleaseWork);
-    NTDLL_GET_PROC(TpSetPoolMaxThreads);
-    NTDLL_GET_PROC(TpSetTimer);
-    NTDLL_GET_PROC(TpSetWait);
-    NTDLL_GET_PROC(TpSimpleTryPost);
-    NTDLL_GET_PROC(TpStartAsyncIoOperation);
-    NTDLL_GET_PROC(TpWaitForIoCompletion);
-    NTDLL_GET_PROC(TpWaitForTimer);
-    NTDLL_GET_PROC(TpWaitForWait);
-    NTDLL_GET_PROC(TpWaitForWork);
+    HMODULE module = GetModuleHandleA("ntdll");
+    GET_PROC(TpAllocCleanupGroup);
+    GET_PROC(TpAllocIoCompletion);
+    GET_PROC(TpAllocPool);
+    GET_PROC(TpAllocTimer);
+    GET_PROC(TpAllocWait);
+    GET_PROC(TpAllocWork);
+    GET_PROC(TpCallbackMayRunLong);
+    GET_PROC(TpCallbackReleaseSemaphoreOnCompletion);
+    GET_PROC(TpCancelAsyncIoOperation);
+    GET_PROC(TpDisassociateCallback);
+    GET_PROC(TpIsTimerSet);
+    GET_PROC(TpPostWork);
+    GET_PROC(TpReleaseCleanupGroup);
+    GET_PROC(TpReleaseCleanupGroupMembers);
+    GET_PROC(TpReleaseIoCompletion);
+    GET_PROC(TpReleasePool);
+    GET_PROC(TpReleaseTimer);
+    GET_PROC(TpReleaseWait);
+    GET_PROC(TpReleaseWork);
+    GET_PROC(TpSetPoolMaxThreads);
+    GET_PROC(TpSetTimer);
+    GET_PROC(TpSetWait);
+    GET_PROC(TpSimpleTryPost);
+    GET_PROC(TpStartAsyncIoOperation);
+    GET_PROC(TpWaitForIoCompletion);
+    GET_PROC(TpWaitForTimer);
+    GET_PROC(TpWaitForWait);
+    GET_PROC(TpWaitForWork);
+
+    module = GetModuleHandleA("kernel32");
+    GET_PROC(CancelThreadpoolIo);
+    GET_PROC(CloseThreadpoolIo);
+    GET_PROC(CreateThreadpoolIo);
+    GET_PROC(StartThreadpoolIo);
+    GET_PROC(WaitForThreadpoolIoCallbacks);
 
     if (!pTpAllocPool)
     {
@@ -2084,6 +2090,151 @@ static void test_tp_io(void)
     pTpReleasePool(pool);
 }
 
+static void CALLBACK kernel32_io_cb(TP_CALLBACK_INSTANCE *instance, void *userdata,
+        void *ovl, ULONG ret, ULONG_PTR length, TP_IO *io)
+{
+    struct io_cb_ctx *ctx = userdata;
+    ++ctx->count;
+    ctx->ovl = ovl;
+    ctx->ret = ret;
+    ctx->length = length;
+    ctx->io = io;
+}
+
+static void test_kernel32_tp_io(void)
+{
+    TP_CALLBACK_ENVIRON environment = {.Version = 1};
+    OVERLAPPED ovl = {}, ovl2 = {};
+    HANDLE client, server, thread;
+    struct io_cb_ctx userdata;
+    char in[1], in2[1];
+    const char out[1];
+    NTSTATUS status;
+    DWORD ret_size;
+    TP_POOL *pool;
+    TP_IO *io;
+    BOOL ret;
+
+    ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
+
+    status = pTpAllocPool(&pool, NULL);
+    ok(!status, "failed to allocate pool, status %#x\n", status);
+
+    server = CreateNamedPipeA("\\\\.\\pipe\\wine_tp_test",
+            PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0, 1, 1024, 1024, 0, NULL);
+    ok(server != INVALID_HANDLE_VALUE, "Failed to create server pipe, error %u.\n", GetLastError());
+    client = CreateFileA("\\\\.\\pipe\\wine_tp_test", GENERIC_READ | GENERIC_WRITE,
+            0, NULL, OPEN_EXISTING, 0, 0);
+    ok(client != INVALID_HANDLE_VALUE, "Failed to create client pipe, error %u.\n", GetLastError());
+
+    environment.Pool = pool;
+    io = NULL;
+    io = pCreateThreadpoolIo(server, kernel32_io_cb, &userdata, &environment);
+    todo_wine ok(!!io, "expected non-NULL TP_IO\n");
+    if (!io)
+        return;
+
+    pWaitForThreadpoolIoCallbacks(io, FALSE);
+
+    userdata.count = 0;
+    pStartThreadpoolIo(io);
+
+    thread = CreateThread(NULL, 0, io_wait_thread, io, 0, NULL);
+    ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "TpWaitForIoCompletion() should not return\n");
+
+    ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
+    ok(!ret, "wrong ret %d\n", ret);
+    ok(GetLastError() == ERROR_IO_PENDING, "wrong error %u\n", GetLastError());
+
+    ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
+    ok(ret, "WriteFile() failed, error %u\n", GetLastError());
+
+    pWaitForThreadpoolIoCallbacks(io, FALSE);
+    ok(userdata.count == 1, "callback ran %u times\n", userdata.count);
+    ok(userdata.ovl == &ovl, "expected %p, got %p\n", &ovl, userdata.ovl);
+    ok(userdata.ret == ERROR_SUCCESS, "got status %#x\n", userdata.ret);
+    ok(userdata.length == 1, "got length %lu\n", userdata.length);
+    ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io);
+
+    ok(!WaitForSingleObject(thread, 1000), "wait timed out\n");
+    CloseHandle(thread);
+
+    userdata.count = 0;
+    pStartThreadpoolIo(io);
+    pStartThreadpoolIo(io);
+
+    ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
+    ok(!ret, "wrong ret %d\n", ret);
+    ok(GetLastError() == ERROR_IO_PENDING, "wrong error %u\n", GetLastError());
+    ret = ReadFile(server, in2, sizeof(in2), NULL, &ovl2);
+    ok(!ret, "wrong ret %d\n", ret);
+    ok(GetLastError() == ERROR_IO_PENDING, "wrong error %u\n", GetLastError());
+
+    ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
+    ok(ret, "WriteFile() failed, error %u\n", GetLastError());
+    ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
+    ok(ret, "WriteFile() failed, error %u\n", GetLastError());
+
+    pWaitForThreadpoolIoCallbacks(io, FALSE);
+    ok(userdata.count == 2, "callback ran %u times\n", userdata.count);
+    ok(userdata.ret == STATUS_SUCCESS, "got status %#x\n", userdata.ret);
+    ok(userdata.length == 1, "got length %lu\n", userdata.length);
+    ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io);
+
+    userdata.count = 0;
+    pStartThreadpoolIo(io);
+    pWaitForThreadpoolIoCallbacks(io, TRUE);
+    ok(!userdata.count, "callback ran %u times\n", userdata.count);
+
+    pStartThreadpoolIo(io);
+
+    ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
+    ok(ret, "WriteFile() failed, error %u\n", GetLastError());
+
+    ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
+    ok(ret, "wrong ret %d\n", ret);
+
+    pWaitForThreadpoolIoCallbacks(io, FALSE);
+    ok(userdata.count == 1, "callback ran %u times\n", userdata.count);
+    ok(userdata.ovl == &ovl, "expected %p, got %p\n", &ovl, userdata.ovl);
+    ok(userdata.ret == ERROR_SUCCESS, "got status %#x\n", userdata.ret);
+    ok(userdata.length == 1, "got length %lu\n", userdata.length);
+    ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io);
+
+    userdata.count = 0;
+    pStartThreadpoolIo(io);
+
+    ret = ReadFile(server, NULL, 1, NULL, &ovl);
+    ok(!ret, "wrong ret %d\n", ret);
+    ok(GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError());
+
+    pCancelThreadpoolIo(io);
+    pWaitForThreadpoolIoCallbacks(io, FALSE);
+    ok(!userdata.count, "callback ran %u times\n", userdata.count);
+
+    userdata.count = 0;
+    pStartThreadpoolIo(io);
+
+    ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
+    ok(!ret, "wrong ret %d\n", ret);
+    ok(GetLastError() == ERROR_IO_PENDING, "wrong error %u\n", GetLastError());
+    ret = CancelIo(server);
+    ok(ret, "CancelIo() failed, error %u\n", GetLastError());
+
+    pWaitForThreadpoolIoCallbacks(io, FALSE);
+    ok(userdata.count == 1, "callback ran %u times\n", userdata.count);
+    ok(userdata.ovl == &ovl, "expected %p, got %p\n", &ovl, userdata.ovl);
+    ok(userdata.ret == ERROR_OPERATION_ABORTED, "got status %#x\n", userdata.ret);
+    ok(!userdata.length, "got length %lu\n", userdata.length);
+    ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io);
+
+    CloseHandle(ovl.hEvent);
+    CloseHandle(client);
+    CloseHandle(server);
+    pCloseThreadpoolIo(io);
+    pTpReleasePool(pool);
+}
+
 START_TEST(threadpool)
 {
     test_RtlQueueWorkItem();
@@ -2104,4 +2255,5 @@ START_TEST(threadpool)
     test_tp_wait();
     test_tp_multi_wait();
     test_tp_io();
+    test_kernel32_tp_io();
 }
-- 
2.26.0




More information about the wine-devel mailing list