From: Conor McCarthy cmccarthy@codeweavers.com
--- dlls/ntdll/tests/threadpool.c | 91 +++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+)
diff --git a/dlls/ntdll/tests/threadpool.c b/dlls/ntdll/tests/threadpool.c index f330cf0671e..b903165a4fb 100644 --- a/dlls/ntdll/tests/threadpool.c +++ b/dlls/ntdll/tests/threadpool.c @@ -2387,6 +2387,96 @@ static void test_kernel32_tp_io(void) pTpReleasePool(pool); }
+static void test_tp_wait_early_closure(void) +{ + TP_CALLBACK_ENVIRON environment; + TP_WAIT *wait1, *wait2; + struct wait_info info; + HANDLE semaphores[2]; + LARGE_INTEGER when; + HANDLE semaphore; + NTSTATUS status; + TP_POOL *pool; + HANDLE timer; + DWORD result; + + semaphores[0] = CreateSemaphoreW(NULL, 0, 2, NULL); + ok(semaphores[0] != NULL, "failed to create semaphore\n"); + semaphores[1] = CreateSemaphoreW(NULL, 0, 1, NULL); + ok(semaphores[1] != NULL, "failed to create semaphore\n"); + semaphore = CreateSemaphoreW(NULL, 0, 1, NULL); + ok(semaphore != NULL, "failed to create semaphore\n"); + timer = CreateWaitableTimerW(NULL, TRUE, NULL); + ok(timer != NULL, "failed to create waitable timer\n"); + info.semaphore = semaphore; + + /* allocate new threadpool */ + pool = NULL; + status = pTpAllocPool(&pool, NULL); + ok(!status, "TpAllocPool failed with status %lx\n", status); + ok(pool != NULL, "expected pool != NULL\n"); + + /* allocate new wait items */ + memset(&environment, 0, sizeof(environment)); + environment.Version = 1; + environment.Pool = pool; + + wait1 = NULL; + status = pTpAllocWait(&wait1, wait_cb, &info, &environment); + 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 %lx\n", status); + ok(wait2 != NULL, "expected wait2 != NULL\n"); + + /* waitable timer closed immediately, and a semaphore */ + when.QuadPart = (ULONGLONG)100 * -10000; + status = NtSetTimer(timer, &when, NULL, NULL, FALSE, 0, NULL); + ok(!status, "NtSetTimer returned status %lx\n", status); + info.userdata = 0; + pTpSetWait(wait1, timer, NULL); + CloseHandle(timer); + pTpSetWait(wait2, semaphores[0], NULL); + result = WaitForSingleObject(semaphore, 200); + todo_wine + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx\n", result); + ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); + ReleaseSemaphore(semaphores[0], 1, NULL); + result = WaitForSingleObject(semaphore, 200); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx\n", result); + todo_wine + ok(info.userdata == 2, "expected info.userdata = 2, got %lu\n", info.userdata); + result = WaitForSingleObject(semaphores[0], 0); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %#lx\n", result); + + /* two semaphores, the first closed immediately */ + info.userdata = 0; + when.QuadPart = (ULONGLONG)200 * -10000; + pTpSetWait(wait1, semaphores[0], &when); + CloseHandle(semaphores[0]); + pTpSetWait(wait2, semaphores[1], NULL); + ReleaseSemaphore(semaphores[1], 1, NULL); + result = WaitForSingleObject(semaphore, 100); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx\n", result); + todo_wine + ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); + result = WaitForSingleObject(semaphores[1], 0); + ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %#lx\n", result); + result = WaitForSingleObject(semaphore, 300); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx\n", result); + todo_wine + ok(info.userdata == 0x10001, "expected info.userdata = 0x10001, got %lu\n", info.userdata); + + /* cleanup */ + pTpReleaseWait(wait1); + pTpReleaseWait(wait2); + pTpReleasePool(pool); + CloseHandle(semaphores[1]); + CloseHandle(semaphore); +} + START_TEST(threadpool) { test_RtlQueueWorkItem(); @@ -2408,4 +2498,5 @@ START_TEST(threadpool) test_tp_multi_wait(); test_tp_io(); test_kernel32_tp_io(); + test_tp_wait_early_closure(); }