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 static HMODULE hntdll = 0; 24 static NTSTATUS (WINAPI *pTpAllocCleanupGroup)(TP_CLEANUP_GROUP **); 25 static NTSTATUS (WINAPI *pTpAllocPool)(TP_POOL **,PVOID); 26 static NTSTATUS (WINAPI *pTpAllocTimer)(TP_TIMER **,PTP_TIMER_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *); 27 static NTSTATUS (WINAPI *pTpAllocWait)(TP_WAIT **,PTP_WAIT_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *); 28 static NTSTATUS (WINAPI *pTpAllocWork)(TP_WORK **,PTP_WORK_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *); 29 static NTSTATUS (WINAPI *pTpCallbackMayRunLong)(TP_CALLBACK_INSTANCE *); 30 static VOID (WINAPI *pTpCallbackReleaseSemaphoreOnCompletion)(TP_CALLBACK_INSTANCE *,HANDLE,DWORD); 31 static VOID (WINAPI *pTpDisassociateCallback)(TP_CALLBACK_INSTANCE *); 32 static BOOL (WINAPI *pTpIsTimerSet)(TP_TIMER *); 33 static VOID (WINAPI *pTpReleaseWait)(TP_WAIT *); 34 static VOID (WINAPI *pTpPostWork)(TP_WORK *); 35 static VOID (WINAPI *pTpReleaseCleanupGroup)(TP_CLEANUP_GROUP *); 36 static VOID (WINAPI *pTpReleaseCleanupGroupMembers)(TP_CLEANUP_GROUP *,BOOL,PVOID); 37 static VOID (WINAPI *pTpReleasePool)(TP_POOL *); 38 static VOID (WINAPI *pTpReleaseTimer)(TP_TIMER *); 39 static VOID (WINAPI *pTpReleaseWork)(TP_WORK *); 40 static VOID (WINAPI *pTpSetPoolMaxThreads)(TP_POOL *,DWORD); 41 static VOID (WINAPI *pTpSetTimer)(TP_TIMER *,LARGE_INTEGER *,LONG,LONG); 42 static VOID (WINAPI *pTpSetWait)(TP_WAIT *,HANDLE,LARGE_INTEGER *); 43 static NTSTATUS (WINAPI *pTpSimpleTryPost)(PTP_SIMPLE_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *); 44 static VOID (WINAPI *pTpWaitForTimer)(TP_TIMER *,BOOL); 45 static VOID (WINAPI *pTpWaitForWait)(TP_WAIT *,BOOL); 46 static VOID (WINAPI *pTpWaitForWork)(TP_WORK *,BOOL); 47 48 #define NTDLL_GET_PROC(func) \ 49 do \ 50 { \ 51 p ## func = (void *)GetProcAddress(hntdll, #func); \ 52 if (!p ## func) trace("Failed to get address for %s\n", #func); \ 53 } \ 54 while (0) 55 56 static BOOL init_threadpool(void) 57 { 58 hntdll = GetModuleHandleA("ntdll"); 59 if (!hntdll) 60 { 61 win_skip("Could not load ntdll\n"); 62 return FALSE; 63 } 64 65 NTDLL_GET_PROC(TpAllocCleanupGroup); 66 NTDLL_GET_PROC(TpAllocPool); 67 NTDLL_GET_PROC(TpAllocTimer); 68 NTDLL_GET_PROC(TpAllocWait); 69 NTDLL_GET_PROC(TpAllocWork); 70 NTDLL_GET_PROC(TpCallbackMayRunLong); 71 NTDLL_GET_PROC(TpCallbackReleaseSemaphoreOnCompletion); 72 NTDLL_GET_PROC(TpDisassociateCallback); 73 NTDLL_GET_PROC(TpIsTimerSet); 74 NTDLL_GET_PROC(TpPostWork); 75 NTDLL_GET_PROC(TpReleaseCleanupGroup); 76 NTDLL_GET_PROC(TpReleaseCleanupGroupMembers); 77 NTDLL_GET_PROC(TpReleasePool); 78 NTDLL_GET_PROC(TpReleaseTimer); 79 NTDLL_GET_PROC(TpReleaseWait); 80 NTDLL_GET_PROC(TpReleaseWork); 81 NTDLL_GET_PROC(TpSetPoolMaxThreads); 82 NTDLL_GET_PROC(TpSetTimer); 83 NTDLL_GET_PROC(TpSetWait); 84 NTDLL_GET_PROC(TpSimpleTryPost); 85 NTDLL_GET_PROC(TpWaitForTimer); 86 NTDLL_GET_PROC(TpWaitForWait); 87 NTDLL_GET_PROC(TpWaitForWork); 88 89 if (!pTpAllocPool) 90 { 91 win_skip("Threadpool functions not supported, skipping tests\n"); 92 return FALSE; 93 } 94 95 return TRUE; 96 } 97 98 #undef NTDLL_GET_PROC 99 100 101 static DWORD CALLBACK rtl_work_cb(void *userdata) 102 { 103 HANDLE semaphore = userdata; 104 trace("Running rtl_work callback\n"); 105 ReleaseSemaphore(semaphore, 1, NULL); 106 return 0; 107 } 108 109 static void test_RtlQueueWorkItem(void) 110 { 111 HANDLE semaphore; 112 NTSTATUS status; 113 DWORD result; 114 115 semaphore = CreateSemaphoreA(NULL, 0, 1, NULL); 116 ok(semaphore != NULL, "CreateSemaphoreA failed %u\n", GetLastError()); 117 118 status = RtlQueueWorkItem(rtl_work_cb, semaphore, WT_EXECUTEDEFAULT); 119 ok(!status, "RtlQueueWorkItem failed with status %x\n", status); 120 result = WaitForSingleObject(semaphore, 1000); 121 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 122 123 status = RtlQueueWorkItem(rtl_work_cb, semaphore, WT_EXECUTEINIOTHREAD); 124 ok(!status, "RtlQueueWorkItem failed with status %x\n", status); 125 result = WaitForSingleObject(semaphore, 1000); 126 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 127 128 status = RtlQueueWorkItem(rtl_work_cb, semaphore, WT_EXECUTEINPERSISTENTTHREAD); 129 ok(!status, "RtlQueueWorkItem failed with status %x\n", status); 130 result = WaitForSingleObject(semaphore, 1000); 131 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 132 133 status = RtlQueueWorkItem(rtl_work_cb, semaphore, WT_EXECUTELONGFUNCTION); 134 ok(!status, "RtlQueueWorkItem failed with status %x\n", status); 135 result = WaitForSingleObject(semaphore, 1000); 136 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 137 138 status = RtlQueueWorkItem(rtl_work_cb, semaphore, WT_TRANSFER_IMPERSONATION); 139 ok(!status, "RtlQueueWorkItem failed with status %x\n", status); 140 result = WaitForSingleObject(semaphore, 1000); 141 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 142 143 CloseHandle(semaphore); 144 } 145 146 struct rtl_wait_info 147 { 148 HANDLE semaphore1; 149 HANDLE semaphore2; 150 DWORD wait_result; 151 DWORD threadid; 152 LONG userdata; 153 }; 154 155 static void CALLBACK rtl_wait_cb(void *userdata, BOOLEAN timeout) 156 { 157 struct rtl_wait_info *info = userdata; 158 DWORD result; 159 160 trace("Running rtl_wait callback\n"); 161 162 if (!timeout) 163 InterlockedIncrement(&info->userdata); 164 else 165 InterlockedExchangeAdd(&info->userdata, 0x10000); 166 info->threadid = GetCurrentThreadId(); 167 ReleaseSemaphore(info->semaphore1, 1, NULL); 168 169 if (info->semaphore2) 170 { 171 result = WaitForSingleObject(info->semaphore2, 200); 172 ok(result == info->wait_result, "expected %u, got %u\n", info->wait_result, result); 173 ReleaseSemaphore(info->semaphore1, 1, NULL); 174 } 175 } 176 177 static HANDLE rtl_wait_apc_semaphore; 178 179 static void CALLBACK rtl_wait_apc_cb(ULONG_PTR userdata) 180 { 181 trace("Running rtl_wait_apc callback\n"); 182 if (rtl_wait_apc_semaphore) 183 ReleaseSemaphore(rtl_wait_apc_semaphore, 1, NULL); 184 } 185 186 static void test_RtlRegisterWait(void) 187 { 188 HANDLE wait1, event, thread; 189 struct rtl_wait_info info; 190 HANDLE semaphores[2]; 191 NTSTATUS status; 192 DWORD result; 193 194 semaphores[0] = CreateSemaphoreW(NULL, 0, 2, NULL); 195 ok(semaphores[0] != NULL, "failed to create semaphore\n"); 196 semaphores[1] = CreateSemaphoreW(NULL, 0, 1, NULL); 197 ok(semaphores[1] != NULL, "failed to create semaphore\n"); 198 info.semaphore1 = semaphores[0]; 199 info.semaphore2 = NULL; 200 201 event = CreateEventW(NULL, FALSE, FALSE, NULL); 202 ok(event != NULL, "failed to create event\n"); 203 204 /* basic test for RtlRegisterWait and RtlDeregisterWait */ 205 wait1 = NULL; 206 info.userdata = 0; 207 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT); 208 ok(!status, "RtlRegisterWait failed with status %x\n", status); 209 ok(wait1 != NULL, "expected wait1 != NULL\n"); 210 status = RtlDeregisterWait(wait1); 211 ok(!status, "RtlDeregisterWait failed with status %x\n", status); 212 ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); 213 214 /* infinite timeout, signal the semaphore two times */ 215 info.userdata = 0; 216 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT); 217 ok(!status, "RtlRegisterWait failed with status %x\n", status); 218 ReleaseSemaphore(semaphores[1], 1, NULL); 219 result = WaitForSingleObject(semaphores[0], 100); 220 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 221 ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); 222 ReleaseSemaphore(semaphores[1], 1, NULL); 223 result = WaitForSingleObject(semaphores[0], 100); 224 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 225 ok(info.userdata == 2, "expected info.userdata = 2, got %u\n", info.userdata); 226 result = WaitForSingleObject(semaphores[1], 0); 227 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 228 Sleep(50); 229 status = RtlDeregisterWait(wait1); 230 ok(!status, "RtlDeregisterWait failed with status %x\n", status); 231 232 /* repeat test with WT_EXECUTEONLYONCE */ 233 info.userdata = 0; 234 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEONLYONCE); 235 ok(!status, "RtlRegisterWait failed with status %x\n", status); 236 ReleaseSemaphore(semaphores[1], 1, NULL); 237 result = WaitForSingleObject(semaphores[0], 100); 238 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 239 ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); 240 ReleaseSemaphore(semaphores[1], 1, NULL); 241 result = WaitForSingleObject(semaphores[0], 100); 242 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 243 ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); 244 result = WaitForSingleObject(semaphores[1], 0); 245 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 246 Sleep(50); 247 status = RtlDeregisterWait(wait1); 248 ok(!status, "RtlDeregisterWait failed with status %x\n", status); 249 250 /* finite timeout, no event */ 251 info.userdata = 0; 252 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 200, WT_EXECUTEDEFAULT); 253 ok(!status, "RtlRegisterWait failed with status %x\n", status); 254 result = WaitForSingleObject(semaphores[0], 100); 255 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 256 ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); 257 result = WaitForSingleObject(semaphores[0], 200); 258 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 259 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata); 260 result = WaitForSingleObject(semaphores[1], 0); 261 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 262 Sleep(50); 263 status = RtlDeregisterWait(wait1); 264 ok(!status, "RtlDeregisterWait failed with status %x\n", status); 265 266 /* finite timeout, with event */ 267 info.userdata = 0; 268 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 200, WT_EXECUTEDEFAULT); 269 ok(!status, "RtlRegisterWait failed with status %x\n", status); 270 result = WaitForSingleObject(semaphores[0], 100); 271 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 272 ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); 273 ReleaseSemaphore(semaphores[1], 1, NULL); 274 result = WaitForSingleObject(semaphores[0], 100); 275 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 276 ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); 277 result = WaitForSingleObject(semaphores[1], 0); 278 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 279 Sleep(50); 280 status = RtlDeregisterWait(wait1); 281 ok(!status, "RtlDeregisterWait failed with status %x\n", status); 282 283 /* test for IO threads */ 284 info.userdata = 0; 285 info.threadid = 0; 286 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEINIOTHREAD); 287 ok(!status, "RtlRegisterWait failed with status %x\n", status); 288 ReleaseSemaphore(semaphores[1], 1, NULL); 289 result = WaitForSingleObject(semaphores[0], 100); 290 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 291 ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); 292 ok(info.threadid != 0, "expected info.threadid != 0, got %u\n", info.threadid); 293 thread = OpenThread(THREAD_SET_CONTEXT, FALSE, info.threadid); 294 ok(thread != NULL, "OpenThread failed with %u\n", GetLastError()); 295 rtl_wait_apc_semaphore = semaphores[0]; 296 result = QueueUserAPC(rtl_wait_apc_cb, thread, 0); 297 ok(result != 0, "QueueUserAPC failed with %u\n", GetLastError()); 298 result = WaitForSingleObject(semaphores[0], 200); 299 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 300 rtl_wait_apc_semaphore = 0; 301 CloseHandle(thread); 302 ReleaseSemaphore(semaphores[1], 1, NULL); 303 result = WaitForSingleObject(semaphores[0], 100); 304 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 305 ok(info.userdata == 2, "expected info.userdata = 2, got %u\n", info.userdata); 306 Sleep(50); 307 status = RtlDeregisterWait(wait1); 308 ok(!status, "RtlDeregisterWait failed with status %x\n", status); 309 310 info.userdata = 0; 311 info.threadid = 0; 312 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT); 313 ok(!status, "RtlRegisterWait failed with status %x\n", status); 314 ReleaseSemaphore(semaphores[1], 1, NULL); 315 result = WaitForSingleObject(semaphores[0], 100); 316 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 317 ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); 318 ok(info.threadid != 0, "expected info.threadid != 0, got %u\n", info.threadid); 319 thread = OpenThread(THREAD_SET_CONTEXT, FALSE, info.threadid); 320 ok(thread != NULL, "OpenThread failed with %u\n", GetLastError()); 321 rtl_wait_apc_semaphore = semaphores[0]; 322 result = QueueUserAPC(rtl_wait_apc_cb, thread, 0); 323 ok(result != 0, "QueueUserAPC failed with %u\n", GetLastError()); 324 result = WaitForSingleObject(semaphores[0], 200); 325 ok(result == WAIT_TIMEOUT || broken(result == WAIT_OBJECT_0) /* >= Win Vista */, 326 "WaitForSingleObject returned %u\n", result); 327 rtl_wait_apc_semaphore = 0; 328 CloseHandle(thread); 329 ReleaseSemaphore(semaphores[1], 1, NULL); 330 result = WaitForSingleObject(semaphores[0], 100); 331 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 332 ok(info.userdata == 2, "expected info.userdata = 2, got %u\n", info.userdata); 333 Sleep(50); 334 status = RtlDeregisterWait(wait1); 335 ok(!status, "RtlDeregisterWait failed with status %x\n", status); 336 337 /* test RtlDeregisterWaitEx before wait expired */ 338 info.userdata = 0; 339 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT); 340 ok(!status, "RtlRegisterWait failed with status %x\n", status); 341 status = RtlDeregisterWaitEx(wait1, NULL); 342 ok(!status, "RtlDeregisterWaitEx failed with status %x\n", status); 343 ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); 344 345 info.userdata = 0; 346 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT); 347 ok(!status, "RtlRegisterWait failed with status %x\n", status); 348 status = RtlDeregisterWaitEx(wait1, INVALID_HANDLE_VALUE); 349 ok(!status, "RtlDeregisterWaitEx failed with status %x\n", status); 350 ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); 351 352 info.userdata = 0; 353 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT); 354 ok(!status, "RtlRegisterWait failed with status %x\n", status); 355 status = RtlDeregisterWaitEx(wait1, event); 356 ok(!status, "RtlDeregisterWaitEx failed with status %x\n", status); 357 ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); 358 result = WaitForSingleObject(event, 200); 359 todo_wine 360 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 361 362 /* test RtlDeregisterWaitEx after wait expired */ 363 info.userdata = 0; 364 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 0, WT_EXECUTEONLYONCE); 365 ok(!status, "RtlRegisterWait failed with status %x\n", status); 366 result = WaitForSingleObject(semaphores[0], 100); 367 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 368 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata); 369 Sleep(50); 370 status = RtlDeregisterWaitEx(wait1, NULL); 371 ok(!status, "RtlDeregisterWaitEx failed with status %x\n", status); 372 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata); 373 374 info.userdata = 0; 375 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 0, WT_EXECUTEONLYONCE); 376 ok(!status, "RtlRegisterWait failed with status %x\n", status); 377 result = WaitForSingleObject(semaphores[0], 100); 378 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 379 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata); 380 Sleep(50); 381 status = RtlDeregisterWaitEx(wait1, INVALID_HANDLE_VALUE); 382 ok(!status, "RtlDeregisterWaitEx failed with status %x\n", status); 383 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata); 384 385 info.userdata = 0; 386 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 0, WT_EXECUTEONLYONCE); 387 ok(!status, "RtlRegisterWait failed with status %x\n", status); 388 result = WaitForSingleObject(semaphores[0], 100); 389 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 390 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata); 391 Sleep(50); 392 status = RtlDeregisterWaitEx(wait1, event); 393 ok(!status, "RtlDeregisterWaitEx failed with status %x\n", status); 394 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata); 395 result = WaitForSingleObject(event, 200); 396 todo_wine 397 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 398 399 /* test RtlDeregisterWaitEx while callback is running */ 400 info.semaphore2 = semaphores[1]; 401 info.wait_result = WAIT_OBJECT_0; 402 403 info.userdata = 0; 404 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEONLYONCE); 405 ok(!status, "RtlRegisterWait failed with status %x\n", status); 406 ReleaseSemaphore(semaphores[1], 1, NULL); 407 result = WaitForSingleObject(semaphores[0], 1000); 408 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 409 ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); 410 status = RtlDeregisterWait(wait1); 411 ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %x\n", status); 412 ReleaseSemaphore(semaphores[1], 1, NULL); 413 result = WaitForSingleObject(semaphores[0], 1000); 414 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 415 416 info.userdata = 0; 417 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEONLYONCE); 418 ok(!status, "RtlRegisterWait failed with status %x\n", status); 419 ReleaseSemaphore(semaphores[1], 1, NULL); 420 result = WaitForSingleObject(semaphores[0], 1000); 421 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 422 ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); 423 status = RtlDeregisterWaitEx(wait1, NULL); 424 ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %x\n", status); 425 ReleaseSemaphore(semaphores[1], 1, NULL); 426 result = WaitForSingleObject(semaphores[0], 1000); 427 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 428 429 info.wait_result = WAIT_TIMEOUT; 430 info.userdata = 0; 431 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEONLYONCE); 432 ok(!status, "RtlRegisterWait failed with status %x\n", status); 433 ReleaseSemaphore(semaphores[1], 1, NULL); 434 result = WaitForSingleObject(semaphores[0], 1000); 435 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 436 ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); 437 status = RtlDeregisterWaitEx(wait1, INVALID_HANDLE_VALUE); 438 ok(!status, "RtlDeregisterWaitEx failed with status %x\n", status); 439 result = WaitForSingleObject(semaphores[0], 0); 440 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 441 442 info.wait_result = WAIT_OBJECT_0; 443 info.userdata = 0; 444 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEONLYONCE); 445 ok(!status, "RtlRegisterWait failed with status %x\n", status); 446 ReleaseSemaphore(semaphores[1], 1, NULL); 447 result = WaitForSingleObject(semaphores[0], 1000); 448 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 449 ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); 450 status = RtlDeregisterWaitEx(wait1, event); 451 ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %x\n", status); 452 ReleaseSemaphore(semaphores[1], 1, NULL); 453 result = WaitForSingleObject(event, 1000); 454 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 455 result = WaitForSingleObject(semaphores[0], 0); 456 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 457 458 CloseHandle(semaphores[0]); 459 CloseHandle(semaphores[1]); 460 CloseHandle(event); 461 } 462 463 static void CALLBACK simple_cb(TP_CALLBACK_INSTANCE *instance, void *userdata) 464 { 465 HANDLE semaphore = userdata; 466 trace("Running simple callback\n"); 467 ReleaseSemaphore(semaphore, 1, NULL); 468 } 469 470 static void CALLBACK simple2_cb(TP_CALLBACK_INSTANCE *instance, void *userdata) 471 { 472 trace("Running simple2 callback\n"); 473 Sleep(50); 474 InterlockedIncrement((LONG *)userdata); 475 } 476 477 static void test_tp_simple(void) 478 { 479 TP_CALLBACK_ENVIRON environment; 480 TP_CALLBACK_ENVIRON_V3 environment3; 481 TP_CLEANUP_GROUP *group; 482 HANDLE semaphore; 483 NTSTATUS status; 484 TP_POOL *pool; 485 LONG userdata; 486 DWORD result; 487 int i; 488 489 semaphore = CreateSemaphoreA(NULL, 0, 1, NULL); 490 ok(semaphore != NULL, "CreateSemaphoreA failed %u\n", GetLastError()); 491 492 /* post the callback using the default threadpool */ 493 memset(&environment, 0, sizeof(environment)); 494 environment.Version = 1; 495 environment.Pool = NULL; 496 status = pTpSimpleTryPost(simple_cb, semaphore, &environment); 497 ok(!status, "TpSimpleTryPost failed with status %x\n", status); 498 result = WaitForSingleObject(semaphore, 1000); 499 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 500 501 /* allocate new threadpool */ 502 pool = NULL; 503 status = pTpAllocPool(&pool, NULL); 504 ok(!status, "TpAllocPool failed with status %x\n", status); 505 ok(pool != NULL, "expected pool != NULL\n"); 506 507 /* post the callback using the new threadpool */ 508 memset(&environment, 0, sizeof(environment)); 509 environment.Version = 1; 510 environment.Pool = pool; 511 status = pTpSimpleTryPost(simple_cb, semaphore, &environment); 512 ok(!status, "TpSimpleTryPost failed with status %x\n", status); 513 result = WaitForSingleObject(semaphore, 1000); 514 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 515 516 /* test with environment version 3 */ 517 memset(&environment3, 0, sizeof(environment3)); 518 environment3.Version = 3; 519 environment3.Pool = pool; 520 environment3.CallbackPriority = TP_CALLBACK_PRIORITY_NORMAL; 521 environment3.Size = sizeof(environment3); 522 status = pTpSimpleTryPost(simple_cb, semaphore, (TP_CALLBACK_ENVIRON *)&environment3); 523 ok(!status, "TpSimpleTryPost failed with status %x\n", status); 524 result = WaitForSingleObject(semaphore, 1000); 525 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 526 527 /* test with invalid version number */ 528 memset(&environment, 0, sizeof(environment)); 529 environment.Version = 9999; 530 environment.Pool = pool; 531 status = pTpSimpleTryPost(simple_cb, semaphore, &environment); 532 todo_wine 533 ok(status == STATUS_INVALID_PARAMETER || broken(!status) /* Vista/2008 */, 534 "TpSimpleTryPost unexpectedly returned status %x\n", status); 535 if (!status) 536 { 537 result = WaitForSingleObject(semaphore, 1000); 538 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 539 } 540 541 /* allocate a cleanup group for synchronization */ 542 group = NULL; 543 status = pTpAllocCleanupGroup(&group); 544 ok(!status, "TpAllocCleanupGroup failed with status %x\n", status); 545 ok(group != NULL, "expected pool != NULL\n"); 546 547 /* use cleanup group to wait for a simple callback */ 548 userdata = 0; 549 memset(&environment, 0, sizeof(environment)); 550 environment.Version = 1; 551 environment.Pool = pool; 552 environment.CleanupGroup = group; 553 status = pTpSimpleTryPost(simple2_cb, &userdata, &environment); 554 ok(!status, "TpSimpleTryPost failed with status %x\n", status); 555 pTpReleaseCleanupGroupMembers(group, FALSE, NULL); 556 ok(userdata == 1, "expected userdata = 1, got %u\n", userdata); 557 558 /* test cancellation of pending simple callbacks */ 559 userdata = 0; 560 pTpSetPoolMaxThreads(pool, 10); 561 memset(&environment, 0, sizeof(environment)); 562 environment.Version = 1; 563 environment.Pool = pool; 564 environment.CleanupGroup = group; 565 for (i = 0; i < 100; i++) 566 { 567 status = pTpSimpleTryPost(simple2_cb, &userdata, &environment); 568 ok(!status, "TpSimpleTryPost failed with status %x\n", status); 569 } 570 pTpReleaseCleanupGroupMembers(group, TRUE, NULL); 571 ok(userdata < 100, "expected userdata < 100, got %u\n", userdata); 572 573 /* cleanup */ 574 pTpReleaseCleanupGroup(group); 575 pTpReleasePool(pool); 576 CloseHandle(semaphore); 577 } 578 579 static void CALLBACK work_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work) 580 { 581 trace("Running work callback\n"); 582 Sleep(100); 583 InterlockedIncrement((LONG *)userdata); 584 } 585 586 static void CALLBACK work2_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work) 587 { 588 trace("Running work2 callback\n"); 589 Sleep(100); 590 InterlockedExchangeAdd((LONG *)userdata, 0x10000); 591 } 592 593 static void test_tp_work(void) 594 { 595 TP_CALLBACK_ENVIRON environment; 596 TP_WORK *work; 597 TP_POOL *pool; 598 NTSTATUS status; 599 LONG userdata; 600 int i; 601 602 /* allocate new threadpool with only one thread */ 603 pool = NULL; 604 status = pTpAllocPool(&pool, NULL); 605 ok(!status, "TpAllocPool failed with status %x\n", status); 606 ok(pool != NULL, "expected pool != NULL\n"); 607 pTpSetPoolMaxThreads(pool, 1); 608 609 /* allocate new work item */ 610 work = NULL; 611 memset(&environment, 0, sizeof(environment)); 612 environment.Version = 1; 613 environment.Pool = pool; 614 status = pTpAllocWork(&work, work_cb, &userdata, &environment); 615 ok(!status, "TpAllocWork failed with status %x\n", status); 616 ok(work != NULL, "expected work != NULL\n"); 617 618 /* post 5 identical work items at once */ 619 userdata = 0; 620 for (i = 0; i < 5; i++) 621 pTpPostWork(work); 622 pTpWaitForWork(work, FALSE); 623 ok(userdata == 5, "expected userdata = 5, got %u\n", userdata); 624 625 /* add more tasks and cancel them immediately */ 626 userdata = 0; 627 for (i = 0; i < 10; i++) 628 pTpPostWork(work); 629 pTpWaitForWork(work, TRUE); 630 ok(userdata < 10, "expected userdata < 10, got %u\n", userdata); 631 632 /* cleanup */ 633 pTpReleaseWork(work); 634 pTpReleasePool(pool); 635 } 636 637 static void test_tp_work_scheduler(void) 638 { 639 TP_CALLBACK_ENVIRON environment; 640 TP_CLEANUP_GROUP *group; 641 TP_WORK *work, *work2; 642 TP_POOL *pool; 643 NTSTATUS status; 644 LONG userdata; 645 int i; 646 647 /* allocate new threadpool with only one thread */ 648 pool = NULL; 649 status = pTpAllocPool(&pool, NULL); 650 ok(!status, "TpAllocPool failed with status %x\n", status); 651 ok(pool != NULL, "expected pool != NULL\n"); 652 pTpSetPoolMaxThreads(pool, 1); 653 654 /* create a cleanup group */ 655 group = NULL; 656 status = pTpAllocCleanupGroup(&group); 657 ok(!status, "TpAllocCleanupGroup failed with status %x\n", status); 658 ok(group != NULL, "expected pool != NULL\n"); 659 660 /* the first work item has no cleanup group associated */ 661 work = NULL; 662 memset(&environment, 0, sizeof(environment)); 663 environment.Version = 1; 664 environment.Pool = pool; 665 status = pTpAllocWork(&work, work_cb, &userdata, &environment); 666 ok(!status, "TpAllocWork failed with status %x\n", status); 667 ok(work != NULL, "expected work != NULL\n"); 668 669 /* allocate a second work item with a cleanup group */ 670 work2 = NULL; 671 memset(&environment, 0, sizeof(environment)); 672 environment.Version = 1; 673 environment.Pool = pool; 674 environment.CleanupGroup = group; 675 status = pTpAllocWork(&work2, work2_cb, &userdata, &environment); 676 ok(!status, "TpAllocWork failed with status %x\n", status); 677 ok(work2 != NULL, "expected work2 != NULL\n"); 678 679 /* the 'work' callbacks are not blocking execution of 'work2' callbacks */ 680 userdata = 0; 681 for (i = 0; i < 10; i++) 682 pTpPostWork(work); 683 for (i = 0; i < 10; i++) 684 pTpPostWork(work2); 685 Sleep(500); 686 pTpWaitForWork(work, TRUE); 687 pTpWaitForWork(work2, TRUE); 688 ok(userdata & 0xffff, "expected userdata & 0xffff != 0, got %u\n", userdata & 0xffff); 689 ok(userdata >> 16, "expected userdata >> 16 != 0, got %u\n", userdata >> 16); 690 691 /* test TpReleaseCleanupGroupMembers on a work item */ 692 userdata = 0; 693 for (i = 0; i < 10; i++) 694 pTpPostWork(work); 695 for (i = 0; i < 3; i++) 696 pTpPostWork(work2); 697 pTpReleaseCleanupGroupMembers(group, FALSE, NULL); 698 pTpWaitForWork(work, TRUE); 699 ok((userdata & 0xffff) < 10, "expected userdata & 0xffff < 10, got %u\n", userdata & 0xffff); 700 ok((userdata >> 16) == 3, "expected userdata >> 16 == 3, got %u\n", userdata >> 16); 701 702 /* cleanup */ 703 pTpReleaseWork(work); 704 pTpReleaseCleanupGroup(group); 705 pTpReleasePool(pool); 706 } 707 708 static void CALLBACK simple_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata) 709 { 710 HANDLE *semaphores = userdata; 711 trace("Running simple release callback\n"); 712 ReleaseSemaphore(semaphores, 1, NULL); 713 Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */ 714 } 715 716 static void CALLBACK work_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work) 717 { 718 HANDLE semaphore = userdata; 719 trace("Running work release callback\n"); 720 ReleaseSemaphore(semaphore, 1, NULL); 721 Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */ 722 pTpReleaseWork(work); 723 } 724 725 static void CALLBACK timer_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer) 726 { 727 HANDLE semaphore = userdata; 728 trace("Running timer release callback\n"); 729 ReleaseSemaphore(semaphore, 1, NULL); 730 Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */ 731 pTpReleaseTimer(timer); 732 } 733 734 static void CALLBACK wait_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, 735 TP_WAIT *wait, TP_WAIT_RESULT result) 736 { 737 HANDLE semaphore = userdata; 738 trace("Running wait release callback\n"); 739 ReleaseSemaphore(semaphore, 1, NULL); 740 Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */ 741 pTpReleaseWait(wait); 742 } 743 744 static void test_tp_group_wait(void) 745 { 746 TP_CALLBACK_ENVIRON environment; 747 TP_CLEANUP_GROUP *group; 748 LARGE_INTEGER when; 749 HANDLE semaphore; 750 NTSTATUS status; 751 TP_TIMER *timer; 752 TP_WAIT *wait; 753 TP_WORK *work; 754 TP_POOL *pool; 755 DWORD result; 756 757 semaphore = CreateSemaphoreA(NULL, 0, 1, NULL); 758 ok(semaphore != NULL, "CreateSemaphoreA failed %u\n", GetLastError()); 759 760 /* allocate new threadpool */ 761 pool = NULL; 762 status = pTpAllocPool(&pool, NULL); 763 ok(!status, "TpAllocPool failed with status %x\n", status); 764 ok(pool != NULL, "expected pool != NULL\n"); 765 766 /* allocate a cleanup group */ 767 group = NULL; 768 status = pTpAllocCleanupGroup(&group); 769 ok(!status, "TpAllocCleanupGroup failed with status %x\n", status); 770 ok(group != NULL, "expected pool != NULL\n"); 771 772 /* release work object during TpReleaseCleanupGroupMembers */ 773 work = NULL; 774 memset(&environment, 0, sizeof(environment)); 775 environment.Version = 1; 776 environment.Pool = pool; 777 environment.CleanupGroup = group; 778 status = pTpAllocWork(&work, work_release_cb, semaphore, &environment); 779 ok(!status, "TpAllocWork failed with status %x\n", status); 780 ok(work != NULL, "expected work != NULL\n"); 781 pTpPostWork(work); 782 result = WaitForSingleObject(semaphore, 1000); 783 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 784 pTpReleaseCleanupGroupMembers(group, FALSE, NULL); 785 786 /* release timer object during TpReleaseCleanupGroupMembers */ 787 timer = NULL; 788 memset(&environment, 0, sizeof(environment)); 789 environment.Version = 1; 790 environment.Pool = pool; 791 environment.CleanupGroup = group; 792 status = pTpAllocTimer(&timer, timer_release_cb, semaphore, &environment); 793 ok(!status, "TpAllocTimer failed with status %x\n", status); 794 ok(timer != NULL, "expected timer != NULL\n"); 795 when.QuadPart = 0; 796 pTpSetTimer(timer, &when, 0, 0); 797 result = WaitForSingleObject(semaphore, 1000); 798 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 799 pTpReleaseCleanupGroupMembers(group, FALSE, NULL); 800 801 /* release wait object during TpReleaseCleanupGroupMembers */ 802 wait = NULL; 803 memset(&environment, 0, sizeof(environment)); 804 environment.Version = 1; 805 environment.Pool = pool; 806 environment.CleanupGroup = group; 807 status = pTpAllocWait(&wait, wait_release_cb, semaphore, &environment); 808 ok(!status, "TpAllocWait failed with status %x\n", status); 809 ok(wait != NULL, "expected wait != NULL\n"); 810 when.QuadPart = 0; 811 pTpSetWait(wait, INVALID_HANDLE_VALUE, &when); 812 result = WaitForSingleObject(semaphore, 1000); 813 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 814 pTpReleaseCleanupGroupMembers(group, FALSE, NULL); 815 816 /* cleanup */ 817 pTpReleaseCleanupGroup(group); 818 pTpReleasePool(pool); 819 CloseHandle(semaphore); 820 } 821 822 static DWORD group_cancel_tid; 823 824 static void CALLBACK simple_group_cancel_cb(TP_CALLBACK_INSTANCE *instance, void *userdata) 825 { 826 HANDLE *semaphores = userdata; 827 NTSTATUS status; 828 DWORD result; 829 int i; 830 831 trace("Running simple group cancel callback\n"); 832 833 status = pTpCallbackMayRunLong(instance); 834 ok(status == STATUS_TOO_MANY_THREADS || broken(status == 1) /* Win Vista / 2008 */, 835 "expected STATUS_TOO_MANY_THREADS, got %08x\n", status); 836 837 ReleaseSemaphore(semaphores[1], 1, NULL); 838 for (i = 0; i < 4; i++) 839 { 840 result = WaitForSingleObject(semaphores[0], 1000); 841 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 842 } 843 ReleaseSemaphore(semaphores[1], 1, NULL); 844 } 845 846 static void CALLBACK work_group_cancel_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work) 847 { 848 HANDLE *semaphores = userdata; 849 DWORD result; 850 851 trace("Running work group cancel callback\n"); 852 853 ReleaseSemaphore(semaphores[1], 1, NULL); 854 result = WaitForSingleObject(semaphores[0], 200); 855 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 856 } 857 858 static void CALLBACK group_cancel_cleanup_release_cb(void *object, void *userdata) 859 { 860 HANDLE *semaphores = userdata; 861 trace("Running group cancel cleanup release callback\n"); 862 group_cancel_tid = GetCurrentThreadId(); 863 ok(object == (void *)0xdeadbeef, "expected 0xdeadbeef, got %p\n", object); 864 ReleaseSemaphore(semaphores[0], 1, NULL); 865 } 866 867 static void CALLBACK group_cancel_cleanup_release2_cb(void *object, void *userdata) 868 { 869 HANDLE *semaphores = userdata; 870 trace("Running group cancel cleanup release2 callback\n"); 871 group_cancel_tid = GetCurrentThreadId(); 872 ok(object == userdata, "expected %p, got %p\n", userdata, object); 873 ReleaseSemaphore(semaphores[0], 1, NULL); 874 } 875 876 static void CALLBACK group_cancel_cleanup_increment_cb(void *object, void *userdata) 877 { 878 trace("Running group cancel cleanup increment callback\n"); 879 group_cancel_tid = GetCurrentThreadId(); 880 InterlockedIncrement((LONG *)userdata); 881 } 882 883 static void CALLBACK unexpected_simple_cb(TP_CALLBACK_INSTANCE *instance, void *userdata) 884 { 885 ok(0, "Unexpected callback\n"); 886 } 887 888 static void CALLBACK unexpected_work_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work) 889 { 890 ok(0, "Unexpected callback\n"); 891 } 892 893 static void CALLBACK unexpected_timer_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer) 894 { 895 ok(0, "Unexpected callback\n"); 896 } 897 898 static void CALLBACK unexpected_wait_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, 899 TP_WAIT *wait, TP_WAIT_RESULT result) 900 { 901 ok(0, "Unexpected callback\n"); 902 } 903 904 static void CALLBACK unexpected_group_cancel_cleanup_cb(void *object, void *userdata) 905 { 906 ok(0, "Unexpected callback\n"); 907 } 908 909 static void test_tp_group_cancel(void) 910 { 911 TP_CALLBACK_ENVIRON environment; 912 TP_CLEANUP_GROUP *group; 913 LONG userdata, userdata2; 914 HANDLE semaphores[2]; 915 NTSTATUS status; 916 TP_TIMER *timer; 917 TP_WAIT *wait; 918 TP_WORK *work; 919 TP_POOL *pool; 920 DWORD result; 921 int i; 922 923 semaphores[0] = CreateSemaphoreA(NULL, 0, 4, NULL); 924 ok(semaphores[0] != NULL, "CreateSemaphoreA failed %u\n", GetLastError()); 925 semaphores[1] = CreateSemaphoreA(NULL, 0, 1, NULL); 926 ok(semaphores[1] != NULL, "CreateSemaphoreA failed %u\n", GetLastError()); 927 928 /* allocate new threadpool with only one thread */ 929 pool = NULL; 930 status = pTpAllocPool(&pool, NULL); 931 ok(!status, "TpAllocPool failed with status %x\n", status); 932 ok(pool != NULL, "expected pool != NULL\n"); 933 pTpSetPoolMaxThreads(pool, 1); 934 935 /* allocate a cleanup group */ 936 group = NULL; 937 status = pTpAllocCleanupGroup(&group); 938 ok(!status, "TpAllocCleanupGroup failed with status %x\n", status); 939 ok(group != NULL, "expected pool != NULL\n"); 940 941 /* test execution of cancellation callback */ 942 memset(&environment, 0, sizeof(environment)); 943 environment.Version = 1; 944 environment.Pool = pool; 945 status = pTpSimpleTryPost(simple_group_cancel_cb, semaphores, &environment); 946 ok(!status, "TpSimpleTryPost failed with status %x\n", status); 947 result = WaitForSingleObject(semaphores[1], 1000); 948 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 949 950 memset(&environment, 0, sizeof(environment)); 951 environment.Version = 1; 952 environment.Pool = pool; 953 environment.CleanupGroup = group; 954 environment.CleanupGroupCancelCallback = group_cancel_cleanup_release_cb; 955 status = pTpSimpleTryPost(unexpected_simple_cb, (void *)0xdeadbeef, &environment); 956 ok(!status, "TpSimpleTryPost failed with status %x\n", status); 957 958 work = NULL; 959 status = pTpAllocWork(&work, unexpected_work_cb, (void *)0xdeadbeef, &environment); 960 ok(!status, "TpAllocWork failed with status %x\n", status); 961 ok(work != NULL, "expected work != NULL\n"); 962 963 timer = NULL; 964 status = pTpAllocTimer(&timer, unexpected_timer_cb, (void *)0xdeadbeef, &environment); 965 ok(!status, "TpAllocTimer failed with status %x\n", status); 966 ok(timer != NULL, "expected timer != NULL\n"); 967 968 wait = NULL; 969 status = pTpAllocWait(&wait, unexpected_wait_cb, (void *)0xdeadbeef, &environment); 970 ok(!status, "TpAllocWait failed with status %x\n", status); 971 ok(wait != NULL, "expected wait != NULL\n"); 972 973 group_cancel_tid = 0xdeadbeef; 974 pTpReleaseCleanupGroupMembers(group, TRUE, semaphores); 975 result = WaitForSingleObject(semaphores[1], 1000); 976 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 977 ok(group_cancel_tid == GetCurrentThreadId(), "expected tid %x, got %x\n", 978 GetCurrentThreadId(), group_cancel_tid); 979 980 /* test if cancellation callbacks are executed before or after wait */ 981 work = NULL; 982 memset(&environment, 0, sizeof(environment)); 983 environment.Version = 1; 984 environment.Pool = pool; 985 environment.CleanupGroup = group; 986 environment.CleanupGroupCancelCallback = group_cancel_cleanup_release2_cb; 987 status = pTpAllocWork(&work, work_group_cancel_cb, semaphores, &environment); 988 ok(!status, "TpAllocWork failed with status %x\n", status); 989 ok(work != NULL, "expected work != NULL\n"); 990 pTpPostWork(work); 991 pTpPostWork(work); 992 993 result = WaitForSingleObject(semaphores[1], 1000); 994 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 995 996 group_cancel_tid = 0xdeadbeef; 997 pTpReleaseCleanupGroupMembers(group, TRUE, semaphores); 998 result = WaitForSingleObject(semaphores[0], 1000); 999 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1000 ok(group_cancel_tid == GetCurrentThreadId(), "expected tid %x, got %x\n", 1001 GetCurrentThreadId(), group_cancel_tid); 1002 1003 /* group cancel callback is not executed if object is destroyed while waiting */ 1004 work = NULL; 1005 memset(&environment, 0, sizeof(environment)); 1006 environment.Version = 1; 1007 environment.Pool = pool; 1008 environment.CleanupGroup = group; 1009 environment.CleanupGroupCancelCallback = unexpected_group_cancel_cleanup_cb; 1010 status = pTpAllocWork(&work, work_release_cb, semaphores[1], &environment); 1011 ok(!status, "TpAllocWork failed with status %x\n", status); 1012 ok(work != NULL, "expected work != NULL\n"); 1013 pTpPostWork(work); 1014 1015 result = WaitForSingleObject(semaphores[1], 1000); 1016 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1017 pTpReleaseCleanupGroupMembers(group, TRUE, NULL); 1018 1019 /* terminated simple callbacks should not trigger the group cancel callback */ 1020 memset(&environment, 0, sizeof(environment)); 1021 environment.Version = 1; 1022 environment.Pool = pool; 1023 environment.CleanupGroup = group; 1024 environment.CleanupGroupCancelCallback = unexpected_group_cancel_cleanup_cb; 1025 status = pTpSimpleTryPost(simple_release_cb, semaphores[1], &environment); 1026 ok(!status, "TpSimpleTryPost failed with status %x\n", status); 1027 result = WaitForSingleObject(semaphores[1], 1000); 1028 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1029 pTpReleaseCleanupGroupMembers(group, TRUE, semaphores); 1030 1031 /* test cancellation callback for objects with multiple instances */ 1032 work = NULL; 1033 memset(&environment, 0, sizeof(environment)); 1034 environment.Version = 1; 1035 environment.Pool = pool; 1036 environment.CleanupGroup = group; 1037 environment.CleanupGroupCancelCallback = group_cancel_cleanup_increment_cb; 1038 status = pTpAllocWork(&work, work_cb, &userdata, &environment); 1039 ok(!status, "TpAllocWork failed with status %x\n", status); 1040 ok(work != NULL, "expected work != NULL\n"); 1041 1042 /* post 10 identical work items at once */ 1043 userdata = userdata2 = 0; 1044 for (i = 0; i < 10; i++) 1045 pTpPostWork(work); 1046 1047 /* check if we get multiple cancellation callbacks */ 1048 group_cancel_tid = 0xdeadbeef; 1049 pTpReleaseCleanupGroupMembers(group, TRUE, &userdata2); 1050 ok(userdata <= 5, "expected userdata <= 5, got %u\n", userdata); 1051 ok(userdata2 == 1, "expected only one cancellation callback, got %u\n", userdata2); 1052 ok(group_cancel_tid == GetCurrentThreadId(), "expected tid %x, got %x\n", 1053 GetCurrentThreadId(), group_cancel_tid); 1054 1055 /* cleanup */ 1056 pTpReleaseCleanupGroup(group); 1057 pTpReleasePool(pool); 1058 CloseHandle(semaphores[0]); 1059 CloseHandle(semaphores[1]); 1060 } 1061 1062 static void CALLBACK instance_semaphore_completion_cb(TP_CALLBACK_INSTANCE *instance, void *userdata) 1063 { 1064 HANDLE *semaphores = userdata; 1065 trace("Running instance completion callback\n"); 1066 pTpCallbackReleaseSemaphoreOnCompletion(instance, semaphores[0], 1); 1067 } 1068 1069 static void CALLBACK instance_finalization_cb(TP_CALLBACK_INSTANCE *instance, void *userdata) 1070 { 1071 HANDLE *semaphores = userdata; 1072 DWORD result; 1073 1074 trace("Running instance finalization callback\n"); 1075 1076 result = WaitForSingleObject(semaphores[0], 100); 1077 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 1078 ReleaseSemaphore(semaphores[1], 1, NULL); 1079 } 1080 1081 static void test_tp_instance(void) 1082 { 1083 TP_CALLBACK_ENVIRON environment; 1084 HANDLE semaphores[2]; 1085 NTSTATUS status; 1086 TP_POOL *pool; 1087 DWORD result; 1088 1089 semaphores[0] = CreateSemaphoreW(NULL, 0, 1, NULL); 1090 ok(semaphores[0] != NULL, "failed to create semaphore\n"); 1091 semaphores[1] = CreateSemaphoreW(NULL, 0, 1, NULL); 1092 ok(semaphores[1] != NULL, "failed to create semaphore\n"); 1093 1094 /* allocate new threadpool */ 1095 pool = NULL; 1096 status = pTpAllocPool(&pool, NULL); 1097 ok(!status, "TpAllocPool failed with status %x\n", status); 1098 ok(pool != NULL, "expected pool != NULL\n"); 1099 1100 /* test for TpCallbackReleaseSemaphoreOnCompletion */ 1101 memset(&environment, 0, sizeof(environment)); 1102 environment.Version = 1; 1103 environment.Pool = pool; 1104 status = pTpSimpleTryPost(instance_semaphore_completion_cb, semaphores, &environment); 1105 ok(!status, "TpSimpleTryPost failed with status %x\n", status); 1106 result = WaitForSingleObject(semaphores[0], 1000); 1107 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1108 1109 /* test for finalization callback */ 1110 memset(&environment, 0, sizeof(environment)); 1111 environment.Version = 1; 1112 environment.Pool = pool; 1113 environment.FinalizationCallback = instance_finalization_cb; 1114 status = pTpSimpleTryPost(instance_semaphore_completion_cb, semaphores, &environment); 1115 ok(!status, "TpSimpleTryPost failed with status %x\n", status); 1116 result = WaitForSingleObject(semaphores[0], 1000); 1117 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1118 result = WaitForSingleObject(semaphores[1], 1000); 1119 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1120 1121 /* cleanup */ 1122 pTpReleasePool(pool); 1123 CloseHandle(semaphores[0]); 1124 CloseHandle(semaphores[1]); 1125 } 1126 1127 static void CALLBACK disassociate_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work) 1128 { 1129 HANDLE *semaphores = userdata; 1130 DWORD result; 1131 1132 trace("Running disassociate callback\n"); 1133 1134 pTpDisassociateCallback(instance); 1135 result = WaitForSingleObject(semaphores[0], 1000); 1136 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1137 ReleaseSemaphore(semaphores[1], 1, NULL); 1138 } 1139 1140 static void CALLBACK disassociate2_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work) 1141 { 1142 HANDLE *semaphores = userdata; 1143 DWORD result; 1144 1145 trace("Running disassociate2 callback\n"); 1146 1147 pTpDisassociateCallback(instance); 1148 result = WaitForSingleObject(semaphores[0], 100); 1149 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 1150 ReleaseSemaphore(semaphores[1], 1, NULL); 1151 } 1152 1153 static void CALLBACK disassociate3_cb(TP_CALLBACK_INSTANCE *instance, void *userdata) 1154 { 1155 HANDLE *semaphores = userdata; 1156 DWORD result; 1157 1158 trace("Running disassociate3 callback\n"); 1159 1160 pTpDisassociateCallback(instance); 1161 result = WaitForSingleObject(semaphores[0], 100); 1162 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 1163 ReleaseSemaphore(semaphores[1], 1, NULL); 1164 } 1165 1166 static void test_tp_disassociate(void) 1167 { 1168 TP_CALLBACK_ENVIRON environment; 1169 TP_CLEANUP_GROUP *group; 1170 HANDLE semaphores[2]; 1171 NTSTATUS status; 1172 TP_POOL *pool; 1173 TP_WORK *work; 1174 DWORD result; 1175 1176 semaphores[0] = CreateSemaphoreW(NULL, 0, 1, NULL); 1177 ok(semaphores[0] != NULL, "failed to create semaphore\n"); 1178 semaphores[1] = CreateSemaphoreW(NULL, 0, 1, NULL); 1179 ok(semaphores[1] != NULL, "failed to create semaphore\n"); 1180 1181 /* allocate new threadpool and cleanup group */ 1182 pool = NULL; 1183 status = pTpAllocPool(&pool, NULL); 1184 ok(!status, "TpAllocPool failed with status %x\n", status); 1185 ok(pool != NULL, "expected pool != NULL\n"); 1186 1187 group = NULL; 1188 status = pTpAllocCleanupGroup(&group); 1189 ok(!status, "TpAllocCleanupGroup failed with status %x\n", status); 1190 ok(group != NULL, "expected pool != NULL\n"); 1191 1192 /* test TpDisassociateCallback on work objects without group */ 1193 work = NULL; 1194 memset(&environment, 0, sizeof(environment)); 1195 environment.Version = 1; 1196 environment.Pool = pool; 1197 status = pTpAllocWork(&work, disassociate_cb, semaphores, &environment); 1198 ok(!status, "TpAllocWork failed with status %x\n", status); 1199 ok(work != NULL, "expected work != NULL\n"); 1200 1201 pTpPostWork(work); 1202 pTpWaitForWork(work, FALSE); 1203 1204 result = WaitForSingleObject(semaphores[1], 100); 1205 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 1206 ReleaseSemaphore(semaphores[0], 1, NULL); 1207 result = WaitForSingleObject(semaphores[1], 1000); 1208 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1209 pTpReleaseWork(work); 1210 1211 /* test TpDisassociateCallback on work objects with group (1) */ 1212 work = NULL; 1213 memset(&environment, 0, sizeof(environment)); 1214 environment.Version = 1; 1215 environment.Pool = pool; 1216 environment.CleanupGroup = group; 1217 status = pTpAllocWork(&work, disassociate_cb, semaphores, &environment); 1218 ok(!status, "TpAllocWork failed with status %x\n", status); 1219 ok(work != NULL, "expected work != NULL\n"); 1220 1221 pTpPostWork(work); 1222 pTpWaitForWork(work, FALSE); 1223 1224 result = WaitForSingleObject(semaphores[1], 100); 1225 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 1226 ReleaseSemaphore(semaphores[0], 1, NULL); 1227 result = WaitForSingleObject(semaphores[1], 1000); 1228 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1229 pTpReleaseCleanupGroupMembers(group, FALSE, NULL); 1230 1231 /* test TpDisassociateCallback on work objects with group (2) */ 1232 work = NULL; 1233 memset(&environment, 0, sizeof(environment)); 1234 environment.Version = 1; 1235 environment.Pool = pool; 1236 environment.CleanupGroup = group; 1237 status = pTpAllocWork(&work, disassociate2_cb, semaphores, &environment); 1238 ok(!status, "TpAllocWork failed with status %x\n", status); 1239 ok(work != NULL, "expected work != NULL\n"); 1240 1241 pTpPostWork(work); 1242 pTpReleaseCleanupGroupMembers(group, FALSE, NULL); 1243 1244 ReleaseSemaphore(semaphores[0], 1, NULL); 1245 result = WaitForSingleObject(semaphores[1], 1000); 1246 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1247 result = WaitForSingleObject(semaphores[0], 1000); 1248 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1249 1250 /* test TpDisassociateCallback on simple callbacks */ 1251 memset(&environment, 0, sizeof(environment)); 1252 environment.Version = 1; 1253 environment.Pool = pool; 1254 environment.CleanupGroup = group; 1255 status = pTpSimpleTryPost(disassociate3_cb, semaphores, &environment); 1256 ok(!status, "TpSimpleTryPost failed with status %x\n", status); 1257 1258 pTpReleaseCleanupGroupMembers(group, FALSE, NULL); 1259 1260 ReleaseSemaphore(semaphores[0], 1, NULL); 1261 result = WaitForSingleObject(semaphores[1], 1000); 1262 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1263 result = WaitForSingleObject(semaphores[0], 1000); 1264 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1265 1266 /* cleanup */ 1267 pTpReleaseCleanupGroup(group); 1268 pTpReleasePool(pool); 1269 CloseHandle(semaphores[0]); 1270 CloseHandle(semaphores[1]); 1271 } 1272 1273 static void CALLBACK timer_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer) 1274 { 1275 HANDLE semaphore = userdata; 1276 trace("Running timer callback\n"); 1277 ReleaseSemaphore(semaphore, 1, NULL); 1278 } 1279 1280 static void test_tp_timer(void) 1281 { 1282 TP_CALLBACK_ENVIRON environment; 1283 DWORD result, ticks; 1284 LARGE_INTEGER when; 1285 HANDLE semaphore; 1286 NTSTATUS status; 1287 TP_TIMER *timer; 1288 TP_POOL *pool; 1289 BOOL success; 1290 int i; 1291 1292 semaphore = CreateSemaphoreA(NULL, 0, 1, NULL); 1293 ok(semaphore != NULL, "CreateSemaphoreA failed %u\n", GetLastError()); 1294 1295 /* allocate new threadpool */ 1296 pool = NULL; 1297 status = pTpAllocPool(&pool, NULL); 1298 ok(!status, "TpAllocPool failed with status %x\n", status); 1299 ok(pool != NULL, "expected pool != NULL\n"); 1300 1301 /* allocate new timer */ 1302 timer = NULL; 1303 memset(&environment, 0, sizeof(environment)); 1304 environment.Version = 1; 1305 environment.Pool = pool; 1306 status = pTpAllocTimer(&timer, timer_cb, semaphore, &environment); 1307 ok(!status, "TpAllocTimer failed with status %x\n", status); 1308 ok(timer != NULL, "expected timer != NULL\n"); 1309 1310 success = pTpIsTimerSet(timer); 1311 ok(!success, "TpIsTimerSet returned TRUE\n"); 1312 1313 /* test timer with a relative timeout */ 1314 when.QuadPart = (ULONGLONG)200 * -10000; 1315 pTpSetTimer(timer, &when, 0, 0); 1316 success = pTpIsTimerSet(timer); 1317 ok(success, "TpIsTimerSet returned FALSE\n"); 1318 1319 pTpWaitForTimer(timer, FALSE); 1320 1321 result = WaitForSingleObject(semaphore, 100); 1322 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 1323 result = WaitForSingleObject(semaphore, 200); 1324 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1325 success = pTpIsTimerSet(timer); 1326 ok(success, "TpIsTimerSet returned FALSE\n"); 1327 1328 /* test timer with an absolute timeout */ 1329 NtQuerySystemTime( &when ); 1330 when.QuadPart += (ULONGLONG)200 * 10000; 1331 pTpSetTimer(timer, &when, 0, 0); 1332 success = pTpIsTimerSet(timer); 1333 ok(success, "TpIsTimerSet returned FALSE\n"); 1334 1335 pTpWaitForTimer(timer, FALSE); 1336 1337 result = WaitForSingleObject(semaphore, 100); 1338 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 1339 result = WaitForSingleObject(semaphore, 200); 1340 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1341 success = pTpIsTimerSet(timer); 1342 ok(success, "TpIsTimerSet returned FALSE\n"); 1343 1344 /* test timer with zero timeout */ 1345 when.QuadPart = 0; 1346 pTpSetTimer(timer, &when, 0, 0); 1347 success = pTpIsTimerSet(timer); 1348 ok(success, "TpIsTimerSet returned FALSE\n"); 1349 1350 pTpWaitForTimer(timer, FALSE); 1351 1352 result = WaitForSingleObject(semaphore, 50); 1353 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1354 success = pTpIsTimerSet(timer); 1355 ok(success, "TpIsTimerSet returned FALSE\n"); 1356 1357 /* unset the timer */ 1358 pTpSetTimer(timer, NULL, 0, 0); 1359 success = pTpIsTimerSet(timer); 1360 ok(!success, "TpIsTimerSet returned TRUE\n"); 1361 pTpWaitForTimer(timer, TRUE); 1362 1363 pTpReleaseTimer(timer); 1364 CloseHandle(semaphore); 1365 1366 semaphore = CreateSemaphoreA(NULL, 0, 3, NULL); 1367 ok(semaphore != NULL, "CreateSemaphoreA failed %u\n", GetLastError()); 1368 1369 /* allocate a new timer */ 1370 timer = NULL; 1371 memset(&environment, 0, sizeof(environment)); 1372 environment.Version = 1; 1373 environment.Pool = pool; 1374 status = pTpAllocTimer(&timer, timer_cb, semaphore, &environment); 1375 ok(!status, "TpAllocTimer failed with status %x\n", status); 1376 ok(timer != NULL, "expected timer != NULL\n"); 1377 1378 /* test a relative timeout repeated periodically */ 1379 when.QuadPart = (ULONGLONG)200 * -10000; 1380 pTpSetTimer(timer, &when, 200, 0); 1381 success = pTpIsTimerSet(timer); 1382 ok(success, "TpIsTimerSet returned FALSE\n"); 1383 1384 /* wait until the timer was triggered three times */ 1385 ticks = GetTickCount(); 1386 for (i = 0; i < 3; i++) 1387 { 1388 result = WaitForSingleObject(semaphore, 1000); 1389 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1390 } 1391 ticks = GetTickCount() - ticks; 1392 ok(ticks >= 500 && (ticks <= 700 || broken(ticks <= 750)) /* Win 7 */, 1393 "expected approximately 600 ticks, got %u\n", ticks); 1394 1395 /* unset the timer */ 1396 pTpSetTimer(timer, NULL, 0, 0); 1397 success = pTpIsTimerSet(timer); 1398 ok(!success, "TpIsTimerSet returned TRUE\n"); 1399 pTpWaitForTimer(timer, TRUE); 1400 1401 /* cleanup */ 1402 pTpReleaseTimer(timer); 1403 pTpReleasePool(pool); 1404 CloseHandle(semaphore); 1405 } 1406 1407 struct window_length_info 1408 { 1409 HANDLE semaphore; 1410 DWORD ticks; 1411 }; 1412 1413 static void CALLBACK window_length_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer) 1414 { 1415 struct window_length_info *info = userdata; 1416 trace("Running window length callback\n"); 1417 info->ticks = GetTickCount(); 1418 ReleaseSemaphore(info->semaphore, 1, NULL); 1419 } 1420 1421 static void test_tp_window_length(void) 1422 { 1423 struct window_length_info info1, info2; 1424 TP_CALLBACK_ENVIRON environment; 1425 TP_TIMER *timer1, *timer2; 1426 LARGE_INTEGER when; 1427 HANDLE semaphore; 1428 NTSTATUS status; 1429 TP_POOL *pool; 1430 DWORD result; 1431 BOOL merged; 1432 1433 semaphore = CreateSemaphoreA(NULL, 0, 2, NULL); 1434 ok(semaphore != NULL, "CreateSemaphoreA failed %u\n", GetLastError()); 1435 1436 /* allocate new threadpool */ 1437 pool = NULL; 1438 status = pTpAllocPool(&pool, NULL); 1439 ok(!status, "TpAllocPool failed with status %x\n", status); 1440 ok(pool != NULL, "expected pool != NULL\n"); 1441 1442 /* allocate two identical timers */ 1443 memset(&environment, 0, sizeof(environment)); 1444 environment.Version = 1; 1445 environment.Pool = pool; 1446 1447 timer1 = NULL; 1448 info1.semaphore = semaphore; 1449 status = pTpAllocTimer(&timer1, window_length_cb, &info1, &environment); 1450 ok(!status, "TpAllocTimer failed with status %x\n", status); 1451 ok(timer1 != NULL, "expected timer1 != NULL\n"); 1452 1453 timer2 = NULL; 1454 info2.semaphore = semaphore; 1455 status = pTpAllocTimer(&timer2, window_length_cb, &info2, &environment); 1456 ok(!status, "TpAllocTimer failed with status %x\n", status); 1457 ok(timer2 != NULL, "expected timer2 != NULL\n"); 1458 1459 /* choose parameters so that timers are not merged */ 1460 info1.ticks = 0; 1461 info2.ticks = 0; 1462 1463 NtQuerySystemTime( &when ); 1464 when.QuadPart += (ULONGLONG)250 * 10000; 1465 pTpSetTimer(timer2, &when, 0, 0); 1466 Sleep(50); 1467 when.QuadPart -= (ULONGLONG)150 * 10000; 1468 pTpSetTimer(timer1, &when, 0, 75); 1469 1470 result = WaitForSingleObject(semaphore, 1000); 1471 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1472 result = WaitForSingleObject(semaphore, 1000); 1473 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1474 ok(info1.ticks != 0 && info2.ticks != 0, "expected that ticks are nonzero\n"); 1475 ok(info2.ticks >= info1.ticks + 75 || broken(info2.ticks < info1.ticks + 75) /* Win 2008 */, 1476 "expected that timers are not merged\n"); 1477 1478 /* timers will be merged */ 1479 info1.ticks = 0; 1480 info2.ticks = 0; 1481 1482 NtQuerySystemTime( &when ); 1483 when.QuadPart += (ULONGLONG)250 * 10000; 1484 pTpSetTimer(timer2, &when, 0, 0); 1485 Sleep(50); 1486 when.QuadPart -= (ULONGLONG)150 * 10000; 1487 pTpSetTimer(timer1, &when, 0, 200); 1488 1489 result = WaitForSingleObject(semaphore, 1000); 1490 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1491 result = WaitForSingleObject(semaphore, 1000); 1492 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1493 ok(info1.ticks != 0 && info2.ticks != 0, "expected that ticks are nonzero\n"); 1494 merged = info2.ticks >= info1.ticks - 50 && info2.ticks <= info1.ticks + 50; 1495 ok(merged || broken(!merged) /* Win 10 */, "expected that timers are merged\n"); 1496 1497 /* on Windows the timers also get merged in this case */ 1498 info1.ticks = 0; 1499 info2.ticks = 0; 1500 1501 NtQuerySystemTime( &when ); 1502 when.QuadPart += (ULONGLONG)100 * 10000; 1503 pTpSetTimer(timer1, &when, 0, 200); 1504 Sleep(50); 1505 when.QuadPart += (ULONGLONG)150 * 10000; 1506 pTpSetTimer(timer2, &when, 0, 0); 1507 1508 result = WaitForSingleObject(semaphore, 1000); 1509 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1510 result = WaitForSingleObject(semaphore, 1000); 1511 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1512 ok(info1.ticks != 0 && info2.ticks != 0, "expected that ticks are nonzero\n"); 1513 merged = info2.ticks >= info1.ticks - 50 && info2.ticks <= info1.ticks + 50; 1514 todo_wine 1515 ok(merged || broken(!merged) /* Win 10 */, "expected that timers are merged\n"); 1516 1517 /* cleanup */ 1518 pTpReleaseTimer(timer1); 1519 pTpReleaseTimer(timer2); 1520 pTpReleasePool(pool); 1521 CloseHandle(semaphore); 1522 } 1523 1524 struct wait_info 1525 { 1526 HANDLE semaphore; 1527 LONG userdata; 1528 }; 1529 1530 static void CALLBACK wait_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, 1531 TP_WAIT *wait, TP_WAIT_RESULT result) 1532 { 1533 struct wait_info *info = userdata; 1534 trace("Running wait callback\n"); 1535 1536 if (result == WAIT_OBJECT_0) 1537 InterlockedIncrement(&info->userdata); 1538 else if (result == WAIT_TIMEOUT) 1539 InterlockedExchangeAdd(&info->userdata, 0x10000); 1540 else 1541 ok(0, "unexpected result %u\n", result); 1542 ReleaseSemaphore(info->semaphore, 1, NULL); 1543 } 1544 1545 static void test_tp_wait(void) 1546 { 1547 TP_CALLBACK_ENVIRON environment; 1548 TP_WAIT *wait1, *wait2; 1549 struct wait_info info; 1550 HANDLE semaphores[2]; 1551 LARGE_INTEGER when; 1552 NTSTATUS status; 1553 TP_POOL *pool; 1554 DWORD result; 1555 1556 semaphores[0] = CreateSemaphoreW(NULL, 0, 2, NULL); 1557 ok(semaphores[0] != NULL, "failed to create semaphore\n"); 1558 semaphores[1] = CreateSemaphoreW(NULL, 0, 1, NULL); 1559 ok(semaphores[1] != NULL, "failed to create semaphore\n"); 1560 info.semaphore = semaphores[0]; 1561 1562 /* allocate new threadpool */ 1563 pool = NULL; 1564 status = pTpAllocPool(&pool, NULL); 1565 ok(!status, "TpAllocPool failed with status %x\n", status); 1566 ok(pool != NULL, "expected pool != NULL\n"); 1567 1568 /* allocate new wait items */ 1569 memset(&environment, 0, sizeof(environment)); 1570 environment.Version = 1; 1571 environment.Pool = pool; 1572 1573 wait1 = NULL; 1574 status = pTpAllocWait(&wait1, wait_cb, &info, &environment); 1575 ok(!status, "TpAllocWait failed with status %x\n", status); 1576 ok(wait1 != NULL, "expected wait1 != NULL\n"); 1577 1578 wait2 = NULL; 1579 status = pTpAllocWait(&wait2, wait_cb, &info, &environment); 1580 ok(!status, "TpAllocWait failed with status %x\n", status); 1581 ok(wait2 != NULL, "expected wait2 != NULL\n"); 1582 1583 /* infinite timeout, signal the semaphore immediately */ 1584 info.userdata = 0; 1585 pTpSetWait(wait1, semaphores[1], NULL); 1586 ReleaseSemaphore(semaphores[1], 1, NULL); 1587 result = WaitForSingleObject(semaphores[0], 100); 1588 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1589 ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); 1590 result = WaitForSingleObject(semaphores[1], 0); 1591 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 1592 1593 /* relative timeout, no event */ 1594 info.userdata = 0; 1595 when.QuadPart = (ULONGLONG)200 * -10000; 1596 pTpSetWait(wait1, semaphores[1], &when); 1597 result = WaitForSingleObject(semaphores[0], 100); 1598 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 1599 ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); 1600 result = WaitForSingleObject(semaphores[0], 200); 1601 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1602 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata); 1603 result = WaitForSingleObject(semaphores[1], 0); 1604 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 1605 1606 /* repeat test with call to TpWaitForWait(..., TRUE) */ 1607 info.userdata = 0; 1608 when.QuadPart = (ULONGLONG)200 * -10000; 1609 pTpSetWait(wait1, semaphores[1], &when); 1610 result = WaitForSingleObject(semaphores[0], 100); 1611 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 1612 pTpWaitForWait(wait1, TRUE); 1613 ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); 1614 result = WaitForSingleObject(semaphores[0], 200); 1615 ok(result == WAIT_OBJECT_0 || broken(result == WAIT_TIMEOUT) /* Win 8 */, 1616 "WaitForSingleObject returned %u\n", result); 1617 if (result == WAIT_OBJECT_0) 1618 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata); 1619 else 1620 ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); 1621 result = WaitForSingleObject(semaphores[1], 0); 1622 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 1623 1624 /* relative timeout, with event */ 1625 info.userdata = 0; 1626 when.QuadPart = (ULONGLONG)200 * -10000; 1627 pTpSetWait(wait1, semaphores[1], &when); 1628 result = WaitForSingleObject(semaphores[0], 100); 1629 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 1630 ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); 1631 ReleaseSemaphore(semaphores[1], 1, NULL); 1632 result = WaitForSingleObject(semaphores[0], 100); 1633 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1634 ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); 1635 result = WaitForSingleObject(semaphores[1], 0); 1636 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 1637 1638 /* repeat test with call to TpWaitForWait(..., TRUE) */ 1639 info.userdata = 0; 1640 when.QuadPart = (ULONGLONG)200 * -10000; 1641 pTpSetWait(wait1, semaphores[1], &when); 1642 result = WaitForSingleObject(semaphores[0], 100); 1643 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 1644 pTpWaitForWait(wait1, TRUE); 1645 ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); 1646 ReleaseSemaphore(semaphores[1], 1, NULL); 1647 result = WaitForSingleObject(semaphores[0], 100); 1648 ok(result == WAIT_OBJECT_0 || broken(result == WAIT_TIMEOUT) /* Win 8 */, 1649 "WaitForSingleObject returned %u\n", result); 1650 if (result == WAIT_OBJECT_0) 1651 { 1652 ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); 1653 result = WaitForSingleObject(semaphores[1], 0); 1654 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 1655 } 1656 else 1657 { 1658 ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); 1659 result = WaitForSingleObject(semaphores[1], 0); 1660 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1661 } 1662 1663 /* absolute timeout, no event */ 1664 info.userdata = 0; 1665 NtQuerySystemTime( &when ); 1666 when.QuadPart += (ULONGLONG)200 * 10000; 1667 pTpSetWait(wait1, semaphores[1], &when); 1668 result = WaitForSingleObject(semaphores[0], 100); 1669 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 1670 ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); 1671 result = WaitForSingleObject(semaphores[0], 200); 1672 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1673 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata); 1674 result = WaitForSingleObject(semaphores[1], 0); 1675 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 1676 1677 /* absolute timeout, with event */ 1678 info.userdata = 0; 1679 NtQuerySystemTime( &when ); 1680 when.QuadPart += (ULONGLONG)200 * 10000; 1681 pTpSetWait(wait1, semaphores[1], &when); 1682 result = WaitForSingleObject(semaphores[0], 100); 1683 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 1684 ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); 1685 ReleaseSemaphore(semaphores[1], 1, NULL); 1686 result = WaitForSingleObject(semaphores[0], 100); 1687 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1688 ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); 1689 result = WaitForSingleObject(semaphores[1], 0); 1690 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 1691 1692 /* test timeout of zero */ 1693 info.userdata = 0; 1694 when.QuadPart = 0; 1695 pTpSetWait(wait1, semaphores[1], &when); 1696 result = WaitForSingleObject(semaphores[0], 100); 1697 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1698 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata); 1699 result = WaitForSingleObject(semaphores[1], 0); 1700 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 1701 1702 /* cancel a pending wait */ 1703 info.userdata = 0; 1704 when.QuadPart = (ULONGLONG)250 * -10000; 1705 pTpSetWait(wait1, semaphores[1], &when); 1706 result = WaitForSingleObject(semaphores[0], 100); 1707 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 1708 pTpSetWait(wait1, NULL, (void *)0xdeadbeef); 1709 Sleep(50); 1710 ReleaseSemaphore(semaphores[1], 1, NULL); 1711 result = WaitForSingleObject(semaphores[0], 100); 1712 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 1713 ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata); 1714 result = WaitForSingleObject(semaphores[1], 0); 1715 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1716 1717 /* test with INVALID_HANDLE_VALUE */ 1718 info.userdata = 0; 1719 when.QuadPart = 0; 1720 pTpSetWait(wait1, INVALID_HANDLE_VALUE, &when); 1721 result = WaitForSingleObject(semaphores[0], 100); 1722 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1723 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata); 1724 1725 /* cancel a pending wait with INVALID_HANDLE_VALUE */ 1726 info.userdata = 0; 1727 when.QuadPart = (ULONGLONG)250 * -10000; 1728 pTpSetWait(wait1, semaphores[1], &when); 1729 result = WaitForSingleObject(semaphores[0], 100); 1730 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 1731 when.QuadPart = 0; 1732 pTpSetWait(wait1, INVALID_HANDLE_VALUE, &when); 1733 Sleep(50); 1734 ReleaseSemaphore(semaphores[1], 1, NULL); 1735 result = WaitForSingleObject(semaphores[0], 100); 1736 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1737 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata); 1738 result = WaitForSingleObject(semaphores[1], 0); 1739 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1740 1741 CloseHandle(semaphores[1]); 1742 semaphores[1] = CreateSemaphoreW(NULL, 0, 2, NULL); 1743 ok(semaphores[1] != NULL, "failed to create semaphore\n"); 1744 1745 /* add two wait objects with the same semaphore */ 1746 info.userdata = 0; 1747 pTpSetWait(wait1, semaphores[1], NULL); 1748 pTpSetWait(wait2, semaphores[1], NULL); 1749 Sleep(50); 1750 ReleaseSemaphore(semaphores[1], 1, NULL); 1751 result = WaitForSingleObject(semaphores[0], 100); 1752 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1753 result = WaitForSingleObject(semaphores[0], 100); 1754 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 1755 ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); 1756 result = WaitForSingleObject(semaphores[1], 0); 1757 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 1758 1759 /* repeat test above with release count 2 */ 1760 info.userdata = 0; 1761 pTpSetWait(wait1, semaphores[1], NULL); 1762 pTpSetWait(wait2, semaphores[1], NULL); 1763 Sleep(50); 1764 result = ReleaseSemaphore(semaphores[1], 2, NULL); 1765 result = WaitForSingleObject(semaphores[0], 100); 1766 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1767 result = WaitForSingleObject(semaphores[0], 100); 1768 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1769 ok(info.userdata == 2, "expected info.userdata = 2, got %u\n", info.userdata); 1770 result = WaitForSingleObject(semaphores[1], 0); 1771 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result); 1772 1773 /* cleanup */ 1774 pTpReleaseWait(wait1); 1775 pTpReleaseWait(wait2); 1776 pTpReleasePool(pool); 1777 CloseHandle(semaphores[0]); 1778 CloseHandle(semaphores[1]); 1779 } 1780 1781 static struct 1782 { 1783 HANDLE semaphore; 1784 DWORD result; 1785 } multi_wait_info; 1786 1787 static void CALLBACK multi_wait_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WAIT *wait, TP_WAIT_RESULT result) 1788 { 1789 DWORD index = (DWORD)(DWORD_PTR)userdata; 1790 1791 if (result == WAIT_OBJECT_0) 1792 multi_wait_info.result = index; 1793 else if (result == WAIT_TIMEOUT) 1794 multi_wait_info.result = 0x10000 | index; 1795 else 1796 ok(0, "unexpected result %u\n", result); 1797 ReleaseSemaphore(multi_wait_info.semaphore, 1, NULL); 1798 } 1799 1800 static void test_tp_multi_wait(void) 1801 { 1802 TP_CALLBACK_ENVIRON environment; 1803 HANDLE semaphores[512]; 1804 TP_WAIT *waits[512]; 1805 LARGE_INTEGER when; 1806 HANDLE semaphore; 1807 NTSTATUS status; 1808 TP_POOL *pool; 1809 DWORD result; 1810 int i; 1811 1812 semaphore = CreateSemaphoreW(NULL, 0, 512, NULL); 1813 ok(semaphore != NULL, "failed to create semaphore\n"); 1814 multi_wait_info.semaphore = semaphore; 1815 1816 /* allocate new threadpool */ 1817 pool = NULL; 1818 status = pTpAllocPool(&pool, NULL); 1819 ok(!status, "TpAllocPool failed with status %x\n", status); 1820 ok(pool != NULL, "expected pool != NULL\n"); 1821 1822 memset(&environment, 0, sizeof(environment)); 1823 environment.Version = 1; 1824 environment.Pool = pool; 1825 1826 /* create semaphores and corresponding wait objects */ 1827 for (i = 0; i < sizeof(semaphores)/sizeof(semaphores[0]); i++) 1828 { 1829 semaphores[i] = CreateSemaphoreW(NULL, 0, 1, NULL); 1830 ok(semaphores[i] != NULL, "failed to create semaphore %i\n", i); 1831 1832 waits[i] = NULL; 1833 status = pTpAllocWait(&waits[i], multi_wait_cb, (void *)(DWORD_PTR)i, &environment); 1834 ok(!status, "TpAllocWait failed with status %x\n", status); 1835 ok(waits[i] != NULL, "expected waits[%d] != NULL\n", i); 1836 1837 pTpSetWait(waits[i], semaphores[i], NULL); 1838 } 1839 1840 /* release all semaphores and wait for callback */ 1841 for (i = 0; i < sizeof(semaphores)/sizeof(semaphores[0]); i++) 1842 { 1843 multi_wait_info.result = 0; 1844 ReleaseSemaphore(semaphores[i], 1, NULL); 1845 1846 result = WaitForSingleObject(semaphore, 100); 1847 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1848 ok(multi_wait_info.result == i, "expected result %d, got %u\n", i, multi_wait_info.result); 1849 1850 pTpSetWait(waits[i], semaphores[i], NULL); 1851 } 1852 1853 /* repeat the same test in reverse order */ 1854 for (i = sizeof(semaphores)/sizeof(semaphores[0]) - 1; i >= 0; i--) 1855 { 1856 multi_wait_info.result = 0; 1857 ReleaseSemaphore(semaphores[i], 1, NULL); 1858 1859 result = WaitForSingleObject(semaphore, 100); 1860 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1861 ok(multi_wait_info.result == i, "expected result %d, got %u\n", i, multi_wait_info.result); 1862 1863 pTpSetWait(waits[i], semaphores[i], NULL); 1864 } 1865 1866 /* test timeout of wait objects */ 1867 multi_wait_info.result = 0; 1868 for (i = 0; i < sizeof(semaphores)/sizeof(semaphores[0]); i++) 1869 { 1870 when.QuadPart = (ULONGLONG)50 * -10000; 1871 pTpSetWait(waits[i], semaphores[i], &when); 1872 } 1873 1874 for (i = 0; i < sizeof(semaphores)/sizeof(semaphores[0]); i++) 1875 { 1876 result = WaitForSingleObject(semaphore, 150); 1877 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); 1878 } 1879 1880 ok(multi_wait_info.result >> 16, "expected multi_wait_info.result >> 16 != 0\n"); 1881 1882 /* destroy the wait objects and semaphores while waiting */ 1883 for (i = 0; i < sizeof(semaphores)/sizeof(semaphores[0]); i++) 1884 { 1885 pTpSetWait(waits[i], semaphores[i], NULL); 1886 } 1887 1888 Sleep(50); 1889 1890 for (i = 0; i < sizeof(semaphores)/sizeof(semaphores[0]); i++) 1891 { 1892 pTpReleaseWait(waits[i]); 1893 NtClose(semaphores[i]); 1894 } 1895 1896 pTpReleasePool(pool); 1897 CloseHandle(semaphore); 1898 } 1899 1900 START_TEST(threadpool) 1901 { 1902 test_RtlQueueWorkItem(); 1903 test_RtlRegisterWait(); 1904 1905 if (!init_threadpool()) 1906 return; 1907 1908 test_tp_simple(); 1909 test_tp_work(); 1910 test_tp_work_scheduler(); 1911 test_tp_group_wait(); 1912 test_tp_group_cancel(); 1913 test_tp_instance(); 1914 test_tp_disassociate(); 1915 test_tp_timer(); 1916 test_tp_window_length(); 1917 test_tp_wait(); 1918 test_tp_multi_wait(); 1919 } 1920