https://git.reactos.org/?p=reactos.git;a=commitdiff;h=88a63011ea30eb14d52490...
commit 88a63011ea30eb14d5249026d4505dc336c3b92f Author: Justin Miller justin.miller@reactos.org AuthorDate: Wed Jan 22 20:13:15 2025 -0800 Commit: Justin Miller justinmiller100@gmail.com CommitDate: Sun Jan 26 23:30:59 2025 -0800
[ROSTESTS] Import winetest threadpool.c from wine-9.7 --- modules/rostests/winetests/ntdll/threadpool.c | 1229 +++++++++++++++++-------- 1 file changed, 857 insertions(+), 372 deletions(-)
diff --git a/modules/rostests/winetests/ntdll/threadpool.c b/modules/rostests/winetests/ntdll/threadpool.c index af0b6673d39..1dd96bfd2f3 100644 --- a/modules/rostests/winetests/ntdll/threadpool.c +++ b/modules/rostests/winetests/ntdll/threadpool.c @@ -20,71 +20,91 @@
#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); static NTSTATUS (WINAPI *pTpAllocTimer)(TP_TIMER **,PTP_TIMER_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *); static NTSTATUS (WINAPI *pTpAllocWait)(TP_WAIT **,PTP_WAIT_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *); static NTSTATUS (WINAPI *pTpAllocWork)(TP_WORK **,PTP_WORK_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *); static NTSTATUS (WINAPI *pTpCallbackMayRunLong)(TP_CALLBACK_INSTANCE *); static VOID (WINAPI *pTpCallbackReleaseSemaphoreOnCompletion)(TP_CALLBACK_INSTANCE *,HANDLE,DWORD); +static void (WINAPI *pTpCancelAsyncIoOperation)(TP_IO *); static VOID (WINAPI *pTpDisassociateCallback)(TP_CALLBACK_INSTANCE *); static BOOL (WINAPI *pTpIsTimerSet)(TP_TIMER *); -static VOID (WINAPI *pTpReleaseWait)(TP_WAIT *); static VOID (WINAPI *pTpPostWork)(TP_WORK *); +static NTSTATUS (WINAPI *pTpQueryPoolStackInformation)(TP_POOL *,TP_POOL_STACK_INFORMATION *); static VOID (WINAPI *pTpReleaseCleanupGroup)(TP_CLEANUP_GROUP *); static VOID (WINAPI *pTpReleaseCleanupGroupMembers)(TP_CLEANUP_GROUP *,BOOL,PVOID); +static void (WINAPI *pTpReleaseIoCompletion)(TP_IO *); static VOID (WINAPI *pTpReleasePool)(TP_POOL *); static VOID (WINAPI *pTpReleaseTimer)(TP_TIMER *); +static VOID (WINAPI *pTpReleaseWait)(TP_WAIT *); static VOID (WINAPI *pTpReleaseWork)(TP_WORK *); static VOID (WINAPI *pTpSetPoolMaxThreads)(TP_POOL *,DWORD); +static NTSTATUS (WINAPI *pTpSetPoolStackInformation)(TP_POOL *,TP_POOL_STACK_INFORMATION *); static VOID (WINAPI *pTpSetTimer)(TP_TIMER *,LARGE_INTEGER *,LONG,LONG); static VOID (WINAPI *pTpSetWait)(TP_WAIT *,HANDLE,LARGE_INTEGER *); static NTSTATUS (WINAPI *pTpSimpleTryPost)(PTP_SIMPLE_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *); +static void (WINAPI *pTpStartAsyncIoOperation)(TP_IO *); +static void (WINAPI *pTpWaitForIoCompletion)(TP_IO *,BOOL); 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(TpAllocPool); - NTDLL_GET_PROC(TpAllocTimer); - NTDLL_GET_PROC(TpAllocWait); - NTDLL_GET_PROC(TpAllocWork); - 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(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(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(TpQueryPoolStackInformation); + 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(TpSetPoolStackInformation); + 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) { @@ -101,7 +121,6 @@ static BOOL init_threadpool(void) static DWORD CALLBACK rtl_work_cb(void *userdata) { HANDLE semaphore = userdata; - trace("Running rtl_work callback\n"); ReleaseSemaphore(semaphore, 1, NULL); return 0; } @@ -113,32 +132,32 @@ static void test_RtlQueueWorkItem(void) DWORD result;
semaphore = CreateSemaphoreA(NULL, 0, 1, NULL); - ok(semaphore != NULL, "CreateSemaphoreA failed %u\n", GetLastError()); + ok(semaphore != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
status = RtlQueueWorkItem(rtl_work_cb, semaphore, WT_EXECUTEDEFAULT); - ok(!status, "RtlQueueWorkItem failed with status %x\n", status); + ok(!status, "RtlQueueWorkItem failed with status %lx\n", status); result = WaitForSingleObject(semaphore, 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
status = RtlQueueWorkItem(rtl_work_cb, semaphore, WT_EXECUTEINIOTHREAD); - ok(!status, "RtlQueueWorkItem failed with status %x\n", status); + ok(!status, "RtlQueueWorkItem failed with status %lx\n", status); result = WaitForSingleObject(semaphore, 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
status = RtlQueueWorkItem(rtl_work_cb, semaphore, WT_EXECUTEINPERSISTENTTHREAD); - ok(!status, "RtlQueueWorkItem failed with status %x\n", status); + ok(!status, "RtlQueueWorkItem failed with status %lx\n", status); result = WaitForSingleObject(semaphore, 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
status = RtlQueueWorkItem(rtl_work_cb, semaphore, WT_EXECUTELONGFUNCTION); - ok(!status, "RtlQueueWorkItem failed with status %x\n", status); + ok(!status, "RtlQueueWorkItem failed with status %lx\n", status); result = WaitForSingleObject(semaphore, 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
status = RtlQueueWorkItem(rtl_work_cb, semaphore, WT_TRANSFER_IMPERSONATION); - ok(!status, "RtlQueueWorkItem failed with status %x\n", status); + ok(!status, "RtlQueueWorkItem failed with status %lx\n", status); result = WaitForSingleObject(semaphore, 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
CloseHandle(semaphore); } @@ -157,8 +176,6 @@ static void CALLBACK rtl_wait_cb(void *userdata, BOOLEAN timeout) struct rtl_wait_info *info = userdata; DWORD result;
- trace("Running rtl_wait callback\n"); - if (!timeout) InterlockedIncrement(&info->userdata); else @@ -169,7 +186,7 @@ static void CALLBACK rtl_wait_cb(void *userdata, BOOLEAN timeout) if (info->semaphore2) { result = WaitForSingleObject(info->semaphore2, 200); - ok(result == info->wait_result, "expected %u, got %u\n", info->wait_result, result); + ok(result == info->wait_result, "expected %lu, got %lu\n", info->wait_result, result); ReleaseSemaphore(info->semaphore1, 1, NULL); } } @@ -178,7 +195,6 @@ static HANDLE rtl_wait_apc_semaphore;
static void CALLBACK rtl_wait_apc_cb(ULONG_PTR userdata) { - trace("Running rtl_wait_apc callback\n"); if (rtl_wait_apc_semaphore) ReleaseSemaphore(rtl_wait_apc_semaphore, 1, NULL); } @@ -189,7 +205,7 @@ static void test_RtlRegisterWait(void) struct rtl_wait_info info; HANDLE semaphores[2]; NTSTATUS status; - DWORD result; + DWORD result, threadid;
semaphores[0] = CreateSemaphoreW(NULL, 0, 2, NULL); ok(semaphores[0] != NULL, "failed to create semaphore\n"); @@ -205,196 +221,257 @@ static void test_RtlRegisterWait(void) wait1 = NULL; info.userdata = 0; status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT); - ok(!status, "RtlRegisterWait failed with status %x\n", status); + ok(!status, "RtlRegisterWait failed with status %lx\n", status); ok(wait1 != NULL, "expected wait1 != NULL\n"); status = RtlDeregisterWait(wait1); - ok(!status, "RtlDeregisterWait failed with status %x\n", status); - ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); + ok(!status, "RtlDeregisterWait failed with status %lx\n", status); + ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
/* infinite timeout, signal the semaphore two times */ info.userdata = 0; status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT); - ok(!status, "RtlRegisterWait failed with status %x\n", status); + ok(!status, "RtlRegisterWait failed with status %lx\n", status); ReleaseSemaphore(semaphores[1], 1, NULL); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); ReleaseSemaphore(semaphores[1], 1, NULL); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 2, "expected info.userdata = 2, got %u\n", info.userdata); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 2, "expected info.userdata = 2, got %lu\n", info.userdata); result = WaitForSingleObject(semaphores[1], 0); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); Sleep(50); status = RtlDeregisterWait(wait1); - ok(!status, "RtlDeregisterWait failed with status %x\n", status); + ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
/* repeat test with WT_EXECUTEONLYONCE */ info.userdata = 0; status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEONLYONCE); - ok(!status, "RtlRegisterWait failed with status %x\n", status); + ok(!status, "RtlRegisterWait failed with status %lx\n", status); ReleaseSemaphore(semaphores[1], 1, NULL); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); ReleaseSemaphore(semaphores[1], 1, NULL); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); result = WaitForSingleObject(semaphores[1], 0); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); Sleep(50); status = RtlDeregisterWait(wait1); - ok(!status, "RtlDeregisterWait failed with status %x\n", status); + ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
/* finite timeout, no event */ info.userdata = 0; status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 200, WT_EXECUTEDEFAULT); - ok(!status, "RtlRegisterWait failed with status %x\n", status); + ok(!status, "RtlRegisterWait failed with status %lx\n", status); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata); result = WaitForSingleObject(semaphores[0], 200); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata); result = WaitForSingleObject(semaphores[1], 0); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); Sleep(50); status = RtlDeregisterWait(wait1); - ok(!status, "RtlDeregisterWait failed with status %x\n", status); + ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
/* finite timeout, with event */ info.userdata = 0; status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 200, WT_EXECUTEDEFAULT); - ok(!status, "RtlRegisterWait failed with status %x\n", status); + ok(!status, "RtlRegisterWait failed with status %lx\n", status); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata); + ReleaseSemaphore(semaphores[1], 1, NULL); + result = WaitForSingleObject(semaphores[0], 100); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); + result = WaitForSingleObject(semaphores[1], 0); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); + Sleep(50); + status = RtlDeregisterWait(wait1); + ok(!status, "RtlDeregisterWait failed with status %lx\n", status); + + /* test RtlRegisterWait WT_EXECUTEINWAITTHREAD flag */ + info.userdata = 0; + info.threadid = 0; + status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 200, WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE); + ok(!status, "RtlRegisterWait failed with status %lx\n", status); ReleaseSemaphore(semaphores[1], 1, NULL); + result = WaitForSingleObject(semaphores[0], 200); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); + ok(info.threadid && info.threadid != GetCurrentThreadId(), "unexpected wait thread id %lx\n", info.threadid); + threadid = info.threadid; + result = WaitForSingleObject(semaphores[1], 0); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); + Sleep(50); + status = RtlDeregisterWait(wait1); + ok(!status, "RtlDeregisterWait failed with status %lx\n", status); + + info.userdata = 0; + info.threadid = 0; + status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 200, WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE); + ok(!status, "RtlRegisterWait failed with status %lx\n", status); + ReleaseSemaphore(semaphores[1], 1, NULL); + result = WaitForSingleObject(semaphores[0], 200); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); + ok(info.threadid == threadid, "unexpected different wait thread id %lx\n", info.threadid); + result = WaitForSingleObject(semaphores[1], 0); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); + Sleep(50); + status = RtlDeregisterWait(wait1); + ok(!status, "RtlDeregisterWait failed with status %lx\n", status); + + /* test RtlRegisterWait WT_EXECUTEINWAITTHREAD flag with 0 timeout */ + info.userdata = 0; + info.threadid = 0; + status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 0, WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE); + ok(!status, "RtlRegisterWait failed with status %lx\n", status); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata); + ok(info.threadid == threadid, "unexpected different wait thread id %lx\n", info.threadid); + result = WaitForSingleObject(semaphores[1], 0); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); + Sleep(50); + status = RtlDeregisterWait(wait1); + ok(!status, "RtlDeregisterWait failed with status %lx\n", status); + + /* test RtlRegisterWait WT_EXECUTEINWAITTHREAD flag with already signaled event */ + info.userdata = 0; + info.threadid = 0; + ReleaseSemaphore(semaphores[1], 1, NULL); + status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 200, WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE); + ok(!status, "RtlRegisterWait failed with status %lx\n", status); + result = WaitForSingleObject(semaphores[0], 200); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); + ok(info.threadid == threadid, "unexpected different wait thread id %lx\n", info.threadid); result = WaitForSingleObject(semaphores[1], 0); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); Sleep(50); status = RtlDeregisterWait(wait1); - ok(!status, "RtlDeregisterWait failed with status %x\n", status); + ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
/* test for IO threads */ info.userdata = 0; info.threadid = 0; status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEINIOTHREAD); - ok(!status, "RtlRegisterWait failed with status %x\n", status); + ok(!status, "RtlRegisterWait failed with status %lx\n", status); ReleaseSemaphore(semaphores[1], 1, NULL); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); - ok(info.threadid != 0, "expected info.threadid != 0, got %u\n", info.threadid); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); + ok(info.threadid != 0, "expected info.threadid != 0, got %lu\n", info.threadid); thread = OpenThread(THREAD_SET_CONTEXT, FALSE, info.threadid); - ok(thread != NULL, "OpenThread failed with %u\n", GetLastError()); + ok(thread != NULL, "OpenThread failed with %lu\n", GetLastError()); rtl_wait_apc_semaphore = semaphores[0]; result = QueueUserAPC(rtl_wait_apc_cb, thread, 0); - ok(result != 0, "QueueUserAPC failed with %u\n", GetLastError()); + ok(result != 0, "QueueUserAPC failed with %lu\n", GetLastError()); result = WaitForSingleObject(semaphores[0], 200); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); rtl_wait_apc_semaphore = 0; CloseHandle(thread); ReleaseSemaphore(semaphores[1], 1, NULL); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 2, "expected info.userdata = 2, got %u\n", info.userdata); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 2, "expected info.userdata = 2, got %lu\n", info.userdata); Sleep(50); status = RtlDeregisterWait(wait1); - ok(!status, "RtlDeregisterWait failed with status %x\n", status); + ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
info.userdata = 0; info.threadid = 0; status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT); - ok(!status, "RtlRegisterWait failed with status %x\n", status); + ok(!status, "RtlRegisterWait failed with status %lx\n", status); ReleaseSemaphore(semaphores[1], 1, NULL); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); - ok(info.threadid != 0, "expected info.threadid != 0, got %u\n", info.threadid); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); + ok(info.threadid != 0, "expected info.threadid != 0, got %lu\n", info.threadid); thread = OpenThread(THREAD_SET_CONTEXT, FALSE, info.threadid); - ok(thread != NULL, "OpenThread failed with %u\n", GetLastError()); + ok(thread != NULL, "OpenThread failed with %lu\n", GetLastError()); rtl_wait_apc_semaphore = semaphores[0]; result = QueueUserAPC(rtl_wait_apc_cb, thread, 0); - ok(result != 0, "QueueUserAPC failed with %u\n", GetLastError()); + ok(result != 0, "QueueUserAPC failed with %lu\n", GetLastError()); result = WaitForSingleObject(semaphores[0], 200); ok(result == WAIT_TIMEOUT || broken(result == WAIT_OBJECT_0) /* >= Win Vista */, - "WaitForSingleObject returned %u\n", result); + "WaitForSingleObject returned %lu\n", result); rtl_wait_apc_semaphore = 0; CloseHandle(thread); ReleaseSemaphore(semaphores[1], 1, NULL); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 2, "expected info.userdata = 2, got %u\n", info.userdata); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 2, "expected info.userdata = 2, got %lu\n", info.userdata); Sleep(50); status = RtlDeregisterWait(wait1); - ok(!status, "RtlDeregisterWait failed with status %x\n", status); + ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
/* test RtlDeregisterWaitEx before wait expired */ info.userdata = 0; status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT); - ok(!status, "RtlRegisterWait failed with status %x\n", status); + ok(!status, "RtlRegisterWait failed with status %lx\n", status); status = RtlDeregisterWaitEx(wait1, NULL); - ok(!status, "RtlDeregisterWaitEx failed with status %x\n", status); - ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); + ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status); + ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
info.userdata = 0; status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT); - ok(!status, "RtlRegisterWait failed with status %x\n", status); + ok(!status, "RtlRegisterWait failed with status %lx\n", status); status = RtlDeregisterWaitEx(wait1, INVALID_HANDLE_VALUE); - ok(!status, "RtlDeregisterWaitEx failed with status %x\n", status); - ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); + ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status); + ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
info.userdata = 0; status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT); - ok(!status, "RtlRegisterWait failed with status %x\n", status); + ok(!status, "RtlRegisterWait failed with status %lx\n", status); status = RtlDeregisterWaitEx(wait1, event); - ok(!status, "RtlDeregisterWaitEx failed with status %x\n", status); - ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); + ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status); + ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata); result = WaitForSingleObject(event, 200); - todo_wine - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
/* test RtlDeregisterWaitEx after wait expired */ info.userdata = 0; status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 0, WT_EXECUTEONLYONCE); - ok(!status, "RtlRegisterWait failed with status %x\n", status); + ok(!status, "RtlRegisterWait failed with status %lx\n", status); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata); Sleep(50); status = RtlDeregisterWaitEx(wait1, NULL); - ok(!status, "RtlDeregisterWaitEx failed with status %x\n", status); - ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata); + ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status); + ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
info.userdata = 0; status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 0, WT_EXECUTEONLYONCE); - ok(!status, "RtlRegisterWait failed with status %x\n", status); + ok(!status, "RtlRegisterWait failed with status %lx\n", status); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata); Sleep(50); status = RtlDeregisterWaitEx(wait1, INVALID_HANDLE_VALUE); - ok(!status, "RtlDeregisterWaitEx failed with status %x\n", status); - ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata); + ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status); + ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
info.userdata = 0; status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 0, WT_EXECUTEONLYONCE); - ok(!status, "RtlRegisterWait failed with status %x\n", status); + ok(!status, "RtlRegisterWait failed with status %lx\n", status); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata); Sleep(50); status = RtlDeregisterWaitEx(wait1, event); - ok(!status, "RtlDeregisterWaitEx failed with status %x\n", status); - ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata); + ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status); + ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata); result = WaitForSingleObject(event, 200); - todo_wine - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
/* test RtlDeregisterWaitEx while callback is running */ info.semaphore2 = semaphores[1]; @@ -402,58 +479,84 @@ static void test_RtlRegisterWait(void)
info.userdata = 0; status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEONLYONCE); - ok(!status, "RtlRegisterWait failed with status %x\n", status); + ok(!status, "RtlRegisterWait failed with status %lx\n", status); ReleaseSemaphore(semaphores[1], 1, NULL); result = WaitForSingleObject(semaphores[0], 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); status = RtlDeregisterWait(wait1); - ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %x\n", status); + ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %lx\n", status); ReleaseSemaphore(semaphores[1], 1, NULL); result = WaitForSingleObject(semaphores[0], 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + + info.userdata = 0; + status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE); + ok(!status, "RtlRegisterWait failed with status %lx\n", status); + ReleaseSemaphore(semaphores[1], 1, NULL); + result = WaitForSingleObject(semaphores[0], 1000); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); + status = RtlDeregisterWait(wait1); + ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %lx\n", status); + ReleaseSemaphore(semaphores[1], 1, NULL); + result = WaitForSingleObject(semaphores[0], 1000); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
info.userdata = 0; status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEONLYONCE); - ok(!status, "RtlRegisterWait failed with status %x\n", status); + ok(!status, "RtlRegisterWait failed with status %lx\n", status); ReleaseSemaphore(semaphores[1], 1, NULL); result = WaitForSingleObject(semaphores[0], 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); status = RtlDeregisterWaitEx(wait1, NULL); - ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %x\n", status); + ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %lx\n", status); ReleaseSemaphore(semaphores[1], 1, NULL); result = WaitForSingleObject(semaphores[0], 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
info.wait_result = WAIT_TIMEOUT; info.userdata = 0; status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEONLYONCE); - ok(!status, "RtlRegisterWait failed with status %x\n", status); + ok(!status, "RtlRegisterWait failed with status %lx\n", status); + ReleaseSemaphore(semaphores[1], 1, NULL); + result = WaitForSingleObject(semaphores[0], 1000); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); + status = RtlDeregisterWaitEx(wait1, INVALID_HANDLE_VALUE); + ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status); + result = WaitForSingleObject(semaphores[0], 0); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + + info.wait_result = WAIT_TIMEOUT; + info.userdata = 0; + status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE); + ok(!status, "RtlRegisterWait failed with status %lx\n", status); ReleaseSemaphore(semaphores[1], 1, NULL); result = WaitForSingleObject(semaphores[0], 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); status = RtlDeregisterWaitEx(wait1, INVALID_HANDLE_VALUE); - ok(!status, "RtlDeregisterWaitEx failed with status %x\n", status); + ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status); result = WaitForSingleObject(semaphores[0], 0); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
info.wait_result = WAIT_OBJECT_0; info.userdata = 0; status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEONLYONCE); - ok(!status, "RtlRegisterWait failed with status %x\n", status); + ok(!status, "RtlRegisterWait failed with status %lx\n", status); ReleaseSemaphore(semaphores[1], 1, NULL); result = WaitForSingleObject(semaphores[0], 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); status = RtlDeregisterWaitEx(wait1, event); - ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %x\n", status); + ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %lx\n", status); ReleaseSemaphore(semaphores[1], 1, NULL); result = WaitForSingleObject(event, 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); result = WaitForSingleObject(semaphores[0], 0); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
CloseHandle(semaphores[0]); CloseHandle(semaphores[1]); @@ -463,19 +566,19 @@ static void test_RtlRegisterWait(void) static void CALLBACK simple_cb(TP_CALLBACK_INSTANCE *instance, void *userdata) { HANDLE semaphore = userdata; - trace("Running simple callback\n"); ReleaseSemaphore(semaphore, 1, NULL); }
static void CALLBACK simple2_cb(TP_CALLBACK_INSTANCE *instance, void *userdata) { - trace("Running simple2 callback\n"); Sleep(50); InterlockedIncrement((LONG *)userdata); }
static void test_tp_simple(void) { + IMAGE_NT_HEADERS *nt = RtlImageNtHeader( NtCurrentTeb()->Peb->ImageBaseAddress ); + TP_POOL_STACK_INFORMATION stack_info; TP_CALLBACK_ENVIRON environment; TP_CALLBACK_ENVIRON_V3 environment3; TP_CLEANUP_GROUP *group; @@ -487,21 +590,21 @@ static void test_tp_simple(void) int i;
semaphore = CreateSemaphoreA(NULL, 0, 1, NULL); - ok(semaphore != NULL, "CreateSemaphoreA failed %u\n", GetLastError()); + ok(semaphore != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
/* post the callback using the default threadpool */ memset(&environment, 0, sizeof(environment)); environment.Version = 1; environment.Pool = NULL; status = pTpSimpleTryPost(simple_cb, semaphore, &environment); - ok(!status, "TpSimpleTryPost failed with status %x\n", status); + ok(!status, "TpSimpleTryPost failed with status %lx\n", status); result = WaitForSingleObject(semaphore, 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
/* allocate new threadpool */ pool = NULL; status = pTpAllocPool(&pool, NULL); - ok(!status, "TpAllocPool failed with status %x\n", status); + ok(!status, "TpAllocPool failed with status %lx\n", status); ok(pool != NULL, "expected pool != NULL\n");
/* post the callback using the new threadpool */ @@ -509,20 +612,29 @@ static void test_tp_simple(void) environment.Version = 1; environment.Pool = pool; status = pTpSimpleTryPost(simple_cb, semaphore, &environment); - ok(!status, "TpSimpleTryPost failed with status %x\n", status); + ok(!status, "TpSimpleTryPost failed with status %lx\n", status); result = WaitForSingleObject(semaphore, 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
/* test with environment version 3 */ memset(&environment3, 0, sizeof(environment3)); environment3.Version = 3; environment3.Pool = pool; - environment3.CallbackPriority = TP_CALLBACK_PRIORITY_NORMAL; environment3.Size = sizeof(environment3); + + for (i = 0; i < 3; ++i) + { + environment3.CallbackPriority = TP_CALLBACK_PRIORITY_HIGH + i; + status = pTpSimpleTryPost(simple_cb, semaphore, (TP_CALLBACK_ENVIRON *)&environment3); + ok(!status, "TpSimpleTryPost failed with status %lx\n", status); + result = WaitForSingleObject(semaphore, 1000); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + } + + environment3.CallbackPriority = 10; status = pTpSimpleTryPost(simple_cb, semaphore, (TP_CALLBACK_ENVIRON *)&environment3); - ok(!status, "TpSimpleTryPost failed with status %x\n", status); - result = WaitForSingleObject(semaphore, 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(status == STATUS_INVALID_PARAMETER || broken(!status) /* Vista does not support priorities */, + "TpSimpleTryPost failed with status %lx\n", status);
/* test with invalid version number */ memset(&environment, 0, sizeof(environment)); @@ -531,17 +643,17 @@ static void test_tp_simple(void) status = pTpSimpleTryPost(simple_cb, semaphore, &environment); todo_wine ok(status == STATUS_INVALID_PARAMETER || broken(!status) /* Vista/2008 */, - "TpSimpleTryPost unexpectedly returned status %x\n", status); + "TpSimpleTryPost unexpectedly returned status %lx\n", status); if (!status) { result = WaitForSingleObject(semaphore, 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); }
/* allocate a cleanup group for synchronization */ group = NULL; status = pTpAllocCleanupGroup(&group); - ok(!status, "TpAllocCleanupGroup failed with status %x\n", status); + ok(!status, "TpAllocCleanupGroup failed with status %lx\n", status); ok(group != NULL, "expected pool != NULL\n");
/* use cleanup group to wait for a simple callback */ @@ -551,9 +663,9 @@ static void test_tp_simple(void) environment.Pool = pool; environment.CleanupGroup = group; status = pTpSimpleTryPost(simple2_cb, &userdata, &environment); - ok(!status, "TpSimpleTryPost failed with status %x\n", status); + ok(!status, "TpSimpleTryPost failed with status %lx\n", status); pTpReleaseCleanupGroupMembers(group, FALSE, NULL); - ok(userdata == 1, "expected userdata = 1, got %u\n", userdata); + ok(userdata == 1, "expected userdata = 1, got %lu\n", userdata);
/* test cancellation of pending simple callbacks */ userdata = 0; @@ -565,10 +677,26 @@ static void test_tp_simple(void) for (i = 0; i < 100; i++) { status = pTpSimpleTryPost(simple2_cb, &userdata, &environment); - ok(!status, "TpSimpleTryPost failed with status %x\n", status); + ok(!status, "TpSimpleTryPost failed with status %lx\n", status); } pTpReleaseCleanupGroupMembers(group, TRUE, NULL); - ok(userdata < 100, "expected userdata < 100, got %u\n", userdata); + ok(userdata < 100, "expected userdata < 100, got %lu\n", userdata); + + /* test querying and setting the stack size */ + status = pTpQueryPoolStackInformation(pool, &stack_info); + ok(!status, "TpQueryPoolStackInformation failed: %lx\n", status); + ok(stack_info.StackReserve == nt->OptionalHeader.SizeOfStackReserve, "expected default StackReserve, got %Ix\n", stack_info.StackReserve); + ok(stack_info.StackCommit == nt->OptionalHeader.SizeOfStackCommit, "expected default StackCommit, got %Ix\n", stack_info.StackCommit); + + /* threadpool does not validate the stack size values */ + stack_info.StackReserve = stack_info.StackCommit = 1; + status = pTpSetPoolStackInformation(pool, &stack_info); + ok(!status, "TpSetPoolStackInformation failed: %lx\n", status); + + status = pTpQueryPoolStackInformation(pool, &stack_info); + ok(!status, "TpQueryPoolStackInformation failed: %lx\n", status); + ok(stack_info.StackReserve == 1, "expected 1 byte StackReserve, got %ld\n", (ULONG)stack_info.StackReserve); + ok(stack_info.StackCommit == 1, "expected 1 byte StackCommit, got %ld\n", (ULONG)stack_info.StackCommit);
/* cleanup */ pTpReleaseCleanupGroup(group); @@ -578,14 +706,12 @@ static void test_tp_simple(void)
static void CALLBACK work_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work) { - trace("Running work callback\n"); Sleep(100); InterlockedIncrement((LONG *)userdata); }
static void CALLBACK work2_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work) { - trace("Running work2 callback\n"); Sleep(100); InterlockedExchangeAdd((LONG *)userdata, 0x10000); } @@ -602,7 +728,7 @@ static void test_tp_work(void) /* allocate new threadpool with only one thread */ pool = NULL; status = pTpAllocPool(&pool, NULL); - ok(!status, "TpAllocPool failed with status %x\n", status); + ok(!status, "TpAllocPool failed with status %lx\n", status); ok(pool != NULL, "expected pool != NULL\n"); pTpSetPoolMaxThreads(pool, 1);
@@ -612,7 +738,7 @@ static void test_tp_work(void) environment.Version = 1; environment.Pool = pool; status = pTpAllocWork(&work, work_cb, &userdata, &environment); - ok(!status, "TpAllocWork failed with status %x\n", status); + ok(!status, "TpAllocWork failed with status %lx\n", status); ok(work != NULL, "expected work != NULL\n");
/* post 5 identical work items at once */ @@ -620,14 +746,14 @@ static void test_tp_work(void) for (i = 0; i < 5; i++) pTpPostWork(work); pTpWaitForWork(work, FALSE); - ok(userdata == 5, "expected userdata = 5, got %u\n", userdata); + ok(userdata == 5, "expected userdata = 5, got %lu\n", userdata);
/* add more tasks and cancel them immediately */ userdata = 0; for (i = 0; i < 10; i++) pTpPostWork(work); pTpWaitForWork(work, TRUE); - ok(userdata < 10, "expected userdata < 10, got %u\n", userdata); + ok(userdata < 10, "expected userdata < 10, got %lu\n", userdata);
/* cleanup */ pTpReleaseWork(work); @@ -647,14 +773,14 @@ static void test_tp_work_scheduler(void) /* allocate new threadpool with only one thread */ pool = NULL; status = pTpAllocPool(&pool, NULL); - ok(!status, "TpAllocPool failed with status %x\n", status); + ok(!status, "TpAllocPool failed with status %lx\n", status); ok(pool != NULL, "expected pool != NULL\n"); pTpSetPoolMaxThreads(pool, 1);
/* create a cleanup group */ group = NULL; status = pTpAllocCleanupGroup(&group); - ok(!status, "TpAllocCleanupGroup failed with status %x\n", status); + ok(!status, "TpAllocCleanupGroup failed with status %lx\n", status); ok(group != NULL, "expected pool != NULL\n");
/* the first work item has no cleanup group associated */ @@ -663,7 +789,7 @@ static void test_tp_work_scheduler(void) environment.Version = 1; environment.Pool = pool; status = pTpAllocWork(&work, work_cb, &userdata, &environment); - ok(!status, "TpAllocWork failed with status %x\n", status); + ok(!status, "TpAllocWork failed with status %lx\n", status); ok(work != NULL, "expected work != NULL\n");
/* allocate a second work item with a cleanup group */ @@ -673,7 +799,7 @@ static void test_tp_work_scheduler(void) environment.Pool = pool; environment.CleanupGroup = group; status = pTpAllocWork(&work2, work2_cb, &userdata, &environment); - ok(!status, "TpAllocWork failed with status %x\n", status); + ok(!status, "TpAllocWork failed with status %lx\n", status); ok(work2 != NULL, "expected work2 != NULL\n");
/* the 'work' callbacks are not blocking execution of 'work2' callbacks */ @@ -685,8 +811,8 @@ static void test_tp_work_scheduler(void) Sleep(500); pTpWaitForWork(work, TRUE); pTpWaitForWork(work2, TRUE); - ok(userdata & 0xffff, "expected userdata & 0xffff != 0, got %u\n", userdata & 0xffff); - ok(userdata >> 16, "expected userdata >> 16 != 0, got %u\n", userdata >> 16); + ok(userdata & 0xffff, "expected userdata & 0xffff != 0, got %lu\n", userdata & 0xffff); + ok(userdata >> 16, "expected userdata >> 16 != 0, got %lu\n", userdata >> 16);
/* test TpReleaseCleanupGroupMembers on a work item */ userdata = 0; @@ -696,8 +822,8 @@ static void test_tp_work_scheduler(void) pTpPostWork(work2); pTpReleaseCleanupGroupMembers(group, FALSE, NULL); pTpWaitForWork(work, TRUE); - ok((userdata & 0xffff) < 10, "expected userdata & 0xffff < 10, got %u\n", userdata & 0xffff); - ok((userdata >> 16) == 3, "expected userdata >> 16 == 3, got %u\n", userdata >> 16); + ok((userdata & 0xffff) < 10, "expected userdata & 0xffff < 10, got %lu\n", userdata & 0xffff); + ok((userdata >> 16) == 3, "expected userdata >> 16 == 3, got %lu\n", userdata >> 16);
/* cleanup */ pTpReleaseWork(work); @@ -708,7 +834,6 @@ static void test_tp_work_scheduler(void) static void CALLBACK simple_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata) { HANDLE *semaphores = userdata; - trace("Running simple release callback\n"); ReleaseSemaphore(semaphores, 1, NULL); Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */ } @@ -716,7 +841,6 @@ static void CALLBACK simple_release_cb(TP_CALLBACK_INSTANCE *instance, void *use static void CALLBACK work_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work) { HANDLE semaphore = userdata; - trace("Running work release callback\n"); ReleaseSemaphore(semaphore, 1, NULL); Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */ pTpReleaseWork(work); @@ -725,7 +849,6 @@ static void CALLBACK work_release_cb(TP_CALLBACK_INSTANCE *instance, void *userd static void CALLBACK timer_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer) { HANDLE semaphore = userdata; - trace("Running timer release callback\n"); ReleaseSemaphore(semaphore, 1, NULL); Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */ pTpReleaseTimer(timer); @@ -735,7 +858,6 @@ static void CALLBACK wait_release_cb(TP_CALLBACK_INSTANCE *instance, void *userd TP_WAIT *wait, TP_WAIT_RESULT result) { HANDLE semaphore = userdata; - trace("Running wait release callback\n"); ReleaseSemaphore(semaphore, 1, NULL); Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */ pTpReleaseWait(wait); @@ -755,18 +877,18 @@ static void test_tp_group_wait(void) DWORD result;
semaphore = CreateSemaphoreA(NULL, 0, 1, NULL); - ok(semaphore != NULL, "CreateSemaphoreA failed %u\n", GetLastError()); + ok(semaphore != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
/* allocate new threadpool */ pool = NULL; status = pTpAllocPool(&pool, NULL); - ok(!status, "TpAllocPool failed with status %x\n", status); + ok(!status, "TpAllocPool failed with status %lx\n", status); ok(pool != NULL, "expected pool != NULL\n");
/* allocate a cleanup group */ group = NULL; status = pTpAllocCleanupGroup(&group); - ok(!status, "TpAllocCleanupGroup failed with status %x\n", status); + ok(!status, "TpAllocCleanupGroup failed with status %lx\n", status); ok(group != NULL, "expected pool != NULL\n");
/* release work object during TpReleaseCleanupGroupMembers */ @@ -776,11 +898,11 @@ static void test_tp_group_wait(void) environment.Pool = pool; environment.CleanupGroup = group; status = pTpAllocWork(&work, work_release_cb, semaphore, &environment); - ok(!status, "TpAllocWork failed with status %x\n", status); + ok(!status, "TpAllocWork failed with status %lx\n", status); ok(work != NULL, "expected work != NULL\n"); pTpPostWork(work); result = WaitForSingleObject(semaphore, 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
/* release timer object during TpReleaseCleanupGroupMembers */ @@ -790,12 +912,12 @@ static void test_tp_group_wait(void) environment.Pool = pool; environment.CleanupGroup = group; status = pTpAllocTimer(&timer, timer_release_cb, semaphore, &environment); - ok(!status, "TpAllocTimer failed with status %x\n", status); + ok(!status, "TpAllocTimer failed with status %lx\n", status); ok(timer != NULL, "expected timer != NULL\n"); when.QuadPart = 0; pTpSetTimer(timer, &when, 0, 0); result = WaitForSingleObject(semaphore, 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
/* release wait object during TpReleaseCleanupGroupMembers */ @@ -805,12 +927,12 @@ static void test_tp_group_wait(void) environment.Pool = pool; environment.CleanupGroup = group; status = pTpAllocWait(&wait, wait_release_cb, semaphore, &environment); - ok(!status, "TpAllocWait failed with status %x\n", status); + ok(!status, "TpAllocWait failed with status %lx\n", status); ok(wait != NULL, "expected wait != NULL\n"); when.QuadPart = 0; pTpSetWait(wait, INVALID_HANDLE_VALUE, &when); result = WaitForSingleObject(semaphore, 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
/* cleanup */ @@ -828,17 +950,15 @@ static void CALLBACK simple_group_cancel_cb(TP_CALLBACK_INSTANCE *instance, void DWORD result; int i;
- trace("Running simple group cancel callback\n"); - status = pTpCallbackMayRunLong(instance); ok(status == STATUS_TOO_MANY_THREADS || broken(status == 1) /* Win Vista / 2008 */, - "expected STATUS_TOO_MANY_THREADS, got %08x\n", status); + "expected STATUS_TOO_MANY_THREADS, got %08lx\n", status);
ReleaseSemaphore(semaphores[1], 1, NULL); for (i = 0; i < 4; i++) { result = WaitForSingleObject(semaphores[0], 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); } ReleaseSemaphore(semaphores[1], 1, NULL); } @@ -848,17 +968,14 @@ static void CALLBACK work_group_cancel_cb(TP_CALLBACK_INSTANCE *instance, void * HANDLE *semaphores = userdata; DWORD result;
- trace("Running work group cancel callback\n"); - ReleaseSemaphore(semaphores[1], 1, NULL); result = WaitForSingleObject(semaphores[0], 200); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); }
static void CALLBACK group_cancel_cleanup_release_cb(void *object, void *userdata) { HANDLE *semaphores = userdata; - trace("Running group cancel cleanup release callback\n"); group_cancel_tid = GetCurrentThreadId(); ok(object == (void *)0xdeadbeef, "expected 0xdeadbeef, got %p\n", object); ReleaseSemaphore(semaphores[0], 1, NULL); @@ -867,7 +984,6 @@ static void CALLBACK group_cancel_cleanup_release_cb(void *object, void *userdat static void CALLBACK group_cancel_cleanup_release2_cb(void *object, void *userdata) { HANDLE *semaphores = userdata; - trace("Running group cancel cleanup release2 callback\n"); group_cancel_tid = GetCurrentThreadId(); ok(object == userdata, "expected %p, got %p\n", userdata, object); ReleaseSemaphore(semaphores[0], 1, NULL); @@ -875,7 +991,6 @@ static void CALLBACK group_cancel_cleanup_release2_cb(void *object, void *userda
static void CALLBACK group_cancel_cleanup_increment_cb(void *object, void *userdata) { - trace("Running group cancel cleanup increment callback\n"); group_cancel_tid = GetCurrentThreadId(); InterlockedIncrement((LONG *)userdata); } @@ -921,21 +1036,21 @@ static void test_tp_group_cancel(void) int i;
semaphores[0] = CreateSemaphoreA(NULL, 0, 4, NULL); - ok(semaphores[0] != NULL, "CreateSemaphoreA failed %u\n", GetLastError()); + ok(semaphores[0] != NULL, "CreateSemaphoreA failed %lu\n", GetLastError()); semaphores[1] = CreateSemaphoreA(NULL, 0, 1, NULL); - ok(semaphores[1] != NULL, "CreateSemaphoreA failed %u\n", GetLastError()); + ok(semaphores[1] != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
/* allocate new threadpool with only one thread */ pool = NULL; status = pTpAllocPool(&pool, NULL); - ok(!status, "TpAllocPool failed with status %x\n", status); + ok(!status, "TpAllocPool failed with status %lx\n", status); ok(pool != NULL, "expected pool != NULL\n"); pTpSetPoolMaxThreads(pool, 1);
/* allocate a cleanup group */ group = NULL; status = pTpAllocCleanupGroup(&group); - ok(!status, "TpAllocCleanupGroup failed with status %x\n", status); + ok(!status, "TpAllocCleanupGroup failed with status %lx\n", status); ok(group != NULL, "expected pool != NULL\n");
/* test execution of cancellation callback */ @@ -943,9 +1058,9 @@ static void test_tp_group_cancel(void) environment.Version = 1; environment.Pool = pool; status = pTpSimpleTryPost(simple_group_cancel_cb, semaphores, &environment); - ok(!status, "TpSimpleTryPost failed with status %x\n", status); + ok(!status, "TpSimpleTryPost failed with status %lx\n", status); result = WaitForSingleObject(semaphores[1], 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
memset(&environment, 0, sizeof(environment)); environment.Version = 1; @@ -953,28 +1068,28 @@ static void test_tp_group_cancel(void) environment.CleanupGroup = group; environment.CleanupGroupCancelCallback = group_cancel_cleanup_release_cb; status = pTpSimpleTryPost(unexpected_simple_cb, (void *)0xdeadbeef, &environment); - ok(!status, "TpSimpleTryPost failed with status %x\n", status); + ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
work = NULL; status = pTpAllocWork(&work, unexpected_work_cb, (void *)0xdeadbeef, &environment); - ok(!status, "TpAllocWork failed with status %x\n", status); + ok(!status, "TpAllocWork failed with status %lx\n", status); ok(work != NULL, "expected work != NULL\n");
timer = NULL; status = pTpAllocTimer(&timer, unexpected_timer_cb, (void *)0xdeadbeef, &environment); - ok(!status, "TpAllocTimer failed with status %x\n", status); + ok(!status, "TpAllocTimer failed with status %lx\n", status); ok(timer != NULL, "expected timer != NULL\n");
wait = NULL; status = pTpAllocWait(&wait, unexpected_wait_cb, (void *)0xdeadbeef, &environment); - ok(!status, "TpAllocWait failed with status %x\n", status); + ok(!status, "TpAllocWait failed with status %lx\n", status); ok(wait != NULL, "expected wait != NULL\n");
group_cancel_tid = 0xdeadbeef; pTpReleaseCleanupGroupMembers(group, TRUE, semaphores); result = WaitForSingleObject(semaphores[1], 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); - ok(group_cancel_tid == GetCurrentThreadId(), "expected tid %x, got %x\n", + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(group_cancel_tid == GetCurrentThreadId(), "expected tid %lx, got %lx\n", GetCurrentThreadId(), group_cancel_tid);
/* test if cancellation callbacks are executed before or after wait */ @@ -985,19 +1100,19 @@ static void test_tp_group_cancel(void) environment.CleanupGroup = group; environment.CleanupGroupCancelCallback = group_cancel_cleanup_release2_cb; status = pTpAllocWork(&work, work_group_cancel_cb, semaphores, &environment); - ok(!status, "TpAllocWork failed with status %x\n", status); + ok(!status, "TpAllocWork failed with status %lx\n", status); ok(work != NULL, "expected work != NULL\n"); pTpPostWork(work); pTpPostWork(work);
result = WaitForSingleObject(semaphores[1], 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
group_cancel_tid = 0xdeadbeef; pTpReleaseCleanupGroupMembers(group, TRUE, semaphores); result = WaitForSingleObject(semaphores[0], 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); - ok(group_cancel_tid == GetCurrentThreadId(), "expected tid %x, got %x\n", + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(group_cancel_tid == GetCurrentThreadId(), "expected tid %lx, got %lx\n", GetCurrentThreadId(), group_cancel_tid);
/* group cancel callback is not executed if object is destroyed while waiting */ @@ -1008,12 +1123,12 @@ static void test_tp_group_cancel(void) environment.CleanupGroup = group; environment.CleanupGroupCancelCallback = unexpected_group_cancel_cleanup_cb; status = pTpAllocWork(&work, work_release_cb, semaphores[1], &environment); - ok(!status, "TpAllocWork failed with status %x\n", status); + ok(!status, "TpAllocWork failed with status %lx\n", status); ok(work != NULL, "expected work != NULL\n"); pTpPostWork(work);
result = WaitForSingleObject(semaphores[1], 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); pTpReleaseCleanupGroupMembers(group, TRUE, NULL);
/* terminated simple callbacks should not trigger the group cancel callback */ @@ -1023,9 +1138,9 @@ static void test_tp_group_cancel(void) environment.CleanupGroup = group; environment.CleanupGroupCancelCallback = unexpected_group_cancel_cleanup_cb; status = pTpSimpleTryPost(simple_release_cb, semaphores[1], &environment); - ok(!status, "TpSimpleTryPost failed with status %x\n", status); + ok(!status, "TpSimpleTryPost failed with status %lx\n", status); result = WaitForSingleObject(semaphores[1], 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); pTpReleaseCleanupGroupMembers(group, TRUE, semaphores);
/* test cancellation callback for objects with multiple instances */ @@ -1036,7 +1151,7 @@ static void test_tp_group_cancel(void) environment.CleanupGroup = group; environment.CleanupGroupCancelCallback = group_cancel_cleanup_increment_cb; status = pTpAllocWork(&work, work_cb, &userdata, &environment); - ok(!status, "TpAllocWork failed with status %x\n", status); + ok(!status, "TpAllocWork failed with status %lx\n", status); ok(work != NULL, "expected work != NULL\n");
/* post 10 identical work items at once */ @@ -1047,9 +1162,9 @@ static void test_tp_group_cancel(void) /* check if we get multiple cancellation callbacks */ group_cancel_tid = 0xdeadbeef; pTpReleaseCleanupGroupMembers(group, TRUE, &userdata2); - ok(userdata <= 5, "expected userdata <= 5, got %u\n", userdata); - ok(userdata2 == 1, "expected only one cancellation callback, got %u\n", userdata2); - ok(group_cancel_tid == GetCurrentThreadId(), "expected tid %x, got %x\n", + ok(userdata <= 5, "expected userdata <= 5, got %lu\n", userdata); + ok(userdata2 == 1, "expected only one cancellation callback, got %lu\n", userdata2); + ok(group_cancel_tid == GetCurrentThreadId(), "expected tid %lx, got %lx\n", GetCurrentThreadId(), group_cancel_tid);
/* cleanup */ @@ -1062,19 +1177,12 @@ static void test_tp_group_cancel(void) static void CALLBACK instance_semaphore_completion_cb(TP_CALLBACK_INSTANCE *instance, void *userdata) { HANDLE *semaphores = userdata; - trace("Running instance completion callback\n"); pTpCallbackReleaseSemaphoreOnCompletion(instance, semaphores[0], 1); }
static void CALLBACK instance_finalization_cb(TP_CALLBACK_INSTANCE *instance, void *userdata) { HANDLE *semaphores = userdata; - DWORD result; - - trace("Running instance finalization callback\n"); - - result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); ReleaseSemaphore(semaphores[1], 1, NULL); }
@@ -1094,7 +1202,7 @@ static void test_tp_instance(void) /* allocate new threadpool */ pool = NULL; status = pTpAllocPool(&pool, NULL); - ok(!status, "TpAllocPool failed with status %x\n", status); + ok(!status, "TpAllocPool failed with status %lx\n", status); ok(pool != NULL, "expected pool != NULL\n");
/* test for TpCallbackReleaseSemaphoreOnCompletion */ @@ -1102,9 +1210,9 @@ static void test_tp_instance(void) environment.Version = 1; environment.Pool = pool; status = pTpSimpleTryPost(instance_semaphore_completion_cb, semaphores, &environment); - ok(!status, "TpSimpleTryPost failed with status %x\n", status); + ok(!status, "TpSimpleTryPost failed with status %lx\n", status); result = WaitForSingleObject(semaphores[0], 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
/* test for finalization callback */ memset(&environment, 0, sizeof(environment)); @@ -1112,11 +1220,11 @@ static void test_tp_instance(void) environment.Pool = pool; environment.FinalizationCallback = instance_finalization_cb; status = pTpSimpleTryPost(instance_semaphore_completion_cb, semaphores, &environment); - ok(!status, "TpSimpleTryPost failed with status %x\n", status); + ok(!status, "TpSimpleTryPost failed with status %lx\n", status); result = WaitForSingleObject(semaphores[0], 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); result = WaitForSingleObject(semaphores[1], 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
/* cleanup */ pTpReleasePool(pool); @@ -1129,11 +1237,9 @@ static void CALLBACK disassociate_cb(TP_CALLBACK_INSTANCE *instance, void *userd HANDLE *semaphores = userdata; DWORD result;
- trace("Running disassociate callback\n"); - pTpDisassociateCallback(instance); result = WaitForSingleObject(semaphores[0], 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); ReleaseSemaphore(semaphores[1], 1, NULL); }
@@ -1142,11 +1248,9 @@ static void CALLBACK disassociate2_cb(TP_CALLBACK_INSTANCE *instance, void *user HANDLE *semaphores = userdata; DWORD result;
- trace("Running disassociate2 callback\n"); - pTpDisassociateCallback(instance); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); ReleaseSemaphore(semaphores[1], 1, NULL); }
@@ -1155,11 +1259,9 @@ static void CALLBACK disassociate3_cb(TP_CALLBACK_INSTANCE *instance, void *user HANDLE *semaphores = userdata; DWORD result;
- trace("Running disassociate3 callback\n"); - pTpDisassociateCallback(instance); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); ReleaseSemaphore(semaphores[1], 1, NULL); }
@@ -1181,12 +1283,12 @@ static void test_tp_disassociate(void) /* allocate new threadpool and cleanup group */ pool = NULL; status = pTpAllocPool(&pool, NULL); - ok(!status, "TpAllocPool failed with status %x\n", status); + ok(!status, "TpAllocPool failed with status %lx\n", status); ok(pool != NULL, "expected pool != NULL\n");
group = NULL; status = pTpAllocCleanupGroup(&group); - ok(!status, "TpAllocCleanupGroup failed with status %x\n", status); + ok(!status, "TpAllocCleanupGroup failed with status %lx\n", status); ok(group != NULL, "expected pool != NULL\n");
/* test TpDisassociateCallback on work objects without group */ @@ -1195,17 +1297,17 @@ static void test_tp_disassociate(void) environment.Version = 1; environment.Pool = pool; status = pTpAllocWork(&work, disassociate_cb, semaphores, &environment); - ok(!status, "TpAllocWork failed with status %x\n", status); + ok(!status, "TpAllocWork failed with status %lx\n", status); ok(work != NULL, "expected work != NULL\n");
pTpPostWork(work); pTpWaitForWork(work, FALSE);
result = WaitForSingleObject(semaphores[1], 100); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); ReleaseSemaphore(semaphores[0], 1, NULL); result = WaitForSingleObject(semaphores[1], 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); pTpReleaseWork(work);
/* test TpDisassociateCallback on work objects with group (1) */ @@ -1215,17 +1317,17 @@ static void test_tp_disassociate(void) environment.Pool = pool; environment.CleanupGroup = group; status = pTpAllocWork(&work, disassociate_cb, semaphores, &environment); - ok(!status, "TpAllocWork failed with status %x\n", status); + ok(!status, "TpAllocWork failed with status %lx\n", status); ok(work != NULL, "expected work != NULL\n");
pTpPostWork(work); pTpWaitForWork(work, FALSE);
result = WaitForSingleObject(semaphores[1], 100); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); ReleaseSemaphore(semaphores[0], 1, NULL); result = WaitForSingleObject(semaphores[1], 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
/* test TpDisassociateCallback on work objects with group (2) */ @@ -1235,7 +1337,7 @@ static void test_tp_disassociate(void) environment.Pool = pool; environment.CleanupGroup = group; status = pTpAllocWork(&work, disassociate2_cb, semaphores, &environment); - ok(!status, "TpAllocWork failed with status %x\n", status); + ok(!status, "TpAllocWork failed with status %lx\n", status); ok(work != NULL, "expected work != NULL\n");
pTpPostWork(work); @@ -1243,9 +1345,9 @@ static void test_tp_disassociate(void)
ReleaseSemaphore(semaphores[0], 1, NULL); result = WaitForSingleObject(semaphores[1], 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); result = WaitForSingleObject(semaphores[0], 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
/* test TpDisassociateCallback on simple callbacks */ memset(&environment, 0, sizeof(environment)); @@ -1253,15 +1355,15 @@ static void test_tp_disassociate(void) environment.Pool = pool; environment.CleanupGroup = group; status = pTpSimpleTryPost(disassociate3_cb, semaphores, &environment); - ok(!status, "TpSimpleTryPost failed with status %x\n", status); + ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
ReleaseSemaphore(semaphores[0], 1, NULL); result = WaitForSingleObject(semaphores[1], 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); result = WaitForSingleObject(semaphores[0], 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
/* cleanup */ pTpReleaseCleanupGroup(group); @@ -1273,7 +1375,6 @@ static void test_tp_disassociate(void) static void CALLBACK timer_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer) { HANDLE semaphore = userdata; - trace("Running timer callback\n"); ReleaseSemaphore(semaphore, 1, NULL); }
@@ -1290,12 +1391,12 @@ static void test_tp_timer(void) int i;
semaphore = CreateSemaphoreA(NULL, 0, 1, NULL); - ok(semaphore != NULL, "CreateSemaphoreA failed %u\n", GetLastError()); + ok(semaphore != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
/* allocate new threadpool */ pool = NULL; status = pTpAllocPool(&pool, NULL); - ok(!status, "TpAllocPool failed with status %x\n", status); + ok(!status, "TpAllocPool failed with status %lx\n", status); ok(pool != NULL, "expected pool != NULL\n");
/* allocate new timer */ @@ -1304,7 +1405,7 @@ static void test_tp_timer(void) environment.Version = 1; environment.Pool = pool; status = pTpAllocTimer(&timer, timer_cb, semaphore, &environment); - ok(!status, "TpAllocTimer failed with status %x\n", status); + ok(!status, "TpAllocTimer failed with status %lx\n", status); ok(timer != NULL, "expected timer != NULL\n");
success = pTpIsTimerSet(timer); @@ -1319,9 +1420,9 @@ static void test_tp_timer(void) pTpWaitForTimer(timer, FALSE);
result = WaitForSingleObject(semaphore, 100); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); result = WaitForSingleObject(semaphore, 200); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); success = pTpIsTimerSet(timer); ok(success, "TpIsTimerSet returned FALSE\n");
@@ -1335,9 +1436,9 @@ static void test_tp_timer(void) pTpWaitForTimer(timer, FALSE);
result = WaitForSingleObject(semaphore, 100); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); result = WaitForSingleObject(semaphore, 200); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); success = pTpIsTimerSet(timer); ok(success, "TpIsTimerSet returned FALSE\n");
@@ -1350,7 +1451,7 @@ static void test_tp_timer(void) pTpWaitForTimer(timer, FALSE);
result = WaitForSingleObject(semaphore, 50); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); success = pTpIsTimerSet(timer); ok(success, "TpIsTimerSet returned FALSE\n");
@@ -1364,7 +1465,7 @@ static void test_tp_timer(void) CloseHandle(semaphore);
semaphore = CreateSemaphoreA(NULL, 0, 3, NULL); - ok(semaphore != NULL, "CreateSemaphoreA failed %u\n", GetLastError()); + ok(semaphore != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
/* allocate a new timer */ timer = NULL; @@ -1372,7 +1473,7 @@ static void test_tp_timer(void) environment.Version = 1; environment.Pool = pool; status = pTpAllocTimer(&timer, timer_cb, semaphore, &environment); - ok(!status, "TpAllocTimer failed with status %x\n", status); + ok(!status, "TpAllocTimer failed with status %lx\n", status); ok(timer != NULL, "expected timer != NULL\n");
/* test a relative timeout repeated periodically */ @@ -1386,11 +1487,11 @@ static void test_tp_timer(void) for (i = 0; i < 3; i++) { result = WaitForSingleObject(semaphore, 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); } ticks = GetTickCount() - ticks; ok(ticks >= 500 && (ticks <= 700 || broken(ticks <= 750)) /* Win 7 */, - "expected approximately 600 ticks, got %u\n", ticks); + "expected approximately 600 ticks, got %lu\n", ticks);
/* unset the timer */ pTpSetTimer(timer, NULL, 0, 0); @@ -1413,7 +1514,6 @@ struct window_length_info static void CALLBACK window_length_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer) { struct window_length_info *info = userdata; - trace("Running window length callback\n"); info->ticks = GetTickCount(); ReleaseSemaphore(info->semaphore, 1, NULL); } @@ -1431,12 +1531,12 @@ static void test_tp_window_length(void) BOOL merged;
semaphore = CreateSemaphoreA(NULL, 0, 2, NULL); - ok(semaphore != NULL, "CreateSemaphoreA failed %u\n", GetLastError()); + ok(semaphore != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
/* allocate new threadpool */ pool = NULL; status = pTpAllocPool(&pool, NULL); - ok(!status, "TpAllocPool failed with status %x\n", status); + ok(!status, "TpAllocPool failed with status %lx\n", status); ok(pool != NULL, "expected pool != NULL\n");
/* allocate two identical timers */ @@ -1447,13 +1547,13 @@ static void test_tp_window_length(void) timer1 = NULL; info1.semaphore = semaphore; status = pTpAllocTimer(&timer1, window_length_cb, &info1, &environment); - ok(!status, "TpAllocTimer failed with status %x\n", status); + ok(!status, "TpAllocTimer failed with status %lx\n", status); ok(timer1 != NULL, "expected timer1 != NULL\n");
timer2 = NULL; info2.semaphore = semaphore; status = pTpAllocTimer(&timer2, window_length_cb, &info2, &environment); - ok(!status, "TpAllocTimer failed with status %x\n", status); + ok(!status, "TpAllocTimer failed with status %lx\n", status); ok(timer2 != NULL, "expected timer2 != NULL\n");
/* choose parameters so that timers are not merged */ @@ -1468,9 +1568,9 @@ static void test_tp_window_length(void) pTpSetTimer(timer1, &when, 0, 75);
result = WaitForSingleObject(semaphore, 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); result = WaitForSingleObject(semaphore, 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); ok(info1.ticks != 0 && info2.ticks != 0, "expected that ticks are nonzero\n"); ok(info2.ticks >= info1.ticks + 75 || broken(info2.ticks < info1.ticks + 75) /* Win 2008 */, "expected that timers are not merged\n"); @@ -1487,9 +1587,9 @@ static void test_tp_window_length(void) pTpSetTimer(timer1, &when, 0, 200);
result = WaitForSingleObject(semaphore, 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); result = WaitForSingleObject(semaphore, 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); ok(info1.ticks != 0 && info2.ticks != 0, "expected that ticks are nonzero\n"); merged = info2.ticks >= info1.ticks - 50 && info2.ticks <= info1.ticks + 50; ok(merged || broken(!merged) /* Win 10 */, "expected that timers are merged\n"); @@ -1506,9 +1606,9 @@ static void test_tp_window_length(void) pTpSetTimer(timer2, &when, 0, 0);
result = WaitForSingleObject(semaphore, 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); result = WaitForSingleObject(semaphore, 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); ok(info1.ticks != 0 && info2.ticks != 0, "expected that ticks are nonzero\n"); merged = info2.ticks >= info1.ticks - 50 && info2.ticks <= info1.ticks + 50; todo_wine @@ -1531,14 +1631,12 @@ static void CALLBACK wait_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WAIT *wait, TP_WAIT_RESULT result) { struct wait_info *info = userdata; - trace("Running wait callback\n"); - if (result == WAIT_OBJECT_0) InterlockedIncrement(&info->userdata); else if (result == WAIT_TIMEOUT) InterlockedExchangeAdd(&info->userdata, 0x10000); else - ok(0, "unexpected result %u\n", result); + ok(0, "unexpected result %lu\n", result); ReleaseSemaphore(info->semaphore, 1, NULL); }
@@ -1562,7 +1660,7 @@ static void test_tp_wait(void) /* allocate new threadpool */ pool = NULL; status = pTpAllocPool(&pool, NULL); - ok(!status, "TpAllocPool failed with status %x\n", status); + ok(!status, "TpAllocPool failed with status %lx\n", status); ok(pool != NULL, "expected pool != NULL\n");
/* allocate new wait items */ @@ -1572,12 +1670,12 @@ static void test_tp_wait(void)
wait1 = NULL; status = pTpAllocWait(&wait1, wait_cb, &info, &environment); - ok(!status, "TpAllocWait failed with status %x\n", status); + ok(!status, "TpAllocWait failed with status %lx\n", status); ok(wait1 != NULL, "expected wait1 != NULL\n");
wait2 = NULL; status = pTpAllocWait(&wait2, wait_cb, &info, &environment); - ok(!status, "TpAllocWait failed with status %x\n", status); + ok(!status, "TpAllocWait failed with status %lx\n", status); ok(wait2 != NULL, "expected wait2 != NULL\n");
/* infinite timeout, signal the semaphore immediately */ @@ -1585,79 +1683,79 @@ static void test_tp_wait(void) pTpSetWait(wait1, semaphores[1], NULL); ReleaseSemaphore(semaphores[1], 1, NULL); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); result = WaitForSingleObject(semaphores[1], 0); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
/* relative timeout, no event */ info.userdata = 0; when.QuadPart = (ULONGLONG)200 * -10000; pTpSetWait(wait1, semaphores[1], &when); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata); result = WaitForSingleObject(semaphores[0], 200); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata); result = WaitForSingleObject(semaphores[1], 0); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
/* repeat test with call to TpWaitForWait(..., TRUE) */ info.userdata = 0; when.QuadPart = (ULONGLONG)200 * -10000; pTpSetWait(wait1, semaphores[1], &when); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); pTpWaitForWait(wait1, TRUE); - ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); + ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata); result = WaitForSingleObject(semaphores[0], 200); ok(result == WAIT_OBJECT_0 || broken(result == WAIT_TIMEOUT) /* Win 8 */, - "WaitForSingleObject returned %u\n", result); + "WaitForSingleObject returned %lu\n", result); if (result == WAIT_OBJECT_0) - ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata); + ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata); else - ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); + ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata); result = WaitForSingleObject(semaphores[1], 0); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
/* relative timeout, with event */ info.userdata = 0; when.QuadPart = (ULONGLONG)200 * -10000; pTpSetWait(wait1, semaphores[1], &when); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata); ReleaseSemaphore(semaphores[1], 1, NULL); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); result = WaitForSingleObject(semaphores[1], 0); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
/* repeat test with call to TpWaitForWait(..., TRUE) */ info.userdata = 0; when.QuadPart = (ULONGLONG)200 * -10000; pTpSetWait(wait1, semaphores[1], &when); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); pTpWaitForWait(wait1, TRUE); - ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); + ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata); ReleaseSemaphore(semaphores[1], 1, NULL); result = WaitForSingleObject(semaphores[0], 100); ok(result == WAIT_OBJECT_0 || broken(result == WAIT_TIMEOUT) /* Win 8 */, - "WaitForSingleObject returned %u\n", result); + "WaitForSingleObject returned %lu\n", result); if (result == WAIT_OBJECT_0) { - ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); + ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); result = WaitForSingleObject(semaphores[1], 0); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); } else { - ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); + ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata); result = WaitForSingleObject(semaphores[1], 0); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); }
/* absolute timeout, no event */ @@ -1666,13 +1764,13 @@ static void test_tp_wait(void) when.QuadPart += (ULONGLONG)200 * 10000; pTpSetWait(wait1, semaphores[1], &when); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata); result = WaitForSingleObject(semaphores[0], 200); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata); result = WaitForSingleObject(semaphores[1], 0); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
/* absolute timeout, with event */ info.userdata = 0; @@ -1680,63 +1778,63 @@ static void test_tp_wait(void) when.QuadPart += (ULONGLONG)200 * 10000; pTpSetWait(wait1, semaphores[1], &when); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata); ReleaseSemaphore(semaphores[1], 1, NULL); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); result = WaitForSingleObject(semaphores[1], 0); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
/* test timeout of zero */ info.userdata = 0; when.QuadPart = 0; pTpSetWait(wait1, semaphores[1], &when); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata); result = WaitForSingleObject(semaphores[1], 0); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
/* cancel a pending wait */ info.userdata = 0; when.QuadPart = (ULONGLONG)250 * -10000; pTpSetWait(wait1, semaphores[1], &when); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); pTpSetWait(wait1, NULL, (void *)0xdeadbeef); Sleep(50); ReleaseSemaphore(semaphores[1], 1, NULL); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata); result = WaitForSingleObject(semaphores[1], 0); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
/* test with INVALID_HANDLE_VALUE */ info.userdata = 0; when.QuadPart = 0; pTpSetWait(wait1, INVALID_HANDLE_VALUE, &when); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
/* cancel a pending wait with INVALID_HANDLE_VALUE */ info.userdata = 0; when.QuadPart = (ULONGLONG)250 * -10000; pTpSetWait(wait1, semaphores[1], &when); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); when.QuadPart = 0; pTpSetWait(wait1, INVALID_HANDLE_VALUE, &when); Sleep(50); ReleaseSemaphore(semaphores[1], 1, NULL); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata); result = WaitForSingleObject(semaphores[1], 0); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
CloseHandle(semaphores[1]); semaphores[1] = CreateSemaphoreW(NULL, 0, 2, NULL); @@ -1749,12 +1847,12 @@ static void test_tp_wait(void) Sleep(50); ReleaseSemaphore(semaphores[1], 1, NULL); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); result = WaitForSingleObject(semaphores[1], 0); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
/* repeat test above with release count 2 */ info.userdata = 0; @@ -1763,12 +1861,12 @@ static void test_tp_wait(void) Sleep(50); result = ReleaseSemaphore(semaphores[1], 2, NULL); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); result = WaitForSingleObject(semaphores[0], 100); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); - ok(info.userdata == 2, "expected info.userdata = 2, got %u\n", info.userdata); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(info.userdata == 2, "expected info.userdata = 2, got %lu\n", info.userdata); result = WaitForSingleObject(semaphores[1], 0); - ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
/* cleanup */ pTpReleaseWait(wait1); @@ -1793,12 +1891,13 @@ static void CALLBACK multi_wait_cb(TP_CALLBACK_INSTANCE *instance, void *userdat else if (result == WAIT_TIMEOUT) multi_wait_info.result = 0x10000 | index; else - ok(0, "unexpected result %u\n", result); + ok(0, "unexpected result %lu\n", result); ReleaseSemaphore(multi_wait_info.semaphore, 1, NULL); }
static void test_tp_multi_wait(void) { + TP_POOL_STACK_INFORMATION stack_info; TP_CALLBACK_ENVIRON environment; HANDLE semaphores[512]; TP_WAIT *waits[512]; @@ -1816,78 +1915,83 @@ static void test_tp_multi_wait(void) /* allocate new threadpool */ pool = NULL; status = pTpAllocPool(&pool, NULL); - ok(!status, "TpAllocPool failed with status %x\n", status); + ok(!status, "TpAllocPool failed with status %lx\n", status); ok(pool != NULL, "expected pool != NULL\n"); + /* many threads -> use the smallest stack possible */ + stack_info.StackReserve = 256 * 1024; + stack_info.StackCommit = 4 * 1024; + status = pTpSetPoolStackInformation(pool, &stack_info); + ok(!status, "TpQueryPoolStackInformation failed: %lx\n", status);
memset(&environment, 0, sizeof(environment)); environment.Version = 1; environment.Pool = pool;
/* create semaphores and corresponding wait objects */ - for (i = 0; i < sizeof(semaphores)/sizeof(semaphores[0]); i++) + for (i = 0; i < ARRAY_SIZE(semaphores); i++) { semaphores[i] = CreateSemaphoreW(NULL, 0, 1, NULL); ok(semaphores[i] != NULL, "failed to create semaphore %i\n", i);
waits[i] = NULL; status = pTpAllocWait(&waits[i], multi_wait_cb, (void *)(DWORD_PTR)i, &environment); - ok(!status, "TpAllocWait failed with status %x\n", status); + ok(!status, "TpAllocWait failed with status %lx\n", status); ok(waits[i] != NULL, "expected waits[%d] != NULL\n", i);
pTpSetWait(waits[i], semaphores[i], NULL); }
/* release all semaphores and wait for callback */ - for (i = 0; i < sizeof(semaphores)/sizeof(semaphores[0]); i++) + for (i = 0; i < ARRAY_SIZE(semaphores); i++) { multi_wait_info.result = 0; ReleaseSemaphore(semaphores[i], 1, NULL);
- result = WaitForSingleObject(semaphore, 100); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); - ok(multi_wait_info.result == i, "expected result %d, got %u\n", i, multi_wait_info.result); + result = WaitForSingleObject(semaphore, 2000); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(multi_wait_info.result == i, "expected result %d, got %lu\n", i, multi_wait_info.result);
pTpSetWait(waits[i], semaphores[i], NULL); }
/* repeat the same test in reverse order */ - for (i = sizeof(semaphores)/sizeof(semaphores[0]) - 1; i >= 0; i--) + for (i = ARRAY_SIZE(semaphores) - 1; i >= 0; i--) { multi_wait_info.result = 0; ReleaseSemaphore(semaphores[i], 1, NULL);
- result = WaitForSingleObject(semaphore, 100); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); - ok(multi_wait_info.result == i, "expected result %d, got %u\n", i, multi_wait_info.result); + result = WaitForSingleObject(semaphore, 2000); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + ok(multi_wait_info.result == i, "expected result %d, got %lu\n", i, multi_wait_info.result);
pTpSetWait(waits[i], semaphores[i], NULL); }
/* test timeout of wait objects */ multi_wait_info.result = 0; - for (i = 0; i < sizeof(semaphores)/sizeof(semaphores[0]); i++) + for (i = 0; i < ARRAY_SIZE(semaphores); i++) { when.QuadPart = (ULONGLONG)50 * -10000; pTpSetWait(waits[i], semaphores[i], &when); }
- for (i = 0; i < sizeof(semaphores)/sizeof(semaphores[0]); i++) + for (i = 0; i < ARRAY_SIZE(semaphores); i++) { - result = WaitForSingleObject(semaphore, 150); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + result = WaitForSingleObject(semaphore, 2000); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); }
ok(multi_wait_info.result >> 16, "expected multi_wait_info.result >> 16 != 0\n");
/* destroy the wait objects and semaphores while waiting */ - for (i = 0; i < sizeof(semaphores)/sizeof(semaphores[0]); i++) + for (i = 0; i < ARRAY_SIZE(semaphores); i++) { pTpSetWait(waits[i], semaphores[i], NULL); }
Sleep(50);
- for (i = 0; i < sizeof(semaphores)/sizeof(semaphores[0]); i++) + for (i = 0; i < ARRAY_SIZE(semaphores); i++) { pTpReleaseWait(waits[i]); NtClose(semaphores[i]); @@ -1897,6 +2001,385 @@ static void test_tp_multi_wait(void) CloseHandle(semaphore); }
+struct io_cb_ctx +{ + unsigned int count; + void *ovl; + NTSTATUS ret; + ULONG_PTR length; + TP_IO *io; +}; + +static void CALLBACK io_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, + void *cvalue, IO_STATUS_BLOCK *iosb, TP_IO *io) +{ + struct io_cb_ctx *ctx = userdata; + ++ctx->count; + ctx->ovl = cvalue; + ctx->ret = iosb->Status; + ctx->length = iosb->Information; + ctx->io = io; +} + +static DWORD WINAPI io_wait_thread(void *arg) +{ + TP_IO *io = arg; + pTpWaitForIoCompletion(io, FALSE); + return 0; +} + +static void test_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 %#lx\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 %lu.\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 %lu.\n", GetLastError()); + + environment.Pool = pool; + io = NULL; + status = pTpAllocIoCompletion(&io, server, io_cb, &userdata, &environment); + ok(!status, "got %#lx\n", status); + ok(!!io, "expected non-NULL TP_IO\n"); + + pTpWaitForIoCompletion(io, FALSE); + + userdata.count = 0; + pTpStartAsyncIoOperation(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 %lu\n", GetLastError()); + + ret = WriteFile(client, out, sizeof(out), &ret_size, NULL); + ok(ret, "WriteFile() failed, error %lu\n", GetLastError()); + + pTpWaitForIoCompletion(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 == STATUS_SUCCESS, "got status %#lx\n", userdata.ret); + ok(userdata.length == 1, "got length %Iu\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; + pTpStartAsyncIoOperation(io); + pTpStartAsyncIoOperation(io); + + ret = ReadFile(server, in, sizeof(in), NULL, &ovl); + ok(!ret, "wrong ret %d\n", ret); + ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError()); + ret = ReadFile(server, in2, sizeof(in2), NULL, &ovl2); + ok(!ret, "wrong ret %d\n", ret); + ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError()); + + ret = WriteFile(client, out, sizeof(out), &ret_size, NULL); + ok(ret, "WriteFile() failed, error %lu\n", GetLastError()); + ret = WriteFile(client, out, sizeof(out), &ret_size, NULL); + ok(ret, "WriteFile() failed, error %lu\n", GetLastError()); + + pTpWaitForIoCompletion(io, FALSE); + ok(userdata.count == 2, "callback ran %u times\n", userdata.count); + ok(userdata.ret == STATUS_SUCCESS, "got status %#lx\n", userdata.ret); + ok(userdata.length == 1, "got length %Iu\n", userdata.length); + ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io); + + /* The documentation is a bit unclear about passing TRUE to + * WaitForThreadpoolIoCallbacks()—"pending I/O requests are not canceled" + * [as with CancelIoEx()], but pending threadpool callbacks are, even those + * which have not yet reached the completion port [as with + * TpCancelAsyncIoOperation()]. */ + userdata.count = 0; + pTpStartAsyncIoOperation(io); + + pTpWaitForIoCompletion(io, TRUE); + ok(!userdata.count, "callback ran %u times\n", userdata.count); + + pTpStartAsyncIoOperation(io); + + ret = WriteFile(client, out, sizeof(out), &ret_size, NULL); + ok(ret, "WriteFile() failed, error %lu\n", GetLastError()); + + ret = ReadFile(server, in, sizeof(in), NULL, &ovl); + ok(ret, "wrong ret %d\n", ret); + + pTpWaitForIoCompletion(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 == STATUS_SUCCESS, "got status %#lx\n", userdata.ret); + ok(userdata.length == 1, "got length %Iu\n", userdata.length); + ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io); + + userdata.count = 0; + pTpStartAsyncIoOperation(io); + + ret = ReadFile(server, NULL, 1, NULL, &ovl); + ok(!ret, "wrong ret %d\n", ret); + ok(GetLastError() == ERROR_NOACCESS, "wrong error %lu\n", GetLastError()); + + pTpCancelAsyncIoOperation(io); + pTpWaitForIoCompletion(io, FALSE); + ok(!userdata.count, "callback ran %u times\n", userdata.count); + + userdata.count = 0; + pTpStartAsyncIoOperation(io); + + ret = ReadFile(server, in, sizeof(in), NULL, &ovl); + ok(!ret, "wrong ret %d\n", ret); + ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError()); + ret = CancelIo(server); + ok(ret, "CancelIo() failed, error %lu\n", GetLastError()); + + pTpWaitForIoCompletion(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 == STATUS_CANCELLED, "got status %#lx\n", userdata.ret); + ok(!userdata.length, "got length %Iu\n", userdata.length); + ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io); + + userdata.count = 0; + pTpStartAsyncIoOperation(io); + pTpCancelAsyncIoOperation(io); + ret = ReadFile(server, in, sizeof(in), NULL, &ovl); + ok(!ret, "wrong ret %d\n", ret); + ret = WriteFile(client, out, sizeof(out), &ret_size, NULL); + ok(ret, "WriteFile() failed, error %lu\n", GetLastError()); + ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError()); + + pTpWaitForIoCompletion(io, FALSE); + if (0) + { + /* Add a sleep to check that callback is not called later. Commented out to + * save the test time. */ + Sleep(200); + } + ok(userdata.count == 0, "callback ran %u times\n", userdata.count); + + pTpReleaseIoCompletion(io); + CloseHandle(server); + + /* Test TPIO object destruction. */ + 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 %lu.\n", GetLastError()); + io = NULL; + status = pTpAllocIoCompletion(&io, server, io_cb, &userdata, &environment); + ok(!status, "got %#lx\n", status); + + ret = HeapValidate(GetProcessHeap(), 0, io); + ok(ret, "Got unexpected ret %#x.\n", ret); + pTpReleaseIoCompletion(io); + ret = HeapValidate(GetProcessHeap(), 0, io); + ok(!ret, "Got unexpected ret %#x.\n", ret); + CloseHandle(server); + CloseHandle(client); + + 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 %lu.\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 %lu.\n", GetLastError()); + + io = NULL; + status = pTpAllocIoCompletion(&io, server, io_cb, &userdata, &environment); + ok(!status, "got %#lx\n", status); + pTpStartAsyncIoOperation(io); + pTpWaitForIoCompletion(io, TRUE); + ret = HeapValidate(GetProcessHeap(), 0, io); + ok(ret, "Got unexpected ret %#x.\n", ret); + pTpReleaseIoCompletion(io); + ret = HeapValidate(GetProcessHeap(), 0, io); + ok(ret, "Got unexpected ret %#x.\n", ret); + + if (0) + { + /* Object destruction will wait until one completion arrives (which was started but not cancelled). + * Commented out to save test time. */ + Sleep(1000); + ret = HeapValidate(GetProcessHeap(), 0, io); + ok(ret, "Got unexpected ret %#x.\n", ret); + ret = ReadFile(server, in, sizeof(in), NULL, &ovl); + ok(!ret, "wrong ret %d\n", ret); + ret = WriteFile(client, out, sizeof(out), &ret_size, NULL); + ok(ret, "WriteFile() failed, error %lu\n", GetLastError()); + Sleep(2000); + ret = HeapValidate(GetProcessHeap(), 0, io); + ok(!ret, "Got unexpected ret %#x.\n", ret); + } + + CloseHandle(server); + CloseHandle(ovl.hEvent); + CloseHandle(client); + 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 %#lx\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 %lu.\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 %lu.\n", GetLastError()); + + environment.Pool = pool; + io = NULL; + io = pCreateThreadpoolIo(server, kernel32_io_cb, &userdata, &environment); + ok(!!io, "expected non-NULL TP_IO\n"); + + 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 %lu\n", GetLastError()); + + ret = WriteFile(client, out, sizeof(out), &ret_size, NULL); + ok(ret, "WriteFile() failed, error %lu\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 %#lx\n", userdata.ret); + ok(userdata.length == 1, "got length %Iu\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 %lu\n", GetLastError()); + ret = ReadFile(server, in2, sizeof(in2), NULL, &ovl2); + ok(!ret, "wrong ret %d\n", ret); + ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError()); + + ret = WriteFile(client, out, sizeof(out), &ret_size, NULL); + ok(ret, "WriteFile() failed, error %lu\n", GetLastError()); + ret = WriteFile(client, out, sizeof(out), &ret_size, NULL); + ok(ret, "WriteFile() failed, error %lu\n", GetLastError()); + + pWaitForThreadpoolIoCallbacks(io, FALSE); + ok(userdata.count == 2, "callback ran %u times\n", userdata.count); + ok(userdata.ret == STATUS_SUCCESS, "got status %#lx\n", userdata.ret); + ok(userdata.length == 1, "got length %Iu\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 %lu\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 %#lx\n", userdata.ret); + ok(userdata.length == 1, "got length %Iu\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 %lu\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 %lu\n", GetLastError()); + ret = CancelIo(server); + ok(ret, "CancelIo() failed, error %lu\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 %#lx\n", userdata.ret); + ok(!userdata.length, "got length %Iu\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(); @@ -1916,4 +2399,6 @@ START_TEST(threadpool) test_tp_window_length(); test_tp_wait(); test_tp_multi_wait(); + test_tp_io(); + test_kernel32_tp_io(); }