[4/7] ntdll/tests: Add basic tests for threadpool wait objects.

Sebastian Lackner sebastian at fds-team.de
Sat Jul 4 19:24:02 CDT 2015


---
 dlls/ntdll/tests/threadpool.c |  266 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 266 insertions(+)

diff --git a/dlls/ntdll/tests/threadpool.c b/dlls/ntdll/tests/threadpool.c
index 0671202..b40e0c1 100644
--- a/dlls/ntdll/tests/threadpool.c
+++ b/dlls/ntdll/tests/threadpool.c
@@ -24,11 +24,13 @@ static HMODULE hntdll = 0;
 static NTSTATUS (WINAPI *pTpAllocCleanupGroup)(TP_CLEANUP_GROUP **);
 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 *pTpDisassociateCallback)(TP_CALLBACK_INSTANCE *);
 static BOOL     (WINAPI *pTpIsTimerSet)(TP_TIMER *);
+static VOID     (WINAPI *pTpReleaseWait)(TP_WAIT *);
 static VOID     (WINAPI *pTpPostWork)(TP_WORK *);
 static VOID     (WINAPI *pTpReleaseCleanupGroup)(TP_CLEANUP_GROUP *);
 static VOID     (WINAPI *pTpReleaseCleanupGroupMembers)(TP_CLEANUP_GROUP *,BOOL,PVOID);
@@ -37,8 +39,10 @@ static VOID     (WINAPI *pTpReleaseTimer)(TP_TIMER *);
 static VOID     (WINAPI *pTpReleaseWork)(TP_WORK *);
 static VOID     (WINAPI *pTpSetPoolMaxThreads)(TP_POOL *,DWORD);
 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 *pTpWaitForTimer)(TP_TIMER *,BOOL);
+static VOID     (WINAPI *pTpWaitForWait)(TP_WAIT *,BOOL);
 static VOID     (WINAPI *pTpWaitForWork)(TP_WORK *,BOOL);
 
 #define NTDLL_GET_PROC(func) \
@@ -61,6 +65,7 @@ static BOOL init_threadpool(void)
     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);
@@ -71,11 +76,14 @@ static BOOL init_threadpool(void)
     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);
 
     if (!pTpAllocPool)
@@ -906,6 +914,263 @@ static void test_tp_window_length(void)
     CloseHandle(semaphore);
 }
 
+struct wait_info
+{
+    HANDLE semaphore;
+    LONG userdata;
+};
+
+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);
+    ReleaseSemaphore(info->semaphore, 1, NULL);
+}
+
+static void test_tp_wait(void)
+{
+    TP_CALLBACK_ENVIRON environment;
+    TP_WAIT *wait1, *wait2;
+    struct wait_info info;
+    HANDLE semaphores[2];
+    LARGE_INTEGER when;
+    NTSTATUS status;
+    TP_POOL *pool;
+    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");
+    info.semaphore = semaphores[0];
+
+    /* allocate new threadpool */
+    pool = NULL;
+    status = pTpAllocPool(&pool, NULL);
+    ok(!status, "TpAllocPool failed with status %x\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 %x\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(wait2 != NULL, "expected wait2 != NULL\n");
+
+    /* infinite timeout, signal the semaphore immediately */
+    info.userdata = 0;
+    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);
+    result = WaitForSingleObject(semaphores[1], 0);
+    ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\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);
+    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);
+    result = WaitForSingleObject(semaphores[1], 0);
+    ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\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);
+    pTpWaitForWait(wait1, TRUE);
+    ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata);
+    result = WaitForSingleObject(semaphores[0], 200);
+    ok(result == WAIT_OBJECT_0 || broken(result == WAIT_TIMEOUT) /* Win 8 */,
+       "WaitForSingleObject returned %u\n", result);
+    if (result == WAIT_OBJECT_0)
+        ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata);
+    else
+        ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata);
+    result = WaitForSingleObject(semaphores[1], 0);
+    ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\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);
+    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);
+    result = WaitForSingleObject(semaphores[1], 0);
+    ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\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);
+    pTpWaitForWait(wait1, TRUE);
+    ok(info.userdata == 0, "expected info.userdata = 0, got %u\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);
+    if (result == WAIT_OBJECT_0)
+    {
+        ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata);
+        result = WaitForSingleObject(semaphores[1], 0);
+        ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
+    }
+    else
+    {
+        ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata);
+        result = WaitForSingleObject(semaphores[1], 0);
+        ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
+    }
+
+    /* absolute timeout, no event */
+    info.userdata = 0;
+    NtQuerySystemTime( &when );
+    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);
+    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);
+    result = WaitForSingleObject(semaphores[1], 0);
+    ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
+
+    /* absolute timeout, with event */
+    info.userdata = 0;
+    NtQuerySystemTime( &when );
+    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);
+    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);
+    result = WaitForSingleObject(semaphores[1], 0);
+    ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\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);
+    result = WaitForSingleObject(semaphores[1], 0);
+    ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\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);
+    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);
+    result = WaitForSingleObject(semaphores[1], 0);
+    ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\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);
+
+    /* 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);
+    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);
+    result = WaitForSingleObject(semaphores[1], 0);
+    ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
+
+    CloseHandle(semaphores[1]);
+    semaphores[1] = CreateSemaphoreW(NULL, 0, 2, NULL);
+    ok(semaphores[1] != NULL, "failed to create semaphore\n");
+
+    /* add two wait objects with the same semaphore */
+    info.userdata = 0;
+    pTpSetWait(wait1, semaphores[1], NULL);
+    pTpSetWait(wait2, semaphores[1], NULL);
+    Sleep(50);
+    ReleaseSemaphore(semaphores[1], 1, NULL);
+    result = WaitForSingleObject(semaphores[0], 100);
+    ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\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);
+    result = WaitForSingleObject(semaphores[1], 0);
+    ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
+
+    /* repeat test above with release count 2 */
+    info.userdata = 0;
+    pTpSetWait(wait1, semaphores[1], NULL);
+    pTpSetWait(wait2, semaphores[1], NULL);
+    Sleep(50);
+    result = ReleaseSemaphore(semaphores[1], 2, NULL);
+    result = WaitForSingleObject(semaphores[0], 100);
+    ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\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);
+    result = WaitForSingleObject(semaphores[1], 0);
+    ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
+
+    /* cleanup */
+    pTpReleaseWait(wait1);
+    pTpReleaseWait(wait2);
+    pTpReleasePool(pool);
+    CloseHandle(semaphores[0]);
+    CloseHandle(semaphores[1]);
+}
+
 START_TEST(threadpool)
 {
     if (!init_threadpool())
@@ -919,4 +1184,5 @@ START_TEST(threadpool)
     test_tp_disassociate();
     test_tp_timer();
     test_tp_window_length();
+    test_tp_wait();
 }
-- 
2.4.4



More information about the wine-patches mailing list