Reactos
at master 2420 lines 98 kB view raw
1/* 2 * Unit test suite for thread pool functions 3 * 4 * Copyright 2015-2016 Sebastian Lackner 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21#include "ntdll_test.h" 22 23#ifdef __REACTOS__ 24typedef void (CALLBACK *PTP_IO_CALLBACK)(PTP_CALLBACK_INSTANCE,void*,void*,IO_STATUS_BLOCK*,PTP_IO); 25#endif 26 27static NTSTATUS (WINAPI *pTpAllocCleanupGroup)(TP_CLEANUP_GROUP **); 28static NTSTATUS (WINAPI *pTpAllocIoCompletion)(TP_IO **,HANDLE,PTP_IO_CALLBACK,void *,TP_CALLBACK_ENVIRON *); 29static NTSTATUS (WINAPI *pTpAllocPool)(TP_POOL **,PVOID); 30static NTSTATUS (WINAPI *pTpAllocTimer)(TP_TIMER **,PTP_TIMER_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *); 31static NTSTATUS (WINAPI *pTpAllocWait)(TP_WAIT **,PTP_WAIT_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *); 32static NTSTATUS (WINAPI *pTpAllocWork)(TP_WORK **,PTP_WORK_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *); 33static NTSTATUS (WINAPI *pTpCallbackMayRunLong)(TP_CALLBACK_INSTANCE *); 34static VOID (WINAPI *pTpCallbackReleaseSemaphoreOnCompletion)(TP_CALLBACK_INSTANCE *,HANDLE,DWORD); 35static void (WINAPI *pTpCancelAsyncIoOperation)(TP_IO *); 36static VOID (WINAPI *pTpDisassociateCallback)(TP_CALLBACK_INSTANCE *); 37static BOOL (WINAPI *pTpIsTimerSet)(TP_TIMER *); 38static VOID (WINAPI *pTpPostWork)(TP_WORK *); 39static NTSTATUS (WINAPI *pTpQueryPoolStackInformation)(TP_POOL *,TP_POOL_STACK_INFORMATION *); 40static VOID (WINAPI *pTpReleaseCleanupGroup)(TP_CLEANUP_GROUP *); 41static VOID (WINAPI *pTpReleaseCleanupGroupMembers)(TP_CLEANUP_GROUP *,BOOL,PVOID); 42static void (WINAPI *pTpReleaseIoCompletion)(TP_IO *); 43static VOID (WINAPI *pTpReleasePool)(TP_POOL *); 44static VOID (WINAPI *pTpReleaseTimer)(TP_TIMER *); 45static VOID (WINAPI *pTpReleaseWait)(TP_WAIT *); 46static VOID (WINAPI *pTpReleaseWork)(TP_WORK *); 47static VOID (WINAPI *pTpSetPoolMaxThreads)(TP_POOL *,DWORD); 48static NTSTATUS (WINAPI *pTpSetPoolStackInformation)(TP_POOL *,TP_POOL_STACK_INFORMATION *); 49static VOID (WINAPI *pTpSetTimer)(TP_TIMER *,LARGE_INTEGER *,LONG,LONG); 50static VOID (WINAPI *pTpSetWait)(TP_WAIT *,HANDLE,LARGE_INTEGER *); 51static NTSTATUS (WINAPI *pTpSimpleTryPost)(PTP_SIMPLE_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *); 52static void (WINAPI *pTpStartAsyncIoOperation)(TP_IO *); 53static void (WINAPI *pTpWaitForIoCompletion)(TP_IO *,BOOL); 54static VOID (WINAPI *pTpWaitForTimer)(TP_TIMER *,BOOL); 55static VOID (WINAPI *pTpWaitForWait)(TP_WAIT *,BOOL); 56static VOID (WINAPI *pTpWaitForWork)(TP_WORK *,BOOL); 57 58static void (WINAPI *pCancelThreadpoolIo)(TP_IO *); 59static void (WINAPI *pCloseThreadpoolIo)(TP_IO *); 60static TP_IO *(WINAPI *pCreateThreadpoolIo)(HANDLE, PTP_WIN32_IO_CALLBACK, void *, TP_CALLBACK_ENVIRON *); 61static void (WINAPI *pStartThreadpoolIo)(TP_IO *); 62static void (WINAPI *pWaitForThreadpoolIoCallbacks)(TP_IO *, BOOL); 63 64#define GET_PROC(func) \ 65 do \ 66 { \ 67 p ## func = (void *)GetProcAddress(module, #func); \ 68 if (!p ## func) trace("Failed to get address for %s\n", #func); \ 69 } \ 70 while (0) 71 72static BOOL init_threadpool(void) 73{ 74 HMODULE module = GetModuleHandleA("ntdll"); 75 GET_PROC(TpAllocCleanupGroup); 76 GET_PROC(TpAllocIoCompletion); 77 GET_PROC(TpAllocPool); 78 GET_PROC(TpAllocTimer); 79 GET_PROC(TpAllocWait); 80 GET_PROC(TpAllocWork); 81 GET_PROC(TpCallbackMayRunLong); 82 GET_PROC(TpCallbackReleaseSemaphoreOnCompletion); 83 GET_PROC(TpCancelAsyncIoOperation); 84 GET_PROC(TpDisassociateCallback); 85 GET_PROC(TpIsTimerSet); 86 GET_PROC(TpPostWork); 87 GET_PROC(TpQueryPoolStackInformation); 88 GET_PROC(TpReleaseCleanupGroup); 89 GET_PROC(TpReleaseCleanupGroupMembers); 90 GET_PROC(TpReleaseIoCompletion); 91 GET_PROC(TpReleasePool); 92 GET_PROC(TpReleaseTimer); 93 GET_PROC(TpReleaseWait); 94 GET_PROC(TpReleaseWork); 95 GET_PROC(TpSetPoolMaxThreads); 96 GET_PROC(TpSetPoolStackInformation); 97 GET_PROC(TpSetTimer); 98 GET_PROC(TpSetWait); 99 GET_PROC(TpSimpleTryPost); 100 GET_PROC(TpStartAsyncIoOperation); 101 GET_PROC(TpWaitForIoCompletion); 102 GET_PROC(TpWaitForTimer); 103 GET_PROC(TpWaitForWait); 104 GET_PROC(TpWaitForWork); 105 106 module = GetModuleHandleA("kernel32"); 107 GET_PROC(CancelThreadpoolIo); 108 GET_PROC(CloseThreadpoolIo); 109 GET_PROC(CreateThreadpoolIo); 110 GET_PROC(StartThreadpoolIo); 111 GET_PROC(WaitForThreadpoolIoCallbacks); 112 113 if (!pTpAllocPool) 114 { 115 win_skip("Threadpool functions not supported, skipping tests\n"); 116 return FALSE; 117 } 118 119 return TRUE; 120} 121 122#undef NTDLL_GET_PROC 123 124 125static DWORD CALLBACK rtl_work_cb(void *userdata) 126{ 127 HANDLE semaphore = userdata; 128 ReleaseSemaphore(semaphore, 1, NULL); 129 return 0; 130} 131 132static void test_RtlQueueWorkItem(void) 133{ 134 HANDLE semaphore; 135 NTSTATUS status; 136 DWORD result; 137 138 semaphore = CreateSemaphoreA(NULL, 0, 1, NULL); 139 ok(semaphore != NULL, "CreateSemaphoreA failed %lu\n", GetLastError()); 140 141 status = RtlQueueWorkItem(rtl_work_cb, semaphore, WT_EXECUTEDEFAULT); 142 ok(!status, "RtlQueueWorkItem failed with status %lx\n", status); 143 result = WaitForSingleObject(semaphore, 1000); 144 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 145 146 status = RtlQueueWorkItem(rtl_work_cb, semaphore, WT_EXECUTEINIOTHREAD); 147 ok(!status, "RtlQueueWorkItem failed with status %lx\n", status); 148 result = WaitForSingleObject(semaphore, 1000); 149 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 150 151 status = RtlQueueWorkItem(rtl_work_cb, semaphore, WT_EXECUTEINPERSISTENTTHREAD); 152 ok(!status, "RtlQueueWorkItem failed with status %lx\n", status); 153 result = WaitForSingleObject(semaphore, 1000); 154 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 155 156 status = RtlQueueWorkItem(rtl_work_cb, semaphore, WT_EXECUTELONGFUNCTION); 157 ok(!status, "RtlQueueWorkItem failed with status %lx\n", status); 158 result = WaitForSingleObject(semaphore, 1000); 159 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 160 161 status = RtlQueueWorkItem(rtl_work_cb, semaphore, WT_TRANSFER_IMPERSONATION); 162 ok(!status, "RtlQueueWorkItem failed with status %lx\n", status); 163 result = WaitForSingleObject(semaphore, 1000); 164 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 165 166 CloseHandle(semaphore); 167} 168 169struct rtl_wait_info 170{ 171 HANDLE semaphore1; 172 HANDLE semaphore2; 173 DWORD wait_result; 174 DWORD threadid; 175 LONG userdata; 176}; 177 178static void CALLBACK rtl_wait_cb(void *userdata, BOOLEAN timeout) 179{ 180 struct rtl_wait_info *info = userdata; 181 DWORD result; 182 183 if (!timeout) 184 InterlockedIncrement(&info->userdata); 185 else 186 InterlockedExchangeAdd(&info->userdata, 0x10000); 187 info->threadid = GetCurrentThreadId(); 188 ReleaseSemaphore(info->semaphore1, 1, NULL); 189 190 if (info->semaphore2) 191 { 192 result = WaitForSingleObject(info->semaphore2, 200); 193 ok(result == info->wait_result, "expected %lu, got %lu\n", info->wait_result, result); 194 ReleaseSemaphore(info->semaphore1, 1, NULL); 195 } 196} 197 198static HANDLE rtl_wait_apc_semaphore; 199 200static void CALLBACK rtl_wait_apc_cb(ULONG_PTR userdata) 201{ 202 if (rtl_wait_apc_semaphore) 203 ReleaseSemaphore(rtl_wait_apc_semaphore, 1, NULL); 204} 205 206static void test_RtlRegisterWait(void) 207{ 208 HANDLE wait1, event, thread; 209 struct rtl_wait_info info; 210 HANDLE semaphores[2]; 211 NTSTATUS status; 212 DWORD result, threadid; 213 214 semaphores[0] = CreateSemaphoreW(NULL, 0, 2, NULL); 215 ok(semaphores[0] != NULL, "failed to create semaphore\n"); 216 semaphores[1] = CreateSemaphoreW(NULL, 0, 1, NULL); 217 ok(semaphores[1] != NULL, "failed to create semaphore\n"); 218 info.semaphore1 = semaphores[0]; 219 info.semaphore2 = NULL; 220 221 event = CreateEventW(NULL, FALSE, FALSE, NULL); 222 ok(event != NULL, "failed to create event\n"); 223 224 /* basic test for RtlRegisterWait and RtlDeregisterWait */ 225 wait1 = NULL; 226 info.userdata = 0; 227 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT); 228 ok(!status, "RtlRegisterWait failed with status %lx\n", status); 229 ok(wait1 != NULL, "expected wait1 != NULL\n"); 230 status = RtlDeregisterWait(wait1); 231 ok(!status, "RtlDeregisterWait failed with status %lx\n", status); 232 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata); 233 234 /* infinite timeout, signal the semaphore two times */ 235 info.userdata = 0; 236 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT); 237 ok(!status, "RtlRegisterWait failed with status %lx\n", status); 238 ReleaseSemaphore(semaphores[1], 1, NULL); 239 result = WaitForSingleObject(semaphores[0], 100); 240 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 241 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); 242 ReleaseSemaphore(semaphores[1], 1, NULL); 243 result = WaitForSingleObject(semaphores[0], 100); 244 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 245 ok(info.userdata == 2, "expected info.userdata = 2, got %lu\n", info.userdata); 246 result = WaitForSingleObject(semaphores[1], 0); 247 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 248 Sleep(50); 249 status = RtlDeregisterWait(wait1); 250 ok(!status, "RtlDeregisterWait failed with status %lx\n", status); 251 252 /* repeat test with WT_EXECUTEONLYONCE */ 253 info.userdata = 0; 254 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEONLYONCE); 255 ok(!status, "RtlRegisterWait failed with status %lx\n", status); 256 ReleaseSemaphore(semaphores[1], 1, NULL); 257 result = WaitForSingleObject(semaphores[0], 100); 258 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 259 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); 260 ReleaseSemaphore(semaphores[1], 1, NULL); 261 result = WaitForSingleObject(semaphores[0], 100); 262 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 263 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); 264 result = WaitForSingleObject(semaphores[1], 0); 265 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 266 Sleep(50); 267 status = RtlDeregisterWait(wait1); 268 ok(!status, "RtlDeregisterWait failed with status %lx\n", status); 269 270 /* finite timeout, no event */ 271 info.userdata = 0; 272 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 200, WT_EXECUTEDEFAULT); 273 ok(!status, "RtlRegisterWait failed with status %lx\n", status); 274 result = WaitForSingleObject(semaphores[0], 100); 275 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 276 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata); 277 result = WaitForSingleObject(semaphores[0], 200); 278 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 279 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata); 280 result = WaitForSingleObject(semaphores[1], 0); 281 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 282 Sleep(50); 283 status = RtlDeregisterWait(wait1); 284 ok(!status, "RtlDeregisterWait failed with status %lx\n", status); 285 286 /* finite timeout, with event */ 287 info.userdata = 0; 288 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 200, WT_EXECUTEDEFAULT); 289 ok(!status, "RtlRegisterWait failed with status %lx\n", status); 290 result = WaitForSingleObject(semaphores[0], 100); 291 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 292 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata); 293 ReleaseSemaphore(semaphores[1], 1, NULL); 294 result = WaitForSingleObject(semaphores[0], 100); 295 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 296 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); 297 result = WaitForSingleObject(semaphores[1], 0); 298 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 299 Sleep(50); 300 status = RtlDeregisterWait(wait1); 301 ok(!status, "RtlDeregisterWait failed with status %lx\n", status); 302 303 /* test RtlRegisterWait WT_EXECUTEINWAITTHREAD flag */ 304 info.userdata = 0; 305 info.threadid = 0; 306 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 200, WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE); 307 ok(!status, "RtlRegisterWait failed with status %lx\n", status); 308 ReleaseSemaphore(semaphores[1], 1, NULL); 309 result = WaitForSingleObject(semaphores[0], 200); 310 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 311 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); 312 ok(info.threadid && info.threadid != GetCurrentThreadId(), "unexpected wait thread id %lx\n", info.threadid); 313 threadid = info.threadid; 314 result = WaitForSingleObject(semaphores[1], 0); 315 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 316 Sleep(50); 317 status = RtlDeregisterWait(wait1); 318 ok(!status, "RtlDeregisterWait failed with status %lx\n", status); 319 320 info.userdata = 0; 321 info.threadid = 0; 322 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 200, WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE); 323 ok(!status, "RtlRegisterWait failed with status %lx\n", status); 324 ReleaseSemaphore(semaphores[1], 1, NULL); 325 result = WaitForSingleObject(semaphores[0], 200); 326 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 327 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); 328 ok(info.threadid == threadid, "unexpected different wait thread id %lx\n", info.threadid); 329 result = WaitForSingleObject(semaphores[1], 0); 330 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 331 Sleep(50); 332 status = RtlDeregisterWait(wait1); 333 ok(!status, "RtlDeregisterWait failed with status %lx\n", status); 334 335 /* test RtlRegisterWait WT_EXECUTEINWAITTHREAD flag with 0 timeout */ 336 info.userdata = 0; 337 info.threadid = 0; 338 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 0, WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE); 339 ok(!status, "RtlRegisterWait failed with status %lx\n", status); 340 result = WaitForSingleObject(semaphores[0], 100); 341 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 342 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata); 343 ok(info.threadid == threadid, "unexpected different wait thread id %lx\n", info.threadid); 344 result = WaitForSingleObject(semaphores[1], 0); 345 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 346 Sleep(50); 347 status = RtlDeregisterWait(wait1); 348 ok(!status, "RtlDeregisterWait failed with status %lx\n", status); 349 350 /* test RtlRegisterWait WT_EXECUTEINWAITTHREAD flag with already signaled event */ 351 info.userdata = 0; 352 info.threadid = 0; 353 ReleaseSemaphore(semaphores[1], 1, NULL); 354 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 200, WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE); 355 ok(!status, "RtlRegisterWait failed with status %lx\n", status); 356 result = WaitForSingleObject(semaphores[0], 200); 357 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 358 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); 359 ok(info.threadid == threadid, "unexpected different wait thread id %lx\n", info.threadid); 360 result = WaitForSingleObject(semaphores[1], 0); 361 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 362 Sleep(50); 363 status = RtlDeregisterWait(wait1); 364 ok(!status, "RtlDeregisterWait failed with status %lx\n", status); 365 366 /* test for IO threads */ 367 info.userdata = 0; 368 info.threadid = 0; 369 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEINIOTHREAD); 370 ok(!status, "RtlRegisterWait failed with status %lx\n", status); 371 ReleaseSemaphore(semaphores[1], 1, NULL); 372 result = WaitForSingleObject(semaphores[0], 100); 373 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 374 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); 375 ok(info.threadid != 0, "expected info.threadid != 0, got %lu\n", info.threadid); 376 thread = OpenThread(THREAD_SET_CONTEXT, FALSE, info.threadid); 377 ok(thread != NULL, "OpenThread failed with %lu\n", GetLastError()); 378 rtl_wait_apc_semaphore = semaphores[0]; 379 result = QueueUserAPC(rtl_wait_apc_cb, thread, 0); 380 ok(result != 0, "QueueUserAPC failed with %lu\n", GetLastError()); 381 result = WaitForSingleObject(semaphores[0], 200); 382 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 383 rtl_wait_apc_semaphore = 0; 384 CloseHandle(thread); 385 ReleaseSemaphore(semaphores[1], 1, NULL); 386 result = WaitForSingleObject(semaphores[0], 100); 387 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 388 ok(info.userdata == 2, "expected info.userdata = 2, got %lu\n", info.userdata); 389 Sleep(50); 390 status = RtlDeregisterWait(wait1); 391 ok(!status, "RtlDeregisterWait failed with status %lx\n", status); 392 393 info.userdata = 0; 394 info.threadid = 0; 395 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT); 396 ok(!status, "RtlRegisterWait failed with status %lx\n", status); 397 ReleaseSemaphore(semaphores[1], 1, NULL); 398 result = WaitForSingleObject(semaphores[0], 100); 399 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 400 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); 401 ok(info.threadid != 0, "expected info.threadid != 0, got %lu\n", info.threadid); 402 thread = OpenThread(THREAD_SET_CONTEXT, FALSE, info.threadid); 403 ok(thread != NULL, "OpenThread failed with %lu\n", GetLastError()); 404 rtl_wait_apc_semaphore = semaphores[0]; 405 result = QueueUserAPC(rtl_wait_apc_cb, thread, 0); 406 ok(result != 0, "QueueUserAPC failed with %lu\n", GetLastError()); 407 result = WaitForSingleObject(semaphores[0], 200); 408 ok(result == WAIT_TIMEOUT || broken(result == WAIT_OBJECT_0) /* >= Win Vista */, 409 "WaitForSingleObject returned %lu\n", result); 410 rtl_wait_apc_semaphore = 0; 411 CloseHandle(thread); 412 ReleaseSemaphore(semaphores[1], 1, NULL); 413 result = WaitForSingleObject(semaphores[0], 100); 414 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 415 ok(info.userdata == 2, "expected info.userdata = 2, got %lu\n", info.userdata); 416 Sleep(50); 417 status = RtlDeregisterWait(wait1); 418 ok(!status, "RtlDeregisterWait failed with status %lx\n", status); 419 420 /* test RtlDeregisterWaitEx before wait expired */ 421 info.userdata = 0; 422 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT); 423 ok(!status, "RtlRegisterWait failed with status %lx\n", status); 424 status = RtlDeregisterWaitEx(wait1, NULL); 425 ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status); 426 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata); 427 428 info.userdata = 0; 429 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT); 430 ok(!status, "RtlRegisterWait failed with status %lx\n", status); 431 status = RtlDeregisterWaitEx(wait1, INVALID_HANDLE_VALUE); 432 ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status); 433 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata); 434 435 info.userdata = 0; 436 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT); 437 ok(!status, "RtlRegisterWait failed with status %lx\n", status); 438 status = RtlDeregisterWaitEx(wait1, event); 439 ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status); 440 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata); 441 result = WaitForSingleObject(event, 200); 442 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 443 444 /* test RtlDeregisterWaitEx after wait expired */ 445 info.userdata = 0; 446 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 0, WT_EXECUTEONLYONCE); 447 ok(!status, "RtlRegisterWait failed with status %lx\n", status); 448 result = WaitForSingleObject(semaphores[0], 100); 449 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 450 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata); 451 Sleep(50); 452 status = RtlDeregisterWaitEx(wait1, NULL); 453 ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status); 454 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata); 455 456 info.userdata = 0; 457 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 0, WT_EXECUTEONLYONCE); 458 ok(!status, "RtlRegisterWait failed with status %lx\n", status); 459 result = WaitForSingleObject(semaphores[0], 100); 460 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 461 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata); 462 Sleep(50); 463 status = RtlDeregisterWaitEx(wait1, INVALID_HANDLE_VALUE); 464 ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status); 465 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata); 466 467 info.userdata = 0; 468 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 0, WT_EXECUTEONLYONCE); 469 ok(!status, "RtlRegisterWait failed with status %lx\n", status); 470 result = WaitForSingleObject(semaphores[0], 100); 471 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 472 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata); 473 Sleep(50); 474 status = RtlDeregisterWaitEx(wait1, event); 475 ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status); 476 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata); 477 result = WaitForSingleObject(event, 200); 478 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 479 480 /* test RtlDeregisterWaitEx while callback is running */ 481 info.semaphore2 = semaphores[1]; 482 info.wait_result = WAIT_OBJECT_0; 483 484 info.userdata = 0; 485 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEONLYONCE); 486 ok(!status, "RtlRegisterWait failed with status %lx\n", status); 487 ReleaseSemaphore(semaphores[1], 1, NULL); 488 result = WaitForSingleObject(semaphores[0], 1000); 489 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 490 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); 491 status = RtlDeregisterWait(wait1); 492 ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %lx\n", status); 493 ReleaseSemaphore(semaphores[1], 1, NULL); 494 result = WaitForSingleObject(semaphores[0], 1000); 495 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 496 497 info.userdata = 0; 498 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE); 499 ok(!status, "RtlRegisterWait failed with status %lx\n", status); 500 ReleaseSemaphore(semaphores[1], 1, NULL); 501 result = WaitForSingleObject(semaphores[0], 1000); 502 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 503 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); 504 status = RtlDeregisterWait(wait1); 505 ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %lx\n", status); 506 ReleaseSemaphore(semaphores[1], 1, NULL); 507 result = WaitForSingleObject(semaphores[0], 1000); 508 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 509 510 info.userdata = 0; 511 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEONLYONCE); 512 ok(!status, "RtlRegisterWait failed with status %lx\n", status); 513 ReleaseSemaphore(semaphores[1], 1, NULL); 514 result = WaitForSingleObject(semaphores[0], 1000); 515 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 516 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); 517 status = RtlDeregisterWaitEx(wait1, NULL); 518 ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %lx\n", status); 519 ReleaseSemaphore(semaphores[1], 1, NULL); 520 result = WaitForSingleObject(semaphores[0], 1000); 521 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 522 523 info.wait_result = WAIT_TIMEOUT; 524 info.userdata = 0; 525 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEONLYONCE); 526 ok(!status, "RtlRegisterWait failed with status %lx\n", status); 527 ReleaseSemaphore(semaphores[1], 1, NULL); 528 result = WaitForSingleObject(semaphores[0], 1000); 529 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 530 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); 531 status = RtlDeregisterWaitEx(wait1, INVALID_HANDLE_VALUE); 532 ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status); 533 result = WaitForSingleObject(semaphores[0], 0); 534 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 535 536 info.wait_result = WAIT_TIMEOUT; 537 info.userdata = 0; 538 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE); 539 ok(!status, "RtlRegisterWait failed with status %lx\n", status); 540 ReleaseSemaphore(semaphores[1], 1, NULL); 541 result = WaitForSingleObject(semaphores[0], 1000); 542 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 543 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); 544 status = RtlDeregisterWaitEx(wait1, INVALID_HANDLE_VALUE); 545 ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status); 546 result = WaitForSingleObject(semaphores[0], 0); 547 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 548 549 info.wait_result = WAIT_OBJECT_0; 550 info.userdata = 0; 551 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEONLYONCE); 552 ok(!status, "RtlRegisterWait failed with status %lx\n", status); 553 ReleaseSemaphore(semaphores[1], 1, NULL); 554 result = WaitForSingleObject(semaphores[0], 1000); 555 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 556 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); 557 status = RtlDeregisterWaitEx(wait1, event); 558 ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %lx\n", status); 559 ReleaseSemaphore(semaphores[1], 1, NULL); 560 result = WaitForSingleObject(event, 1000); 561 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 562 result = WaitForSingleObject(semaphores[0], 0); 563 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 564 565 CloseHandle(semaphores[0]); 566 CloseHandle(semaphores[1]); 567 CloseHandle(event); 568} 569 570static void CALLBACK simple_cb(TP_CALLBACK_INSTANCE *instance, void *userdata) 571{ 572 HANDLE semaphore = userdata; 573 ReleaseSemaphore(semaphore, 1, NULL); 574} 575 576static void CALLBACK simple2_cb(TP_CALLBACK_INSTANCE *instance, void *userdata) 577{ 578 Sleep(50); 579 InterlockedIncrement((LONG *)userdata); 580} 581 582static void test_tp_simple(void) 583{ 584 IMAGE_NT_HEADERS *nt = RtlImageNtHeader( NtCurrentTeb()->Peb->ImageBaseAddress ); 585 TP_POOL_STACK_INFORMATION stack_info; 586 TP_CALLBACK_ENVIRON environment; 587#ifndef __REACTOS__ 588 TP_CALLBACK_ENVIRON_V3 environment3; 589#endif 590 TP_CLEANUP_GROUP *group; 591 HANDLE semaphore; 592 NTSTATUS status; 593 TP_POOL *pool; 594 LONG userdata; 595 DWORD result; 596 int i; 597 598 semaphore = CreateSemaphoreA(NULL, 0, 1, NULL); 599 ok(semaphore != NULL, "CreateSemaphoreA failed %lu\n", GetLastError()); 600 601 /* post the callback using the default threadpool */ 602 memset(&environment, 0, sizeof(environment)); 603 environment.Version = 1; 604 environment.Pool = NULL; 605 status = pTpSimpleTryPost(simple_cb, semaphore, &environment); 606 ok(!status, "TpSimpleTryPost failed with status %lx\n", status); 607 result = WaitForSingleObject(semaphore, 1000); 608 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 609 610 /* allocate new threadpool */ 611 pool = NULL; 612 status = pTpAllocPool(&pool, NULL); 613 ok(!status, "TpAllocPool failed with status %lx\n", status); 614 ok(pool != NULL, "expected pool != NULL\n"); 615 616 /* post the callback using the new threadpool */ 617 memset(&environment, 0, sizeof(environment)); 618 environment.Version = 1; 619 environment.Pool = pool; 620 status = pTpSimpleTryPost(simple_cb, semaphore, &environment); 621 ok(!status, "TpSimpleTryPost failed with status %lx\n", status); 622 result = WaitForSingleObject(semaphore, 1000); 623 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 624 625#ifndef __REACTOS__ // Windows 7 626 /* test with environment version 3 */ 627 memset(&environment3, 0, sizeof(environment3)); 628 environment3.Version = 3; 629 environment3.Pool = pool; 630 environment3.Size = sizeof(environment3); 631 632 for (i = 0; i < 3; ++i) 633 { 634 environment3.CallbackPriority = TP_CALLBACK_PRIORITY_HIGH + i; 635 status = pTpSimpleTryPost(simple_cb, semaphore, (TP_CALLBACK_ENVIRON *)&environment3); 636 ok(!status, "TpSimpleTryPost failed with status %lx\n", status); 637 result = WaitForSingleObject(semaphore, 1000); 638 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 639 } 640 641 environment3.CallbackPriority = 10; 642 status = pTpSimpleTryPost(simple_cb, semaphore, (TP_CALLBACK_ENVIRON *)&environment3); 643 ok(status == STATUS_INVALID_PARAMETER || broken(!status) /* Vista does not support priorities */, 644 "TpSimpleTryPost failed with status %lx\n", status); 645#endif 646 647 /* test with invalid version number */ 648 memset(&environment, 0, sizeof(environment)); 649 environment.Version = 9999; 650 environment.Pool = pool; 651 status = pTpSimpleTryPost(simple_cb, semaphore, &environment); 652 todo_wine 653 ok(status == STATUS_INVALID_PARAMETER || broken(!status) /* Vista/2008 */, 654 "TpSimpleTryPost unexpectedly returned status %lx\n", status); 655 if (!status) 656 { 657 result = WaitForSingleObject(semaphore, 1000); 658 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 659 } 660 661 /* allocate a cleanup group for synchronization */ 662 group = NULL; 663 status = pTpAllocCleanupGroup(&group); 664 ok(!status, "TpAllocCleanupGroup failed with status %lx\n", status); 665 ok(group != NULL, "expected pool != NULL\n"); 666 667 /* use cleanup group to wait for a simple callback */ 668 userdata = 0; 669 memset(&environment, 0, sizeof(environment)); 670 environment.Version = 1; 671 environment.Pool = pool; 672 environment.CleanupGroup = group; 673 status = pTpSimpleTryPost(simple2_cb, &userdata, &environment); 674 ok(!status, "TpSimpleTryPost failed with status %lx\n", status); 675 pTpReleaseCleanupGroupMembers(group, FALSE, NULL); 676 ok(userdata == 1, "expected userdata = 1, got %lu\n", userdata); 677 678 /* test cancellation of pending simple callbacks */ 679 userdata = 0; 680 pTpSetPoolMaxThreads(pool, 10); 681 memset(&environment, 0, sizeof(environment)); 682 environment.Version = 1; 683 environment.Pool = pool; 684 environment.CleanupGroup = group; 685 for (i = 0; i < 100; i++) 686 { 687 status = pTpSimpleTryPost(simple2_cb, &userdata, &environment); 688 ok(!status, "TpSimpleTryPost failed with status %lx\n", status); 689 } 690 pTpReleaseCleanupGroupMembers(group, TRUE, NULL); 691 ok(userdata < 100, "expected userdata < 100, got %lu\n", userdata); 692 693 /* test querying and setting the stack size */ 694 status = pTpQueryPoolStackInformation(pool, &stack_info); 695 ok(!status, "TpQueryPoolStackInformation failed: %lx\n", status); 696 ok(stack_info.StackReserve == nt->OptionalHeader.SizeOfStackReserve, "expected default StackReserve, got %Ix\n", stack_info.StackReserve); 697 ok(stack_info.StackCommit == nt->OptionalHeader.SizeOfStackCommit, "expected default StackCommit, got %Ix\n", stack_info.StackCommit); 698 699 /* threadpool does not validate the stack size values */ 700 stack_info.StackReserve = stack_info.StackCommit = 1; 701 status = pTpSetPoolStackInformation(pool, &stack_info); 702 ok(!status, "TpSetPoolStackInformation failed: %lx\n", status); 703 704 status = pTpQueryPoolStackInformation(pool, &stack_info); 705 ok(!status, "TpQueryPoolStackInformation failed: %lx\n", status); 706 ok(stack_info.StackReserve == 1, "expected 1 byte StackReserve, got %ld\n", (ULONG)stack_info.StackReserve); 707 ok(stack_info.StackCommit == 1, "expected 1 byte StackCommit, got %ld\n", (ULONG)stack_info.StackCommit); 708 709 /* cleanup */ 710 pTpReleaseCleanupGroup(group); 711 pTpReleasePool(pool); 712 CloseHandle(semaphore); 713} 714 715static void CALLBACK work_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work) 716{ 717 Sleep(100); 718 InterlockedIncrement((LONG *)userdata); 719} 720 721static void CALLBACK work2_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work) 722{ 723 Sleep(100); 724 InterlockedExchangeAdd((LONG *)userdata, 0x10000); 725} 726 727static void test_tp_work(void) 728{ 729 TP_CALLBACK_ENVIRON environment; 730 TP_WORK *work; 731 TP_POOL *pool; 732 NTSTATUS status; 733 LONG userdata; 734 int i; 735 736 /* allocate new threadpool with only one thread */ 737 pool = NULL; 738 status = pTpAllocPool(&pool, NULL); 739 ok(!status, "TpAllocPool failed with status %lx\n", status); 740 ok(pool != NULL, "expected pool != NULL\n"); 741 pTpSetPoolMaxThreads(pool, 1); 742 743 /* allocate new work item */ 744 work = NULL; 745 memset(&environment, 0, sizeof(environment)); 746 environment.Version = 1; 747 environment.Pool = pool; 748 status = pTpAllocWork(&work, work_cb, &userdata, &environment); 749 ok(!status, "TpAllocWork failed with status %lx\n", status); 750 ok(work != NULL, "expected work != NULL\n"); 751 752 /* post 5 identical work items at once */ 753 userdata = 0; 754 for (i = 0; i < 5; i++) 755 pTpPostWork(work); 756 pTpWaitForWork(work, FALSE); 757 ok(userdata == 5, "expected userdata = 5, got %lu\n", userdata); 758 759 /* add more tasks and cancel them immediately */ 760 userdata = 0; 761 for (i = 0; i < 10; i++) 762 pTpPostWork(work); 763 pTpWaitForWork(work, TRUE); 764 ok(userdata < 10, "expected userdata < 10, got %lu\n", userdata); 765 766 /* cleanup */ 767 pTpReleaseWork(work); 768 pTpReleasePool(pool); 769} 770 771static void test_tp_work_scheduler(void) 772{ 773 TP_CALLBACK_ENVIRON environment; 774 TP_CLEANUP_GROUP *group; 775 TP_WORK *work, *work2; 776 TP_POOL *pool; 777 NTSTATUS status; 778 LONG userdata; 779 int i; 780 781 /* allocate new threadpool with only one thread */ 782 pool = NULL; 783 status = pTpAllocPool(&pool, NULL); 784 ok(!status, "TpAllocPool failed with status %lx\n", status); 785 ok(pool != NULL, "expected pool != NULL\n"); 786 pTpSetPoolMaxThreads(pool, 1); 787 788 /* create a cleanup group */ 789 group = NULL; 790 status = pTpAllocCleanupGroup(&group); 791 ok(!status, "TpAllocCleanupGroup failed with status %lx\n", status); 792 ok(group != NULL, "expected pool != NULL\n"); 793 794 /* the first work item has no cleanup group associated */ 795 work = NULL; 796 memset(&environment, 0, sizeof(environment)); 797 environment.Version = 1; 798 environment.Pool = pool; 799 status = pTpAllocWork(&work, work_cb, &userdata, &environment); 800 ok(!status, "TpAllocWork failed with status %lx\n", status); 801 ok(work != NULL, "expected work != NULL\n"); 802 803 /* allocate a second work item with a cleanup group */ 804 work2 = NULL; 805 memset(&environment, 0, sizeof(environment)); 806 environment.Version = 1; 807 environment.Pool = pool; 808 environment.CleanupGroup = group; 809 status = pTpAllocWork(&work2, work2_cb, &userdata, &environment); 810 ok(!status, "TpAllocWork failed with status %lx\n", status); 811 ok(work2 != NULL, "expected work2 != NULL\n"); 812 813 /* the 'work' callbacks are not blocking execution of 'work2' callbacks */ 814 userdata = 0; 815 for (i = 0; i < 10; i++) 816 pTpPostWork(work); 817 for (i = 0; i < 10; i++) 818 pTpPostWork(work2); 819 Sleep(500); 820 pTpWaitForWork(work, TRUE); 821 pTpWaitForWork(work2, TRUE); 822 ok(userdata & 0xffff, "expected userdata & 0xffff != 0, got %lu\n", userdata & 0xffff); 823 ok(userdata >> 16, "expected userdata >> 16 != 0, got %lu\n", userdata >> 16); 824 825 /* test TpReleaseCleanupGroupMembers on a work item */ 826 userdata = 0; 827 for (i = 0; i < 10; i++) 828 pTpPostWork(work); 829 for (i = 0; i < 3; i++) 830 pTpPostWork(work2); 831 pTpReleaseCleanupGroupMembers(group, FALSE, NULL); 832 pTpWaitForWork(work, TRUE); 833 ok((userdata & 0xffff) < 10, "expected userdata & 0xffff < 10, got %lu\n", userdata & 0xffff); 834 ok((userdata >> 16) == 3, "expected userdata >> 16 == 3, got %lu\n", userdata >> 16); 835 836 /* cleanup */ 837 pTpReleaseWork(work); 838 pTpReleaseCleanupGroup(group); 839 pTpReleasePool(pool); 840} 841 842static void CALLBACK simple_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata) 843{ 844 HANDLE *semaphores = userdata; 845 ReleaseSemaphore(semaphores, 1, NULL); 846 Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */ 847} 848 849static void CALLBACK work_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work) 850{ 851 HANDLE semaphore = userdata; 852 ReleaseSemaphore(semaphore, 1, NULL); 853 Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */ 854 pTpReleaseWork(work); 855} 856 857static void CALLBACK timer_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer) 858{ 859 HANDLE semaphore = userdata; 860 ReleaseSemaphore(semaphore, 1, NULL); 861 Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */ 862 pTpReleaseTimer(timer); 863} 864 865static void CALLBACK wait_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, 866 TP_WAIT *wait, TP_WAIT_RESULT result) 867{ 868 HANDLE semaphore = userdata; 869 ReleaseSemaphore(semaphore, 1, NULL); 870 Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */ 871 pTpReleaseWait(wait); 872} 873 874static void test_tp_group_wait(void) 875{ 876 TP_CALLBACK_ENVIRON environment; 877 TP_CLEANUP_GROUP *group; 878 LARGE_INTEGER when; 879 HANDLE semaphore; 880 NTSTATUS status; 881 TP_TIMER *timer; 882 TP_WAIT *wait; 883 TP_WORK *work; 884 TP_POOL *pool; 885 DWORD result; 886 887 semaphore = CreateSemaphoreA(NULL, 0, 1, NULL); 888 ok(semaphore != NULL, "CreateSemaphoreA failed %lu\n", GetLastError()); 889 890 /* allocate new threadpool */ 891 pool = NULL; 892 status = pTpAllocPool(&pool, NULL); 893 ok(!status, "TpAllocPool failed with status %lx\n", status); 894 ok(pool != NULL, "expected pool != NULL\n"); 895 896 /* allocate a cleanup group */ 897 group = NULL; 898 status = pTpAllocCleanupGroup(&group); 899 ok(!status, "TpAllocCleanupGroup failed with status %lx\n", status); 900 ok(group != NULL, "expected pool != NULL\n"); 901 902 /* release work object during TpReleaseCleanupGroupMembers */ 903 work = NULL; 904 memset(&environment, 0, sizeof(environment)); 905 environment.Version = 1; 906 environment.Pool = pool; 907 environment.CleanupGroup = group; 908 status = pTpAllocWork(&work, work_release_cb, semaphore, &environment); 909 ok(!status, "TpAllocWork failed with status %lx\n", status); 910 ok(work != NULL, "expected work != NULL\n"); 911 pTpPostWork(work); 912 result = WaitForSingleObject(semaphore, 1000); 913 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 914 pTpReleaseCleanupGroupMembers(group, FALSE, NULL); 915 916 /* release timer object during TpReleaseCleanupGroupMembers */ 917 timer = NULL; 918 memset(&environment, 0, sizeof(environment)); 919 environment.Version = 1; 920 environment.Pool = pool; 921 environment.CleanupGroup = group; 922 status = pTpAllocTimer(&timer, timer_release_cb, semaphore, &environment); 923 ok(!status, "TpAllocTimer failed with status %lx\n", status); 924 ok(timer != NULL, "expected timer != NULL\n"); 925 when.QuadPart = 0; 926 pTpSetTimer(timer, &when, 0, 0); 927 result = WaitForSingleObject(semaphore, 1000); 928 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 929 pTpReleaseCleanupGroupMembers(group, FALSE, NULL); 930 931 /* release wait object during TpReleaseCleanupGroupMembers */ 932 wait = NULL; 933 memset(&environment, 0, sizeof(environment)); 934 environment.Version = 1; 935 environment.Pool = pool; 936 environment.CleanupGroup = group; 937 status = pTpAllocWait(&wait, wait_release_cb, semaphore, &environment); 938 ok(!status, "TpAllocWait failed with status %lx\n", status); 939 ok(wait != NULL, "expected wait != NULL\n"); 940 when.QuadPart = 0; 941 pTpSetWait(wait, INVALID_HANDLE_VALUE, &when); 942 result = WaitForSingleObject(semaphore, 1000); 943 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 944 pTpReleaseCleanupGroupMembers(group, FALSE, NULL); 945 946 /* cleanup */ 947 pTpReleaseCleanupGroup(group); 948 pTpReleasePool(pool); 949 CloseHandle(semaphore); 950} 951 952static DWORD group_cancel_tid; 953 954static void CALLBACK simple_group_cancel_cb(TP_CALLBACK_INSTANCE *instance, void *userdata) 955{ 956 HANDLE *semaphores = userdata; 957 NTSTATUS status; 958 DWORD result; 959 int i; 960 961 status = pTpCallbackMayRunLong(instance); 962 ok(status == STATUS_TOO_MANY_THREADS || broken(status == 1) /* Win Vista / 2008 */, 963 "expected STATUS_TOO_MANY_THREADS, got %08lx\n", status); 964 965 ReleaseSemaphore(semaphores[1], 1, NULL); 966 for (i = 0; i < 4; i++) 967 { 968 result = WaitForSingleObject(semaphores[0], 1000); 969 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 970 } 971 ReleaseSemaphore(semaphores[1], 1, NULL); 972} 973 974static void CALLBACK work_group_cancel_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work) 975{ 976 HANDLE *semaphores = userdata; 977 DWORD result; 978 979 ReleaseSemaphore(semaphores[1], 1, NULL); 980 result = WaitForSingleObject(semaphores[0], 200); 981 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 982} 983 984static void CALLBACK group_cancel_cleanup_release_cb(void *object, void *userdata) 985{ 986 HANDLE *semaphores = userdata; 987 group_cancel_tid = GetCurrentThreadId(); 988 ok(object == (void *)0xdeadbeef, "expected 0xdeadbeef, got %p\n", object); 989 ReleaseSemaphore(semaphores[0], 1, NULL); 990} 991 992static void CALLBACK group_cancel_cleanup_release2_cb(void *object, void *userdata) 993{ 994 HANDLE *semaphores = userdata; 995 group_cancel_tid = GetCurrentThreadId(); 996 ok(object == userdata, "expected %p, got %p\n", userdata, object); 997 ReleaseSemaphore(semaphores[0], 1, NULL); 998} 999 1000static void CALLBACK group_cancel_cleanup_increment_cb(void *object, void *userdata) 1001{ 1002 group_cancel_tid = GetCurrentThreadId(); 1003 InterlockedIncrement((LONG *)userdata); 1004} 1005 1006static void CALLBACK unexpected_simple_cb(TP_CALLBACK_INSTANCE *instance, void *userdata) 1007{ 1008 ok(0, "Unexpected callback\n"); 1009} 1010 1011static void CALLBACK unexpected_work_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work) 1012{ 1013 ok(0, "Unexpected callback\n"); 1014} 1015 1016static void CALLBACK unexpected_timer_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer) 1017{ 1018 ok(0, "Unexpected callback\n"); 1019} 1020 1021static void CALLBACK unexpected_wait_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, 1022 TP_WAIT *wait, TP_WAIT_RESULT result) 1023{ 1024 ok(0, "Unexpected callback\n"); 1025} 1026 1027static void CALLBACK unexpected_group_cancel_cleanup_cb(void *object, void *userdata) 1028{ 1029 ok(0, "Unexpected callback\n"); 1030} 1031 1032static void test_tp_group_cancel(void) 1033{ 1034 TP_CALLBACK_ENVIRON environment; 1035 TP_CLEANUP_GROUP *group; 1036 LONG userdata, userdata2; 1037 HANDLE semaphores[2]; 1038 NTSTATUS status; 1039 TP_TIMER *timer; 1040 TP_WAIT *wait; 1041 TP_WORK *work; 1042 TP_POOL *pool; 1043 DWORD result; 1044 int i; 1045 1046 semaphores[0] = CreateSemaphoreA(NULL, 0, 4, NULL); 1047 ok(semaphores[0] != NULL, "CreateSemaphoreA failed %lu\n", GetLastError()); 1048 semaphores[1] = CreateSemaphoreA(NULL, 0, 1, NULL); 1049 ok(semaphores[1] != NULL, "CreateSemaphoreA failed %lu\n", GetLastError()); 1050 1051 /* allocate new threadpool with only one thread */ 1052 pool = NULL; 1053 status = pTpAllocPool(&pool, NULL); 1054 ok(!status, "TpAllocPool failed with status %lx\n", status); 1055 ok(pool != NULL, "expected pool != NULL\n"); 1056 pTpSetPoolMaxThreads(pool, 1); 1057 1058 /* allocate a cleanup group */ 1059 group = NULL; 1060 status = pTpAllocCleanupGroup(&group); 1061 ok(!status, "TpAllocCleanupGroup failed with status %lx\n", status); 1062 ok(group != NULL, "expected pool != NULL\n"); 1063 1064 /* test execution of cancellation callback */ 1065 memset(&environment, 0, sizeof(environment)); 1066 environment.Version = 1; 1067 environment.Pool = pool; 1068 status = pTpSimpleTryPost(simple_group_cancel_cb, semaphores, &environment); 1069 ok(!status, "TpSimpleTryPost failed with status %lx\n", status); 1070 result = WaitForSingleObject(semaphores[1], 1000); 1071 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1072 1073 memset(&environment, 0, sizeof(environment)); 1074 environment.Version = 1; 1075 environment.Pool = pool; 1076 environment.CleanupGroup = group; 1077 environment.CleanupGroupCancelCallback = group_cancel_cleanup_release_cb; 1078 status = pTpSimpleTryPost(unexpected_simple_cb, (void *)0xdeadbeef, &environment); 1079 ok(!status, "TpSimpleTryPost failed with status %lx\n", status); 1080 1081 work = NULL; 1082 status = pTpAllocWork(&work, unexpected_work_cb, (void *)0xdeadbeef, &environment); 1083 ok(!status, "TpAllocWork failed with status %lx\n", status); 1084 ok(work != NULL, "expected work != NULL\n"); 1085 1086 timer = NULL; 1087 status = pTpAllocTimer(&timer, unexpected_timer_cb, (void *)0xdeadbeef, &environment); 1088 ok(!status, "TpAllocTimer failed with status %lx\n", status); 1089 ok(timer != NULL, "expected timer != NULL\n"); 1090 1091 wait = NULL; 1092 status = pTpAllocWait(&wait, unexpected_wait_cb, (void *)0xdeadbeef, &environment); 1093 ok(!status, "TpAllocWait failed with status %lx\n", status); 1094 ok(wait != NULL, "expected wait != NULL\n"); 1095 1096 group_cancel_tid = 0xdeadbeef; 1097 pTpReleaseCleanupGroupMembers(group, TRUE, semaphores); 1098 result = WaitForSingleObject(semaphores[1], 1000); 1099 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1100 ok(group_cancel_tid == GetCurrentThreadId(), "expected tid %lx, got %lx\n", 1101 GetCurrentThreadId(), group_cancel_tid); 1102 1103 /* test if cancellation callbacks are executed before or after wait */ 1104 work = NULL; 1105 memset(&environment, 0, sizeof(environment)); 1106 environment.Version = 1; 1107 environment.Pool = pool; 1108 environment.CleanupGroup = group; 1109 environment.CleanupGroupCancelCallback = group_cancel_cleanup_release2_cb; 1110 status = pTpAllocWork(&work, work_group_cancel_cb, semaphores, &environment); 1111 ok(!status, "TpAllocWork failed with status %lx\n", status); 1112 ok(work != NULL, "expected work != NULL\n"); 1113 pTpPostWork(work); 1114 pTpPostWork(work); 1115 1116 result = WaitForSingleObject(semaphores[1], 1000); 1117 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1118 1119 group_cancel_tid = 0xdeadbeef; 1120 pTpReleaseCleanupGroupMembers(group, TRUE, semaphores); 1121 result = WaitForSingleObject(semaphores[0], 1000); 1122 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1123 ok(group_cancel_tid == GetCurrentThreadId(), "expected tid %lx, got %lx\n", 1124 GetCurrentThreadId(), group_cancel_tid); 1125 1126 /* group cancel callback is not executed if object is destroyed while waiting */ 1127 work = NULL; 1128 memset(&environment, 0, sizeof(environment)); 1129 environment.Version = 1; 1130 environment.Pool = pool; 1131 environment.CleanupGroup = group; 1132 environment.CleanupGroupCancelCallback = unexpected_group_cancel_cleanup_cb; 1133 status = pTpAllocWork(&work, work_release_cb, semaphores[1], &environment); 1134 ok(!status, "TpAllocWork failed with status %lx\n", status); 1135 ok(work != NULL, "expected work != NULL\n"); 1136 pTpPostWork(work); 1137 1138 result = WaitForSingleObject(semaphores[1], 1000); 1139 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1140 pTpReleaseCleanupGroupMembers(group, TRUE, NULL); 1141 1142 /* terminated simple callbacks should not trigger the group cancel callback */ 1143 memset(&environment, 0, sizeof(environment)); 1144 environment.Version = 1; 1145 environment.Pool = pool; 1146 environment.CleanupGroup = group; 1147 environment.CleanupGroupCancelCallback = unexpected_group_cancel_cleanup_cb; 1148 status = pTpSimpleTryPost(simple_release_cb, semaphores[1], &environment); 1149 ok(!status, "TpSimpleTryPost failed with status %lx\n", status); 1150 result = WaitForSingleObject(semaphores[1], 1000); 1151 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1152 pTpReleaseCleanupGroupMembers(group, TRUE, semaphores); 1153 1154 /* test cancellation callback for objects with multiple instances */ 1155 work = NULL; 1156 memset(&environment, 0, sizeof(environment)); 1157 environment.Version = 1; 1158 environment.Pool = pool; 1159 environment.CleanupGroup = group; 1160 environment.CleanupGroupCancelCallback = group_cancel_cleanup_increment_cb; 1161 status = pTpAllocWork(&work, work_cb, &userdata, &environment); 1162 ok(!status, "TpAllocWork failed with status %lx\n", status); 1163 ok(work != NULL, "expected work != NULL\n"); 1164 1165 /* post 10 identical work items at once */ 1166 userdata = userdata2 = 0; 1167 for (i = 0; i < 10; i++) 1168 pTpPostWork(work); 1169 1170 /* check if we get multiple cancellation callbacks */ 1171 group_cancel_tid = 0xdeadbeef; 1172 pTpReleaseCleanupGroupMembers(group, TRUE, &userdata2); 1173 ok(userdata <= 5, "expected userdata <= 5, got %lu\n", userdata); 1174 ok(userdata2 == 1, "expected only one cancellation callback, got %lu\n", userdata2); 1175 ok(group_cancel_tid == GetCurrentThreadId(), "expected tid %lx, got %lx\n", 1176 GetCurrentThreadId(), group_cancel_tid); 1177 1178 /* cleanup */ 1179 pTpReleaseCleanupGroup(group); 1180 pTpReleasePool(pool); 1181 CloseHandle(semaphores[0]); 1182 CloseHandle(semaphores[1]); 1183} 1184 1185static void CALLBACK instance_semaphore_completion_cb(TP_CALLBACK_INSTANCE *instance, void *userdata) 1186{ 1187 HANDLE *semaphores = userdata; 1188 pTpCallbackReleaseSemaphoreOnCompletion(instance, semaphores[0], 1); 1189} 1190 1191static void CALLBACK instance_finalization_cb(TP_CALLBACK_INSTANCE *instance, void *userdata) 1192{ 1193 HANDLE *semaphores = userdata; 1194 ReleaseSemaphore(semaphores[1], 1, NULL); 1195} 1196 1197static void test_tp_instance(void) 1198{ 1199 TP_CALLBACK_ENVIRON environment; 1200 HANDLE semaphores[2]; 1201 NTSTATUS status; 1202 TP_POOL *pool; 1203 DWORD result; 1204 1205 semaphores[0] = CreateSemaphoreW(NULL, 0, 1, NULL); 1206 ok(semaphores[0] != NULL, "failed to create semaphore\n"); 1207 semaphores[1] = CreateSemaphoreW(NULL, 0, 1, NULL); 1208 ok(semaphores[1] != NULL, "failed to create semaphore\n"); 1209 1210 /* allocate new threadpool */ 1211 pool = NULL; 1212 status = pTpAllocPool(&pool, NULL); 1213 ok(!status, "TpAllocPool failed with status %lx\n", status); 1214 ok(pool != NULL, "expected pool != NULL\n"); 1215 1216 /* test for TpCallbackReleaseSemaphoreOnCompletion */ 1217 memset(&environment, 0, sizeof(environment)); 1218 environment.Version = 1; 1219 environment.Pool = pool; 1220 status = pTpSimpleTryPost(instance_semaphore_completion_cb, semaphores, &environment); 1221 ok(!status, "TpSimpleTryPost failed with status %lx\n", status); 1222 result = WaitForSingleObject(semaphores[0], 1000); 1223 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1224 1225 /* test for finalization callback */ 1226 memset(&environment, 0, sizeof(environment)); 1227 environment.Version = 1; 1228 environment.Pool = pool; 1229 environment.FinalizationCallback = instance_finalization_cb; 1230 status = pTpSimpleTryPost(instance_semaphore_completion_cb, semaphores, &environment); 1231 ok(!status, "TpSimpleTryPost failed with status %lx\n", status); 1232 result = WaitForSingleObject(semaphores[0], 1000); 1233 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1234 result = WaitForSingleObject(semaphores[1], 1000); 1235 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1236 1237 /* cleanup */ 1238 pTpReleasePool(pool); 1239 CloseHandle(semaphores[0]); 1240 CloseHandle(semaphores[1]); 1241} 1242 1243static void CALLBACK disassociate_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work) 1244{ 1245 HANDLE *semaphores = userdata; 1246 DWORD result; 1247 1248 pTpDisassociateCallback(instance); 1249 result = WaitForSingleObject(semaphores[0], 1000); 1250 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1251 ReleaseSemaphore(semaphores[1], 1, NULL); 1252} 1253 1254static void CALLBACK disassociate2_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work) 1255{ 1256 HANDLE *semaphores = userdata; 1257 DWORD result; 1258 1259 pTpDisassociateCallback(instance); 1260 result = WaitForSingleObject(semaphores[0], 100); 1261 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 1262 ReleaseSemaphore(semaphores[1], 1, NULL); 1263} 1264 1265static void CALLBACK disassociate3_cb(TP_CALLBACK_INSTANCE *instance, void *userdata) 1266{ 1267 HANDLE *semaphores = userdata; 1268 DWORD result; 1269 1270 pTpDisassociateCallback(instance); 1271 result = WaitForSingleObject(semaphores[0], 100); 1272 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 1273 ReleaseSemaphore(semaphores[1], 1, NULL); 1274} 1275 1276static void test_tp_disassociate(void) 1277{ 1278 TP_CALLBACK_ENVIRON environment; 1279 TP_CLEANUP_GROUP *group; 1280 HANDLE semaphores[2]; 1281 NTSTATUS status; 1282 TP_POOL *pool; 1283 TP_WORK *work; 1284 DWORD result; 1285 1286 semaphores[0] = CreateSemaphoreW(NULL, 0, 1, NULL); 1287 ok(semaphores[0] != NULL, "failed to create semaphore\n"); 1288 semaphores[1] = CreateSemaphoreW(NULL, 0, 1, NULL); 1289 ok(semaphores[1] != NULL, "failed to create semaphore\n"); 1290 1291 /* allocate new threadpool and cleanup group */ 1292 pool = NULL; 1293 status = pTpAllocPool(&pool, NULL); 1294 ok(!status, "TpAllocPool failed with status %lx\n", status); 1295 ok(pool != NULL, "expected pool != NULL\n"); 1296 1297 group = NULL; 1298 status = pTpAllocCleanupGroup(&group); 1299 ok(!status, "TpAllocCleanupGroup failed with status %lx\n", status); 1300 ok(group != NULL, "expected pool != NULL\n"); 1301 1302 /* test TpDisassociateCallback on work objects without group */ 1303 work = NULL; 1304 memset(&environment, 0, sizeof(environment)); 1305 environment.Version = 1; 1306 environment.Pool = pool; 1307 status = pTpAllocWork(&work, disassociate_cb, semaphores, &environment); 1308 ok(!status, "TpAllocWork failed with status %lx\n", status); 1309 ok(work != NULL, "expected work != NULL\n"); 1310 1311 pTpPostWork(work); 1312 pTpWaitForWork(work, FALSE); 1313 1314 result = WaitForSingleObject(semaphores[1], 100); 1315 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 1316 ReleaseSemaphore(semaphores[0], 1, NULL); 1317 result = WaitForSingleObject(semaphores[1], 1000); 1318 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1319 pTpReleaseWork(work); 1320 1321 /* test TpDisassociateCallback on work objects with group (1) */ 1322 work = NULL; 1323 memset(&environment, 0, sizeof(environment)); 1324 environment.Version = 1; 1325 environment.Pool = pool; 1326 environment.CleanupGroup = group; 1327 status = pTpAllocWork(&work, disassociate_cb, semaphores, &environment); 1328 ok(!status, "TpAllocWork failed with status %lx\n", status); 1329 ok(work != NULL, "expected work != NULL\n"); 1330 1331 pTpPostWork(work); 1332 pTpWaitForWork(work, FALSE); 1333 1334 result = WaitForSingleObject(semaphores[1], 100); 1335 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 1336 ReleaseSemaphore(semaphores[0], 1, NULL); 1337 result = WaitForSingleObject(semaphores[1], 1000); 1338 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1339 pTpReleaseCleanupGroupMembers(group, FALSE, NULL); 1340 1341 /* test TpDisassociateCallback on work objects with group (2) */ 1342 work = NULL; 1343 memset(&environment, 0, sizeof(environment)); 1344 environment.Version = 1; 1345 environment.Pool = pool; 1346 environment.CleanupGroup = group; 1347 status = pTpAllocWork(&work, disassociate2_cb, semaphores, &environment); 1348 ok(!status, "TpAllocWork failed with status %lx\n", status); 1349 ok(work != NULL, "expected work != NULL\n"); 1350 1351 pTpPostWork(work); 1352 pTpReleaseCleanupGroupMembers(group, FALSE, NULL); 1353 1354 ReleaseSemaphore(semaphores[0], 1, NULL); 1355 result = WaitForSingleObject(semaphores[1], 1000); 1356 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1357 result = WaitForSingleObject(semaphores[0], 1000); 1358 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1359 1360 /* test TpDisassociateCallback on simple callbacks */ 1361 memset(&environment, 0, sizeof(environment)); 1362 environment.Version = 1; 1363 environment.Pool = pool; 1364 environment.CleanupGroup = group; 1365 status = pTpSimpleTryPost(disassociate3_cb, semaphores, &environment); 1366 ok(!status, "TpSimpleTryPost failed with status %lx\n", status); 1367 1368 pTpReleaseCleanupGroupMembers(group, FALSE, NULL); 1369 1370 ReleaseSemaphore(semaphores[0], 1, NULL); 1371 result = WaitForSingleObject(semaphores[1], 1000); 1372 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1373 result = WaitForSingleObject(semaphores[0], 1000); 1374 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1375 1376 /* cleanup */ 1377 pTpReleaseCleanupGroup(group); 1378 pTpReleasePool(pool); 1379 CloseHandle(semaphores[0]); 1380 CloseHandle(semaphores[1]); 1381} 1382 1383static void CALLBACK timer_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer) 1384{ 1385 HANDLE semaphore = userdata; 1386 ReleaseSemaphore(semaphore, 1, NULL); 1387} 1388 1389static void test_tp_timer(void) 1390{ 1391 TP_CALLBACK_ENVIRON environment; 1392 DWORD result, ticks; 1393 LARGE_INTEGER when; 1394 HANDLE semaphore; 1395 NTSTATUS status; 1396 TP_TIMER *timer; 1397 TP_POOL *pool; 1398 BOOL success; 1399 int i; 1400 1401 semaphore = CreateSemaphoreA(NULL, 0, 1, NULL); 1402 ok(semaphore != NULL, "CreateSemaphoreA failed %lu\n", GetLastError()); 1403 1404 /* allocate new threadpool */ 1405 pool = NULL; 1406 status = pTpAllocPool(&pool, NULL); 1407 ok(!status, "TpAllocPool failed with status %lx\n", status); 1408 ok(pool != NULL, "expected pool != NULL\n"); 1409 1410 /* allocate new timer */ 1411 timer = NULL; 1412 memset(&environment, 0, sizeof(environment)); 1413 environment.Version = 1; 1414 environment.Pool = pool; 1415 status = pTpAllocTimer(&timer, timer_cb, semaphore, &environment); 1416 ok(!status, "TpAllocTimer failed with status %lx\n", status); 1417 ok(timer != NULL, "expected timer != NULL\n"); 1418 1419 success = pTpIsTimerSet(timer); 1420 ok(!success, "TpIsTimerSet returned TRUE\n"); 1421 1422 /* test timer with a relative timeout */ 1423 when.QuadPart = (ULONGLONG)200 * -10000; 1424 pTpSetTimer(timer, &when, 0, 0); 1425 success = pTpIsTimerSet(timer); 1426 ok(success, "TpIsTimerSet returned FALSE\n"); 1427 1428 pTpWaitForTimer(timer, FALSE); 1429 1430 result = WaitForSingleObject(semaphore, 100); 1431 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 1432 result = WaitForSingleObject(semaphore, 200); 1433 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1434 success = pTpIsTimerSet(timer); 1435 ok(success, "TpIsTimerSet returned FALSE\n"); 1436 1437 /* test timer with an absolute timeout */ 1438 NtQuerySystemTime( &when ); 1439 when.QuadPart += (ULONGLONG)200 * 10000; 1440 pTpSetTimer(timer, &when, 0, 0); 1441 success = pTpIsTimerSet(timer); 1442 ok(success, "TpIsTimerSet returned FALSE\n"); 1443 1444 pTpWaitForTimer(timer, FALSE); 1445 1446 result = WaitForSingleObject(semaphore, 100); 1447 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 1448 result = WaitForSingleObject(semaphore, 200); 1449 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1450 success = pTpIsTimerSet(timer); 1451 ok(success, "TpIsTimerSet returned FALSE\n"); 1452 1453 /* test timer with zero timeout */ 1454 when.QuadPart = 0; 1455 pTpSetTimer(timer, &when, 0, 0); 1456 success = pTpIsTimerSet(timer); 1457 ok(success, "TpIsTimerSet returned FALSE\n"); 1458 1459 pTpWaitForTimer(timer, FALSE); 1460 1461 result = WaitForSingleObject(semaphore, 50); 1462 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1463 success = pTpIsTimerSet(timer); 1464 ok(success, "TpIsTimerSet returned FALSE\n"); 1465 1466 /* unset the timer */ 1467 pTpSetTimer(timer, NULL, 0, 0); 1468 success = pTpIsTimerSet(timer); 1469 ok(!success, "TpIsTimerSet returned TRUE\n"); 1470 pTpWaitForTimer(timer, TRUE); 1471 1472 pTpReleaseTimer(timer); 1473 CloseHandle(semaphore); 1474 1475 semaphore = CreateSemaphoreA(NULL, 0, 3, NULL); 1476 ok(semaphore != NULL, "CreateSemaphoreA failed %lu\n", GetLastError()); 1477 1478 /* allocate a new timer */ 1479 timer = NULL; 1480 memset(&environment, 0, sizeof(environment)); 1481 environment.Version = 1; 1482 environment.Pool = pool; 1483 status = pTpAllocTimer(&timer, timer_cb, semaphore, &environment); 1484 ok(!status, "TpAllocTimer failed with status %lx\n", status); 1485 ok(timer != NULL, "expected timer != NULL\n"); 1486 1487 /* test a relative timeout repeated periodically */ 1488 when.QuadPart = (ULONGLONG)200 * -10000; 1489 pTpSetTimer(timer, &when, 200, 0); 1490 success = pTpIsTimerSet(timer); 1491 ok(success, "TpIsTimerSet returned FALSE\n"); 1492 1493 /* wait until the timer was triggered three times */ 1494 ticks = GetTickCount(); 1495 for (i = 0; i < 3; i++) 1496 { 1497 result = WaitForSingleObject(semaphore, 1000); 1498 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1499 } 1500 ticks = GetTickCount() - ticks; 1501 ok(ticks >= 500 && (ticks <= 700 || broken(ticks <= 750)) /* Win 7 */, 1502 "expected approximately 600 ticks, got %lu\n", ticks); 1503 1504 /* unset the timer */ 1505 pTpSetTimer(timer, NULL, 0, 0); 1506 success = pTpIsTimerSet(timer); 1507 ok(!success, "TpIsTimerSet returned TRUE\n"); 1508 pTpWaitForTimer(timer, TRUE); 1509 1510 /* cleanup */ 1511 pTpReleaseTimer(timer); 1512 pTpReleasePool(pool); 1513 CloseHandle(semaphore); 1514} 1515 1516struct window_length_info 1517{ 1518 HANDLE semaphore; 1519 DWORD ticks; 1520}; 1521 1522static void CALLBACK window_length_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer) 1523{ 1524 struct window_length_info *info = userdata; 1525 info->ticks = GetTickCount(); 1526 ReleaseSemaphore(info->semaphore, 1, NULL); 1527} 1528 1529static void test_tp_window_length(void) 1530{ 1531 struct window_length_info info1, info2; 1532 TP_CALLBACK_ENVIRON environment; 1533 TP_TIMER *timer1, *timer2; 1534 LARGE_INTEGER when; 1535 HANDLE semaphore; 1536 NTSTATUS status; 1537 TP_POOL *pool; 1538 DWORD result; 1539 BOOL merged; 1540 1541 semaphore = CreateSemaphoreA(NULL, 0, 2, NULL); 1542 ok(semaphore != NULL, "CreateSemaphoreA failed %lu\n", GetLastError()); 1543 1544 /* allocate new threadpool */ 1545 pool = NULL; 1546 status = pTpAllocPool(&pool, NULL); 1547 ok(!status, "TpAllocPool failed with status %lx\n", status); 1548 ok(pool != NULL, "expected pool != NULL\n"); 1549 1550 /* allocate two identical timers */ 1551 memset(&environment, 0, sizeof(environment)); 1552 environment.Version = 1; 1553 environment.Pool = pool; 1554 1555 timer1 = NULL; 1556 info1.semaphore = semaphore; 1557 status = pTpAllocTimer(&timer1, window_length_cb, &info1, &environment); 1558 ok(!status, "TpAllocTimer failed with status %lx\n", status); 1559 ok(timer1 != NULL, "expected timer1 != NULL\n"); 1560 1561 timer2 = NULL; 1562 info2.semaphore = semaphore; 1563 status = pTpAllocTimer(&timer2, window_length_cb, &info2, &environment); 1564 ok(!status, "TpAllocTimer failed with status %lx\n", status); 1565 ok(timer2 != NULL, "expected timer2 != NULL\n"); 1566 1567 /* choose parameters so that timers are not merged */ 1568 info1.ticks = 0; 1569 info2.ticks = 0; 1570 1571 NtQuerySystemTime( &when ); 1572 when.QuadPart += (ULONGLONG)250 * 10000; 1573 pTpSetTimer(timer2, &when, 0, 0); 1574 Sleep(50); 1575 when.QuadPart -= (ULONGLONG)150 * 10000; 1576 pTpSetTimer(timer1, &when, 0, 75); 1577 1578 result = WaitForSingleObject(semaphore, 1000); 1579 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1580 result = WaitForSingleObject(semaphore, 1000); 1581 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1582 ok(info1.ticks != 0 && info2.ticks != 0, "expected that ticks are nonzero\n"); 1583 ok(info2.ticks >= info1.ticks + 75 || broken(info2.ticks < info1.ticks + 75) /* Win 2008 */, 1584 "expected that timers are not merged\n"); 1585 1586 /* timers will be merged */ 1587 info1.ticks = 0; 1588 info2.ticks = 0; 1589 1590 NtQuerySystemTime( &when ); 1591 when.QuadPart += (ULONGLONG)250 * 10000; 1592 pTpSetTimer(timer2, &when, 0, 0); 1593 Sleep(50); 1594 when.QuadPart -= (ULONGLONG)150 * 10000; 1595 pTpSetTimer(timer1, &when, 0, 200); 1596 1597 result = WaitForSingleObject(semaphore, 1000); 1598 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1599 result = WaitForSingleObject(semaphore, 1000); 1600 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1601 ok(info1.ticks != 0 && info2.ticks != 0, "expected that ticks are nonzero\n"); 1602 merged = info2.ticks >= info1.ticks - 50 && info2.ticks <= info1.ticks + 50; 1603 ok(merged || broken(!merged) /* Win 10 */, "expected that timers are merged\n"); 1604 1605 /* on Windows the timers also get merged in this case */ 1606 info1.ticks = 0; 1607 info2.ticks = 0; 1608 1609 NtQuerySystemTime( &when ); 1610 when.QuadPart += (ULONGLONG)100 * 10000; 1611 pTpSetTimer(timer1, &when, 0, 200); 1612 Sleep(50); 1613 when.QuadPart += (ULONGLONG)150 * 10000; 1614 pTpSetTimer(timer2, &when, 0, 0); 1615 1616 result = WaitForSingleObject(semaphore, 1000); 1617 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1618 result = WaitForSingleObject(semaphore, 1000); 1619 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1620 ok(info1.ticks != 0 && info2.ticks != 0, "expected that ticks are nonzero\n"); 1621 merged = info2.ticks >= info1.ticks - 50 && info2.ticks <= info1.ticks + 50; 1622 todo_wine 1623 ok(merged || broken(!merged) /* Win 10 */, "expected that timers are merged\n"); 1624 1625 /* cleanup */ 1626 pTpReleaseTimer(timer1); 1627 pTpReleaseTimer(timer2); 1628 pTpReleasePool(pool); 1629 CloseHandle(semaphore); 1630} 1631 1632struct wait_info 1633{ 1634 HANDLE semaphore; 1635 LONG userdata; 1636}; 1637 1638static void CALLBACK wait_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, 1639 TP_WAIT *wait, TP_WAIT_RESULT result) 1640{ 1641 struct wait_info *info = userdata; 1642 if (result == WAIT_OBJECT_0) 1643 InterlockedIncrement(&info->userdata); 1644 else if (result == WAIT_TIMEOUT) 1645 InterlockedExchangeAdd(&info->userdata, 0x10000); 1646 else 1647 ok(0, "unexpected result %lu\n", result); 1648 ReleaseSemaphore(info->semaphore, 1, NULL); 1649} 1650 1651static void test_tp_wait(void) 1652{ 1653 TP_CALLBACK_ENVIRON environment; 1654 TP_WAIT *wait1, *wait2; 1655 struct wait_info info; 1656 HANDLE semaphores[2]; 1657 LARGE_INTEGER when; 1658 NTSTATUS status; 1659 TP_POOL *pool; 1660 DWORD result; 1661 1662 semaphores[0] = CreateSemaphoreW(NULL, 0, 2, NULL); 1663 ok(semaphores[0] != NULL, "failed to create semaphore\n"); 1664 semaphores[1] = CreateSemaphoreW(NULL, 0, 1, NULL); 1665 ok(semaphores[1] != NULL, "failed to create semaphore\n"); 1666 info.semaphore = semaphores[0]; 1667 1668 /* allocate new threadpool */ 1669 pool = NULL; 1670 status = pTpAllocPool(&pool, NULL); 1671 ok(!status, "TpAllocPool failed with status %lx\n", status); 1672 ok(pool != NULL, "expected pool != NULL\n"); 1673 1674 /* allocate new wait items */ 1675 memset(&environment, 0, sizeof(environment)); 1676 environment.Version = 1; 1677 environment.Pool = pool; 1678 1679 wait1 = NULL; 1680 status = pTpAllocWait(&wait1, wait_cb, &info, &environment); 1681 ok(!status, "TpAllocWait failed with status %lx\n", status); 1682 ok(wait1 != NULL, "expected wait1 != NULL\n"); 1683 1684 wait2 = NULL; 1685 status = pTpAllocWait(&wait2, wait_cb, &info, &environment); 1686 ok(!status, "TpAllocWait failed with status %lx\n", status); 1687 ok(wait2 != NULL, "expected wait2 != NULL\n"); 1688 1689 /* infinite timeout, signal the semaphore immediately */ 1690 info.userdata = 0; 1691 pTpSetWait(wait1, semaphores[1], NULL); 1692 ReleaseSemaphore(semaphores[1], 1, NULL); 1693 result = WaitForSingleObject(semaphores[0], 100); 1694 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1695 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); 1696 result = WaitForSingleObject(semaphores[1], 0); 1697 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 1698 1699 /* relative timeout, no event */ 1700 info.userdata = 0; 1701 when.QuadPart = (ULONGLONG)200 * -10000; 1702 pTpSetWait(wait1, semaphores[1], &when); 1703 result = WaitForSingleObject(semaphores[0], 100); 1704 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 1705 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata); 1706 result = WaitForSingleObject(semaphores[0], 200); 1707 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1708 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata); 1709 result = WaitForSingleObject(semaphores[1], 0); 1710 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 1711 1712 /* repeat test with call to TpWaitForWait(..., TRUE) */ 1713 info.userdata = 0; 1714 when.QuadPart = (ULONGLONG)200 * -10000; 1715 pTpSetWait(wait1, semaphores[1], &when); 1716 result = WaitForSingleObject(semaphores[0], 100); 1717 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 1718 pTpWaitForWait(wait1, TRUE); 1719 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata); 1720 result = WaitForSingleObject(semaphores[0], 200); 1721 ok(result == WAIT_OBJECT_0 || broken(result == WAIT_TIMEOUT) /* Win 8 */, 1722 "WaitForSingleObject returned %lu\n", result); 1723 if (result == WAIT_OBJECT_0) 1724 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata); 1725 else 1726 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata); 1727 result = WaitForSingleObject(semaphores[1], 0); 1728 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 1729 1730 /* relative timeout, with event */ 1731 info.userdata = 0; 1732 when.QuadPart = (ULONGLONG)200 * -10000; 1733 pTpSetWait(wait1, semaphores[1], &when); 1734 result = WaitForSingleObject(semaphores[0], 100); 1735 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 1736 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata); 1737 ReleaseSemaphore(semaphores[1], 1, NULL); 1738 result = WaitForSingleObject(semaphores[0], 100); 1739 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1740 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); 1741 result = WaitForSingleObject(semaphores[1], 0); 1742 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 1743 1744 /* repeat test with call to TpWaitForWait(..., TRUE) */ 1745 info.userdata = 0; 1746 when.QuadPart = (ULONGLONG)200 * -10000; 1747 pTpSetWait(wait1, semaphores[1], &when); 1748 result = WaitForSingleObject(semaphores[0], 100); 1749 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 1750 pTpWaitForWait(wait1, TRUE); 1751 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata); 1752 ReleaseSemaphore(semaphores[1], 1, NULL); 1753 result = WaitForSingleObject(semaphores[0], 100); 1754 ok(result == WAIT_OBJECT_0 || broken(result == WAIT_TIMEOUT) /* Win 8 */, 1755 "WaitForSingleObject returned %lu\n", result); 1756 if (result == WAIT_OBJECT_0) 1757 { 1758 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); 1759 result = WaitForSingleObject(semaphores[1], 0); 1760 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 1761 } 1762 else 1763 { 1764 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata); 1765 result = WaitForSingleObject(semaphores[1], 0); 1766 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1767 } 1768 1769 /* absolute timeout, no event */ 1770 info.userdata = 0; 1771 NtQuerySystemTime( &when ); 1772 when.QuadPart += (ULONGLONG)200 * 10000; 1773 pTpSetWait(wait1, semaphores[1], &when); 1774 result = WaitForSingleObject(semaphores[0], 100); 1775 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 1776 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata); 1777 result = WaitForSingleObject(semaphores[0], 200); 1778 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1779 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata); 1780 result = WaitForSingleObject(semaphores[1], 0); 1781 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 1782 1783 /* absolute timeout, with event */ 1784 info.userdata = 0; 1785 NtQuerySystemTime( &when ); 1786 when.QuadPart += (ULONGLONG)200 * 10000; 1787 pTpSetWait(wait1, semaphores[1], &when); 1788 result = WaitForSingleObject(semaphores[0], 100); 1789 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 1790 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata); 1791 ReleaseSemaphore(semaphores[1], 1, NULL); 1792 result = WaitForSingleObject(semaphores[0], 100); 1793 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1794 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); 1795 result = WaitForSingleObject(semaphores[1], 0); 1796 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 1797 1798 /* test timeout of zero */ 1799 info.userdata = 0; 1800 when.QuadPart = 0; 1801 pTpSetWait(wait1, semaphores[1], &when); 1802 result = WaitForSingleObject(semaphores[0], 100); 1803 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1804 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata); 1805 result = WaitForSingleObject(semaphores[1], 0); 1806 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 1807 1808 /* cancel a pending wait */ 1809 info.userdata = 0; 1810 when.QuadPart = (ULONGLONG)250 * -10000; 1811 pTpSetWait(wait1, semaphores[1], &when); 1812 result = WaitForSingleObject(semaphores[0], 100); 1813 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 1814 pTpSetWait(wait1, NULL, (void *)0xdeadbeef); 1815 Sleep(50); 1816 ReleaseSemaphore(semaphores[1], 1, NULL); 1817 result = WaitForSingleObject(semaphores[0], 100); 1818 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 1819 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata); 1820 result = WaitForSingleObject(semaphores[1], 0); 1821 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1822 1823 /* test with INVALID_HANDLE_VALUE */ 1824 info.userdata = 0; 1825 when.QuadPart = 0; 1826 pTpSetWait(wait1, INVALID_HANDLE_VALUE, &when); 1827 result = WaitForSingleObject(semaphores[0], 100); 1828 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1829 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata); 1830 1831 /* cancel a pending wait with INVALID_HANDLE_VALUE */ 1832 info.userdata = 0; 1833 when.QuadPart = (ULONGLONG)250 * -10000; 1834 pTpSetWait(wait1, semaphores[1], &when); 1835 result = WaitForSingleObject(semaphores[0], 100); 1836 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 1837 when.QuadPart = 0; 1838 pTpSetWait(wait1, INVALID_HANDLE_VALUE, &when); 1839 Sleep(50); 1840 ReleaseSemaphore(semaphores[1], 1, NULL); 1841 result = WaitForSingleObject(semaphores[0], 100); 1842 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1843 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata); 1844 result = WaitForSingleObject(semaphores[1], 0); 1845 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1846 1847 CloseHandle(semaphores[1]); 1848 semaphores[1] = CreateSemaphoreW(NULL, 0, 2, NULL); 1849 ok(semaphores[1] != NULL, "failed to create semaphore\n"); 1850 1851 /* add two wait objects with the same semaphore */ 1852 info.userdata = 0; 1853 pTpSetWait(wait1, semaphores[1], NULL); 1854 pTpSetWait(wait2, semaphores[1], NULL); 1855 Sleep(50); 1856 ReleaseSemaphore(semaphores[1], 1, NULL); 1857 result = WaitForSingleObject(semaphores[0], 100); 1858 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1859 result = WaitForSingleObject(semaphores[0], 100); 1860 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 1861 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata); 1862 result = WaitForSingleObject(semaphores[1], 0); 1863 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 1864 1865 /* repeat test above with release count 2 */ 1866 info.userdata = 0; 1867 pTpSetWait(wait1, semaphores[1], NULL); 1868 pTpSetWait(wait2, semaphores[1], NULL); 1869 Sleep(50); 1870 result = ReleaseSemaphore(semaphores[1], 2, NULL); 1871 result = WaitForSingleObject(semaphores[0], 100); 1872 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1873 result = WaitForSingleObject(semaphores[0], 100); 1874 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1875 ok(info.userdata == 2, "expected info.userdata = 2, got %lu\n", info.userdata); 1876 result = WaitForSingleObject(semaphores[1], 0); 1877 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result); 1878 1879 /* cleanup */ 1880 pTpReleaseWait(wait1); 1881 pTpReleaseWait(wait2); 1882 pTpReleasePool(pool); 1883 CloseHandle(semaphores[0]); 1884 CloseHandle(semaphores[1]); 1885} 1886 1887static struct 1888{ 1889 HANDLE semaphore; 1890 DWORD result; 1891} multi_wait_info; 1892 1893static void CALLBACK multi_wait_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WAIT *wait, TP_WAIT_RESULT result) 1894{ 1895 DWORD index = (DWORD)(DWORD_PTR)userdata; 1896 1897 if (result == WAIT_OBJECT_0) 1898 multi_wait_info.result = index; 1899 else if (result == WAIT_TIMEOUT) 1900 multi_wait_info.result = 0x10000 | index; 1901 else 1902 ok(0, "unexpected result %lu\n", result); 1903 ReleaseSemaphore(multi_wait_info.semaphore, 1, NULL); 1904} 1905 1906static void test_tp_multi_wait(void) 1907{ 1908 TP_POOL_STACK_INFORMATION stack_info; 1909 TP_CALLBACK_ENVIRON environment; 1910 HANDLE semaphores[512]; 1911 TP_WAIT *waits[512]; 1912 LARGE_INTEGER when; 1913 HANDLE semaphore; 1914 NTSTATUS status; 1915 TP_POOL *pool; 1916 DWORD result; 1917 int i; 1918 1919 semaphore = CreateSemaphoreW(NULL, 0, 512, NULL); 1920 ok(semaphore != NULL, "failed to create semaphore\n"); 1921 multi_wait_info.semaphore = semaphore; 1922 1923 /* allocate new threadpool */ 1924 pool = NULL; 1925 status = pTpAllocPool(&pool, NULL); 1926 ok(!status, "TpAllocPool failed with status %lx\n", status); 1927 ok(pool != NULL, "expected pool != NULL\n"); 1928 /* many threads -> use the smallest stack possible */ 1929 stack_info.StackReserve = 256 * 1024; 1930 stack_info.StackCommit = 4 * 1024; 1931 status = pTpSetPoolStackInformation(pool, &stack_info); 1932 ok(!status, "TpQueryPoolStackInformation failed: %lx\n", status); 1933 1934 memset(&environment, 0, sizeof(environment)); 1935 environment.Version = 1; 1936 environment.Pool = pool; 1937 1938 /* create semaphores and corresponding wait objects */ 1939 for (i = 0; i < ARRAY_SIZE(semaphores); i++) 1940 { 1941 semaphores[i] = CreateSemaphoreW(NULL, 0, 1, NULL); 1942 ok(semaphores[i] != NULL, "failed to create semaphore %i\n", i); 1943 1944 waits[i] = NULL; 1945 status = pTpAllocWait(&waits[i], multi_wait_cb, (void *)(DWORD_PTR)i, &environment); 1946 ok(!status, "TpAllocWait failed with status %lx\n", status); 1947 ok(waits[i] != NULL, "expected waits[%d] != NULL\n", i); 1948 1949 pTpSetWait(waits[i], semaphores[i], NULL); 1950 } 1951 1952 /* release all semaphores and wait for callback */ 1953 for (i = 0; i < ARRAY_SIZE(semaphores); i++) 1954 { 1955 multi_wait_info.result = 0; 1956 ReleaseSemaphore(semaphores[i], 1, NULL); 1957 1958 result = WaitForSingleObject(semaphore, 2000); 1959 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1960 ok(multi_wait_info.result == i, "expected result %d, got %lu\n", i, multi_wait_info.result); 1961 1962 pTpSetWait(waits[i], semaphores[i], NULL); 1963 } 1964 1965 /* repeat the same test in reverse order */ 1966 for (i = ARRAY_SIZE(semaphores) - 1; i >= 0; i--) 1967 { 1968 multi_wait_info.result = 0; 1969 ReleaseSemaphore(semaphores[i], 1, NULL); 1970 1971 result = WaitForSingleObject(semaphore, 2000); 1972 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1973 ok(multi_wait_info.result == i, "expected result %d, got %lu\n", i, multi_wait_info.result); 1974 1975 pTpSetWait(waits[i], semaphores[i], NULL); 1976 } 1977 1978 /* test timeout of wait objects */ 1979 multi_wait_info.result = 0; 1980 for (i = 0; i < ARRAY_SIZE(semaphores); i++) 1981 { 1982 when.QuadPart = (ULONGLONG)50 * -10000; 1983 pTpSetWait(waits[i], semaphores[i], &when); 1984 } 1985 1986 for (i = 0; i < ARRAY_SIZE(semaphores); i++) 1987 { 1988 result = WaitForSingleObject(semaphore, 2000); 1989 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); 1990 } 1991 1992 ok(multi_wait_info.result >> 16, "expected multi_wait_info.result >> 16 != 0\n"); 1993 1994 /* destroy the wait objects and semaphores while waiting */ 1995 for (i = 0; i < ARRAY_SIZE(semaphores); i++) 1996 { 1997 pTpSetWait(waits[i], semaphores[i], NULL); 1998 } 1999 2000 Sleep(50); 2001 2002 for (i = 0; i < ARRAY_SIZE(semaphores); i++) 2003 { 2004 pTpReleaseWait(waits[i]); 2005 NtClose(semaphores[i]); 2006 } 2007 2008 pTpReleasePool(pool); 2009 CloseHandle(semaphore); 2010} 2011 2012struct io_cb_ctx 2013{ 2014 unsigned int count; 2015 void *ovl; 2016 NTSTATUS ret; 2017 ULONG_PTR length; 2018 TP_IO *io; 2019}; 2020 2021static void CALLBACK io_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, 2022 void *cvalue, IO_STATUS_BLOCK *iosb, TP_IO *io) 2023{ 2024 struct io_cb_ctx *ctx = userdata; 2025 ++ctx->count; 2026 ctx->ovl = cvalue; 2027 ctx->ret = iosb->Status; 2028 ctx->length = iosb->Information; 2029 ctx->io = io; 2030} 2031 2032static DWORD WINAPI io_wait_thread(void *arg) 2033{ 2034 TP_IO *io = arg; 2035 pTpWaitForIoCompletion(io, FALSE); 2036 return 0; 2037} 2038 2039static void test_tp_io(void) 2040{ 2041 TP_CALLBACK_ENVIRON environment = {.Version = 1}; 2042#ifdef __REACTOS__ 2043 OVERLAPPED ovl = {0}, ovl2 = {0}; 2044#else 2045 OVERLAPPED ovl = {}, ovl2 = {}; 2046#endif 2047 HANDLE client, server, thread; 2048 struct io_cb_ctx userdata; 2049 char in[1], in2[1]; 2050 const char out[1]; 2051 NTSTATUS status; 2052 DWORD ret_size; 2053 TP_POOL *pool; 2054 TP_IO *io; 2055 BOOL ret; 2056 2057 ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); 2058 2059 status = pTpAllocPool(&pool, NULL); 2060 ok(!status, "failed to allocate pool, status %#lx\n", status); 2061 2062 server = CreateNamedPipeA("\\\\.\\pipe\\wine_tp_test", 2063 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0, 1, 1024, 1024, 0, NULL); 2064 ok(server != INVALID_HANDLE_VALUE, "Failed to create server pipe, error %lu.\n", GetLastError()); 2065 client = CreateFileA("\\\\.\\pipe\\wine_tp_test", GENERIC_READ | GENERIC_WRITE, 2066 0, NULL, OPEN_EXISTING, 0, 0); 2067 ok(client != INVALID_HANDLE_VALUE, "Failed to create client pipe, error %lu.\n", GetLastError()); 2068 2069 environment.Pool = pool; 2070 io = NULL; 2071 status = pTpAllocIoCompletion(&io, server, io_cb, &userdata, &environment); 2072 ok(!status, "got %#lx\n", status); 2073 ok(!!io, "expected non-NULL TP_IO\n"); 2074 2075 pTpWaitForIoCompletion(io, FALSE); 2076 2077 userdata.count = 0; 2078 pTpStartAsyncIoOperation(io); 2079 2080 thread = CreateThread(NULL, 0, io_wait_thread, io, 0, NULL); 2081 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "TpWaitForIoCompletion() should not return\n"); 2082 2083 ret = ReadFile(server, in, sizeof(in), NULL, &ovl); 2084 ok(!ret, "wrong ret %d\n", ret); 2085 ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError()); 2086 2087 ret = WriteFile(client, out, sizeof(out), &ret_size, NULL); 2088 ok(ret, "WriteFile() failed, error %lu\n", GetLastError()); 2089 2090 pTpWaitForIoCompletion(io, FALSE); 2091 ok(userdata.count == 1, "callback ran %u times\n", userdata.count); 2092 ok(userdata.ovl == &ovl, "expected %p, got %p\n", &ovl, userdata.ovl); 2093 ok(userdata.ret == STATUS_SUCCESS, "got status %#lx\n", userdata.ret); 2094 ok(userdata.length == 1, "got length %Iu\n", userdata.length); 2095 ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io); 2096 2097 ok(!WaitForSingleObject(thread, 1000), "wait timed out\n"); 2098 CloseHandle(thread); 2099 2100 userdata.count = 0; 2101 pTpStartAsyncIoOperation(io); 2102 pTpStartAsyncIoOperation(io); 2103 2104 ret = ReadFile(server, in, sizeof(in), NULL, &ovl); 2105 ok(!ret, "wrong ret %d\n", ret); 2106 ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError()); 2107 ret = ReadFile(server, in2, sizeof(in2), NULL, &ovl2); 2108 ok(!ret, "wrong ret %d\n", ret); 2109 ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError()); 2110 2111 ret = WriteFile(client, out, sizeof(out), &ret_size, NULL); 2112 ok(ret, "WriteFile() failed, error %lu\n", GetLastError()); 2113 ret = WriteFile(client, out, sizeof(out), &ret_size, NULL); 2114 ok(ret, "WriteFile() failed, error %lu\n", GetLastError()); 2115 2116 pTpWaitForIoCompletion(io, FALSE); 2117 ok(userdata.count == 2, "callback ran %u times\n", userdata.count); 2118 ok(userdata.ret == STATUS_SUCCESS, "got status %#lx\n", userdata.ret); 2119 ok(userdata.length == 1, "got length %Iu\n", userdata.length); 2120 ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io); 2121 2122 /* The documentation is a bit unclear about passing TRUE to 2123 * WaitForThreadpoolIoCallbacks()—"pending I/O requests are not canceled" 2124 * [as with CancelIoEx()], but pending threadpool callbacks are, even those 2125 * which have not yet reached the completion port [as with 2126 * TpCancelAsyncIoOperation()]. */ 2127 userdata.count = 0; 2128 pTpStartAsyncIoOperation(io); 2129 2130 pTpWaitForIoCompletion(io, TRUE); 2131 ok(!userdata.count, "callback ran %u times\n", userdata.count); 2132 2133 pTpStartAsyncIoOperation(io); 2134 2135 ret = WriteFile(client, out, sizeof(out), &ret_size, NULL); 2136 ok(ret, "WriteFile() failed, error %lu\n", GetLastError()); 2137 2138 ret = ReadFile(server, in, sizeof(in), NULL, &ovl); 2139 ok(ret, "wrong ret %d\n", ret); 2140 2141 pTpWaitForIoCompletion(io, FALSE); 2142 ok(userdata.count == 1, "callback ran %u times\n", userdata.count); 2143 ok(userdata.ovl == &ovl, "expected %p, got %p\n", &ovl, userdata.ovl); 2144 ok(userdata.ret == STATUS_SUCCESS, "got status %#lx\n", userdata.ret); 2145 ok(userdata.length == 1, "got length %Iu\n", userdata.length); 2146 ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io); 2147 2148 userdata.count = 0; 2149 pTpStartAsyncIoOperation(io); 2150 2151 ret = ReadFile(server, NULL, 1, NULL, &ovl); 2152 ok(!ret, "wrong ret %d\n", ret); 2153 ok(GetLastError() == ERROR_NOACCESS, "wrong error %lu\n", GetLastError()); 2154 2155 pTpCancelAsyncIoOperation(io); 2156 pTpWaitForIoCompletion(io, FALSE); 2157 ok(!userdata.count, "callback ran %u times\n", userdata.count); 2158 2159 userdata.count = 0; 2160 pTpStartAsyncIoOperation(io); 2161 2162 ret = ReadFile(server, in, sizeof(in), NULL, &ovl); 2163 ok(!ret, "wrong ret %d\n", ret); 2164 ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError()); 2165 ret = CancelIo(server); 2166 ok(ret, "CancelIo() failed, error %lu\n", GetLastError()); 2167 2168 pTpWaitForIoCompletion(io, FALSE); 2169 ok(userdata.count == 1, "callback ran %u times\n", userdata.count); 2170 ok(userdata.ovl == &ovl, "expected %p, got %p\n", &ovl, userdata.ovl); 2171 ok(userdata.ret == STATUS_CANCELLED, "got status %#lx\n", userdata.ret); 2172 ok(!userdata.length, "got length %Iu\n", userdata.length); 2173 ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io); 2174 2175 userdata.count = 0; 2176 pTpStartAsyncIoOperation(io); 2177 pTpCancelAsyncIoOperation(io); 2178 ret = ReadFile(server, in, sizeof(in), NULL, &ovl); 2179 ok(!ret, "wrong ret %d\n", ret); 2180 ret = WriteFile(client, out, sizeof(out), &ret_size, NULL); 2181 ok(ret, "WriteFile() failed, error %lu\n", GetLastError()); 2182 ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError()); 2183 2184 pTpWaitForIoCompletion(io, FALSE); 2185 if (0) 2186 { 2187 /* Add a sleep to check that callback is not called later. Commented out to 2188 * save the test time. */ 2189 Sleep(200); 2190 } 2191 ok(userdata.count == 0, "callback ran %u times\n", userdata.count); 2192 2193 pTpReleaseIoCompletion(io); 2194 CloseHandle(server); 2195 2196 /* Test TPIO object destruction. */ 2197 server = CreateNamedPipeA("\\\\.\\pipe\\wine_tp_test", 2198 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0, 1, 1024, 1024, 0, NULL); 2199 ok(server != INVALID_HANDLE_VALUE, "Failed to create server pipe, error %lu.\n", GetLastError()); 2200 io = NULL; 2201 status = pTpAllocIoCompletion(&io, server, io_cb, &userdata, &environment); 2202 ok(!status, "got %#lx\n", status); 2203 2204 ret = HeapValidate(GetProcessHeap(), 0, io); 2205 ok(ret, "Got unexpected ret %#x.\n", ret); 2206 pTpReleaseIoCompletion(io); 2207 ret = HeapValidate(GetProcessHeap(), 0, io); 2208 ok(!ret, "Got unexpected ret %#x.\n", ret); 2209 CloseHandle(server); 2210 CloseHandle(client); 2211 2212 server = CreateNamedPipeA("\\\\.\\pipe\\wine_tp_test", 2213 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0, 1, 1024, 1024, 0, NULL); 2214 ok(server != INVALID_HANDLE_VALUE, "Failed to create server pipe, error %lu.\n", GetLastError()); 2215 client = CreateFileA("\\\\.\\pipe\\wine_tp_test", GENERIC_READ | GENERIC_WRITE, 2216 0, NULL, OPEN_EXISTING, 0, 0); 2217 ok(client != INVALID_HANDLE_VALUE, "Failed to create client pipe, error %lu.\n", GetLastError()); 2218 2219 io = NULL; 2220 status = pTpAllocIoCompletion(&io, server, io_cb, &userdata, &environment); 2221 ok(!status, "got %#lx\n", status); 2222 pTpStartAsyncIoOperation(io); 2223 pTpWaitForIoCompletion(io, TRUE); 2224 ret = HeapValidate(GetProcessHeap(), 0, io); 2225 ok(ret, "Got unexpected ret %#x.\n", ret); 2226 pTpReleaseIoCompletion(io); 2227 ret = HeapValidate(GetProcessHeap(), 0, io); 2228 ok(ret, "Got unexpected ret %#x.\n", ret); 2229 2230 if (0) 2231 { 2232 /* Object destruction will wait until one completion arrives (which was started but not cancelled). 2233 * Commented out to save test time. */ 2234 Sleep(1000); 2235 ret = HeapValidate(GetProcessHeap(), 0, io); 2236 ok(ret, "Got unexpected ret %#x.\n", ret); 2237 ret = ReadFile(server, in, sizeof(in), NULL, &ovl); 2238 ok(!ret, "wrong ret %d\n", ret); 2239 ret = WriteFile(client, out, sizeof(out), &ret_size, NULL); 2240 ok(ret, "WriteFile() failed, error %lu\n", GetLastError()); 2241 Sleep(2000); 2242 ret = HeapValidate(GetProcessHeap(), 0, io); 2243 ok(!ret, "Got unexpected ret %#x.\n", ret); 2244 } 2245 2246 CloseHandle(server); 2247 CloseHandle(ovl.hEvent); 2248 CloseHandle(client); 2249 pTpReleasePool(pool); 2250} 2251 2252static void CALLBACK kernel32_io_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, 2253 void *ovl, ULONG ret, ULONG_PTR length, TP_IO *io) 2254{ 2255 struct io_cb_ctx *ctx = userdata; 2256 ++ctx->count; 2257 ctx->ovl = ovl; 2258 ctx->ret = ret; 2259 ctx->length = length; 2260 ctx->io = io; 2261} 2262 2263static void test_kernel32_tp_io(void) 2264{ 2265 TP_CALLBACK_ENVIRON environment = {.Version = 1}; 2266#ifdef __REACTOS__ 2267 OVERLAPPED ovl = {0}, ovl2 = {0}; 2268#else 2269 OVERLAPPED ovl = {}, ovl2 = {}; 2270#endif 2271 HANDLE client, server, thread; 2272 struct io_cb_ctx userdata; 2273 char in[1], in2[1]; 2274 const char out[1]; 2275 NTSTATUS status; 2276 DWORD ret_size; 2277 TP_POOL *pool; 2278 TP_IO *io; 2279 BOOL ret; 2280 2281 ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); 2282 2283 status = pTpAllocPool(&pool, NULL); 2284 ok(!status, "failed to allocate pool, status %#lx\n", status); 2285 2286 server = CreateNamedPipeA("\\\\.\\pipe\\wine_tp_test", 2287 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0, 1, 1024, 1024, 0, NULL); 2288 ok(server != INVALID_HANDLE_VALUE, "Failed to create server pipe, error %lu.\n", GetLastError()); 2289 client = CreateFileA("\\\\.\\pipe\\wine_tp_test", GENERIC_READ | GENERIC_WRITE, 2290 0, NULL, OPEN_EXISTING, 0, 0); 2291 ok(client != INVALID_HANDLE_VALUE, "Failed to create client pipe, error %lu.\n", GetLastError()); 2292 2293 environment.Pool = pool; 2294 io = NULL; 2295 io = pCreateThreadpoolIo(server, kernel32_io_cb, &userdata, &environment); 2296 ok(!!io, "expected non-NULL TP_IO\n"); 2297 2298 pWaitForThreadpoolIoCallbacks(io, FALSE); 2299 2300 userdata.count = 0; 2301 pStartThreadpoolIo(io); 2302 2303 thread = CreateThread(NULL, 0, io_wait_thread, io, 0, NULL); 2304 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "TpWaitForIoCompletion() should not return\n"); 2305 2306 ret = ReadFile(server, in, sizeof(in), NULL, &ovl); 2307 ok(!ret, "wrong ret %d\n", ret); 2308 ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError()); 2309 2310 ret = WriteFile(client, out, sizeof(out), &ret_size, NULL); 2311 ok(ret, "WriteFile() failed, error %lu\n", GetLastError()); 2312 2313 pWaitForThreadpoolIoCallbacks(io, FALSE); 2314 ok(userdata.count == 1, "callback ran %u times\n", userdata.count); 2315 ok(userdata.ovl == &ovl, "expected %p, got %p\n", &ovl, userdata.ovl); 2316 ok(userdata.ret == ERROR_SUCCESS, "got status %#lx\n", userdata.ret); 2317 ok(userdata.length == 1, "got length %Iu\n", userdata.length); 2318 ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io); 2319 2320 ok(!WaitForSingleObject(thread, 1000), "wait timed out\n"); 2321 CloseHandle(thread); 2322 2323 userdata.count = 0; 2324 pStartThreadpoolIo(io); 2325 pStartThreadpoolIo(io); 2326 2327 ret = ReadFile(server, in, sizeof(in), NULL, &ovl); 2328 ok(!ret, "wrong ret %d\n", ret); 2329 ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError()); 2330 ret = ReadFile(server, in2, sizeof(in2), NULL, &ovl2); 2331 ok(!ret, "wrong ret %d\n", ret); 2332 ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError()); 2333 2334 ret = WriteFile(client, out, sizeof(out), &ret_size, NULL); 2335 ok(ret, "WriteFile() failed, error %lu\n", GetLastError()); 2336 ret = WriteFile(client, out, sizeof(out), &ret_size, NULL); 2337 ok(ret, "WriteFile() failed, error %lu\n", GetLastError()); 2338 2339 pWaitForThreadpoolIoCallbacks(io, FALSE); 2340 ok(userdata.count == 2, "callback ran %u times\n", userdata.count); 2341 ok(userdata.ret == STATUS_SUCCESS, "got status %#lx\n", userdata.ret); 2342 ok(userdata.length == 1, "got length %Iu\n", userdata.length); 2343 ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io); 2344 2345 userdata.count = 0; 2346 pStartThreadpoolIo(io); 2347 pWaitForThreadpoolIoCallbacks(io, TRUE); 2348 ok(!userdata.count, "callback ran %u times\n", userdata.count); 2349 2350 pStartThreadpoolIo(io); 2351 2352 ret = WriteFile(client, out, sizeof(out), &ret_size, NULL); 2353 ok(ret, "WriteFile() failed, error %lu\n", GetLastError()); 2354 2355 ret = ReadFile(server, in, sizeof(in), NULL, &ovl); 2356 ok(ret, "wrong ret %d\n", ret); 2357 2358 pWaitForThreadpoolIoCallbacks(io, FALSE); 2359 ok(userdata.count == 1, "callback ran %u times\n", userdata.count); 2360 ok(userdata.ovl == &ovl, "expected %p, got %p\n", &ovl, userdata.ovl); 2361 ok(userdata.ret == ERROR_SUCCESS, "got status %#lx\n", userdata.ret); 2362 ok(userdata.length == 1, "got length %Iu\n", userdata.length); 2363 ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io); 2364 2365 userdata.count = 0; 2366 pStartThreadpoolIo(io); 2367 2368 ret = ReadFile(server, NULL, 1, NULL, &ovl); 2369 ok(!ret, "wrong ret %d\n", ret); 2370 ok(GetLastError() == ERROR_NOACCESS, "wrong error %lu\n", GetLastError()); 2371 2372 pCancelThreadpoolIo(io); 2373 pWaitForThreadpoolIoCallbacks(io, FALSE); 2374 ok(!userdata.count, "callback ran %u times\n", userdata.count); 2375 2376 userdata.count = 0; 2377 pStartThreadpoolIo(io); 2378 2379 ret = ReadFile(server, in, sizeof(in), NULL, &ovl); 2380 ok(!ret, "wrong ret %d\n", ret); 2381 ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError()); 2382 ret = CancelIo(server); 2383 ok(ret, "CancelIo() failed, error %lu\n", GetLastError()); 2384 2385 pWaitForThreadpoolIoCallbacks(io, FALSE); 2386 ok(userdata.count == 1, "callback ran %u times\n", userdata.count); 2387 ok(userdata.ovl == &ovl, "expected %p, got %p\n", &ovl, userdata.ovl); 2388 ok(userdata.ret == ERROR_OPERATION_ABORTED, "got status %#lx\n", userdata.ret); 2389 ok(!userdata.length, "got length %Iu\n", userdata.length); 2390 ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io); 2391 2392 CloseHandle(ovl.hEvent); 2393 CloseHandle(client); 2394 CloseHandle(server); 2395 pCloseThreadpoolIo(io); 2396 pTpReleasePool(pool); 2397} 2398 2399START_TEST(threadpool) 2400{ 2401 test_RtlQueueWorkItem(); 2402 test_RtlRegisterWait(); 2403 2404 if (!init_threadpool()) 2405 return; 2406 2407 test_tp_simple(); 2408 test_tp_work(); 2409 test_tp_work_scheduler(); 2410 test_tp_group_wait(); 2411 test_tp_group_cancel(); 2412 test_tp_instance(); 2413 test_tp_disassociate(); 2414 test_tp_timer(); 2415 test_tp_window_length(); 2416 test_tp_wait(); 2417 test_tp_multi_wait(); 2418 test_tp_io(); 2419 test_kernel32_tp_io(); 2420}