ntdll/tests: Add basic tests for threadpool wait objects.
This commit is contained in:
parent
185247576b
commit
553ae488d0
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue