ReactOS 0.4.16-dev-889-g9563c07
threadpool.c
Go to the documentation of this file.
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__
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);
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 *);
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
73{
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;
129 return 0;
130}
131
132static void test_RtlQueueWorkItem(void)
133{
137
139 ok(semaphore != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
140
142 ok(!status, "RtlQueueWorkItem failed with status %lx\n", status);
144 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
145
147 ok(!status, "RtlQueueWorkItem failed with status %lx\n", status);
149 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
150
152 ok(!status, "RtlQueueWorkItem failed with status %lx\n", status);
154 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
155
157 ok(!status, "RtlQueueWorkItem failed with status %lx\n", status);
159 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
160
162 ok(!status, "RtlQueueWorkItem failed with status %lx\n", status);
164 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
165
167}
168
170{
176};
177
178static void CALLBACK rtl_wait_cb(void *userdata, BOOLEAN timeout)
179{
180 struct rtl_wait_info *info = userdata;
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
199
201{
204}
205
206static void test_RtlRegisterWait(void)
207{
208 HANDLE wait1, event, thread;
209 struct rtl_wait_info info;
210 HANDLE semaphores[2];
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;
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;
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;
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;
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);
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;
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);
377 ok(thread != NULL, "OpenThread failed with %lu\n", GetLastError());
378 rtl_wait_apc_semaphore = semaphores[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);
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);
403 ok(thread != NULL, "OpenThread failed with %lu\n", GetLastError());
404 rtl_wait_apc_semaphore = semaphores[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);
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);
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);
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);
439 ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status);
440 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
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);
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);
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);
475 ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status);
476 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
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;
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;
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;
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);
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;
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);
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;
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);
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;
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);
558 ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %lx\n", status);
559 ReleaseSemaphore(semaphores[1], 1, NULL);
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]);
568}
569
571{
574}
575
577{
578 Sleep(50);
580}
581
582static void test_tp_simple(void)
583{
585 TP_POOL_STACK_INFORMATION stack_info;
586 TP_CALLBACK_ENVIRON environment;
587#ifndef __REACTOS__
588 TP_CALLBACK_ENVIRON_V3 environment3;
589#endif
593 TP_POOL *pool;
596 int i;
597
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);
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);
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 {
635 status = pTpSimpleTryPost(simple_cb, semaphore, (TP_CALLBACK_ENVIRON *)&environment3);
636 ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
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);
653 ok(status == STATUS_INVALID_PARAMETER || broken(!status) /* Vista/2008 */,
654 "TpSimpleTryPost unexpectedly returned status %lx\n", status);
655 if (!status)
656 {
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);
713}
714
716{
717 Sleep(100);
719}
720
722{
723 Sleep(100);
725}
726
727static void test_tp_work(void)
728{
729 TP_CALLBACK_ENVIRON environment;
730 TP_WORK *work;
731 TP_POOL *pool;
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;
775 TP_WORK *work, *work2;
776 TP_POOL *pool;
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
843{
844 HANDLE *semaphores = userdata;
845 ReleaseSemaphore(semaphores, 1, NULL);
846 Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */
847}
848
850{
853 Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */
854 pTpReleaseWork(work);
855}
856
858{
861 Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */
862 pTpReleaseTimer(timer);
863}
864
867{
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;
878 LARGE_INTEGER when;
881 TP_TIMER *timer;
882 TP_WAIT *wait;
883 TP_WORK *work;
884 TP_POOL *pool;
886
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);
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);
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);
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);
950}
951
953
955{
956 HANDLE *semaphores = userdata;
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
975{
976 HANDLE *semaphores = userdata;
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;
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;
996 ok(object == userdata, "expected %p, got %p\n", userdata, object);
997 ReleaseSemaphore(semaphores[0], 1, NULL);
998}
999
1001{
1004}
1005
1007{
1008 ok(0, "Unexpected callback\n");
1009}
1010
1012{
1013 ok(0, "Unexpected callback\n");
1014}
1015
1017{
1018 ok(0, "Unexpected callback\n");
1019}
1020
1023{
1024 ok(0, "Unexpected callback\n");
1025}
1026
1028{
1029 ok(0, "Unexpected callback\n");
1030}
1031
1032static void test_tp_group_cancel(void)
1033{
1034 TP_CALLBACK_ENVIRON environment;
1036 LONG userdata, userdata2;
1037 HANDLE semaphores[2];
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;
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",
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;
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",
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;
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;
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;
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",
1177
1178 /* cleanup */
1179 pTpReleaseCleanupGroup(group);
1180 pTpReleasePool(pool);
1181 CloseHandle(semaphores[0]);
1182 CloseHandle(semaphores[1]);
1183}
1184
1186{
1187 HANDLE *semaphores = userdata;
1188 pTpCallbackReleaseSemaphoreOnCompletion(instance, semaphores[0], 1);
1189}
1190
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];
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;
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
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
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
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;
1280 HANDLE semaphores[2];
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
1384{
1387}
1388
1389static void test_tp_timer(void)
1390{
1391 TP_CALLBACK_ENVIRON environment;
1392 DWORD result, ticks;
1393 LARGE_INTEGER when;
1396 TP_TIMER *timer;
1397 TP_POOL *pool;
1398 BOOL success;
1399 int i;
1400
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
1431 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
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
1447 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
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
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);
1474
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 {
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);
1514}
1515
1517{
1520};
1521
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;
1537 TP_POOL *pool;
1538 DWORD result;
1539 BOOL merged;
1540
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
1579 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
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
1598 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
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
1617 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
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);
1630}
1631
1633{
1636};
1637
1638static void CALLBACK wait_cb(TP_CALLBACK_INSTANCE *instance, void *userdata,
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;
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{
1892
1894{
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;
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
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
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 {
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);
2010}
2011
2013{
2014 unsigned int count;
2015 void *ovl;
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
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
2048 struct io_cb_ctx userdata;
2049 char in[1], in2[1];
2050 const char out[1];
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
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");
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);
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
2205 ok(ret, "Got unexpected ret %#x.\n", ret);
2206 pTpReleaseIoCompletion(io);
2208 ok(!ret, "Got unexpected ret %#x.\n", ret);
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);
2225 ok(ret, "Got unexpected ret %#x.\n", ret);
2226 pTpReleaseIoCompletion(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);
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);
2243 ok(!ret, "Got unexpected ret %#x.\n", ret);
2244 }
2245
2247 CloseHandle(ovl.hEvent);
2249 pTpReleasePool(pool);
2250}
2251
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
2272 struct io_cb_ctx userdata;
2273 char in[1], in2[1];
2274 const char out[1];
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
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");
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);
2395 pCloseThreadpoolIo(io);
2396 pTpReleasePool(pool);
2397}
2398
2400{
2403
2404 if (!init_threadpool())
2405 return;
2406
2408 test_tp_work();
2414 test_tp_timer();
2416 test_tp_wait();
2418 test_tp_io();
2420}
unsigned char BOOLEAN
#define VOID
Definition: acefi.h:82
#define InterlockedIncrement
Definition: armddk.h:53
#define ok(value,...)
Definition: atltest.h:57
#define broken(x)
Definition: atltest.h:178
#define START_TEST(x)
Definition: atltest.h:75
LONG NTSTATUS
Definition: precomp.h:26
#define index(s, c)
Definition: various.h:29
#define ARRAY_SIZE(A)
Definition: main.h:20
static HANDLE thread
Definition: service.c:33
#define STATUS_PENDING
Definition: d3dkmdt.h:43
#define WAIT_TIMEOUT
Definition: dderror.h:14
#define ERROR_IO_PENDING
Definition: dderror.h:15
#define ERROR_SUCCESS
Definition: deptool.c:10
BOOL WINAPI CancelIo(IN HANDLE hFile)
Definition: deviceio.c:290
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
static HINSTANCE instance
Definition: main.c:40
#define NTSTATUS
Definition: precomp.h:19
#define CloseHandle
Definition: compat.h:739
#define GetProcessHeap()
Definition: compat.h:736
#define OPEN_EXISTING
Definition: compat.h:775
#define ReadFile(a, b, c, d, e)
Definition: compat.h:742
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
#define CreateFileA(a, b, c, d, e, f, g)
Definition: compat.h:740
#define GENERIC_READ
Definition: compat.h:135
#define RtlImageNtHeader
Definition: compat.h:806
#define CALLBACK
Definition: compat.h:35
PPEB Peb
Definition: dllmain.c:27
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
HMODULE WINAPI DECLSPEC_HOTPATCH GetModuleHandleA(LPCSTR lpModuleName)
Definition: loader.c:812
DWORD WINAPI QueueUserAPC(IN PAPCFUNC pfnAPC, IN HANDLE hThread, IN ULONG_PTR dwData)
Definition: thread.c:959
HANDLE WINAPI OpenThread(IN DWORD dwDesiredAccess, IN BOOL bInheritHandle, IN DWORD dwThreadId)
Definition: thread.c:403
HANDLE WINAPI DECLSPEC_HOTPATCH CreateThread(IN LPSECURITY_ATTRIBUTES lpThreadAttributes, IN DWORD dwStackSize, IN LPTHREAD_START_ROUTINE lpStartAddress, IN LPVOID lpParameter, IN DWORD dwCreationFlags, OUT LPDWORD lpThreadId)
Definition: thread.c:137
DWORD WINAPI GetTickCount(VOID)
Definition: time.c:455
#define INFINITE
Definition: serial.h:102
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
struct _cl_event * event
Definition: glext.h:7739
GLuint index
Definition: glext.h:6031
GLuint in
Definition: glext.h:9616
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
GLboolean GLuint group
Definition: glext.h:11120
GLuint64EXT * result
Definition: glext.h:11304
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
BOOL WINAPI HeapValidate(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem)
Definition: heapmem.c:156
#define THREAD_SET_CONTEXT
#define InterlockedExchangeAdd
Definition: interlocked.h:181
#define NtCurrentTeb
#define FILE_FLAG_OVERLAPPED
Definition: disk.h:46
IMAGE_NT_HEADERS nt
Definition: module.c:50
#define todo_wine
Definition: custom.c:89
static HANDLE PIO_APC_ROUTINE PVOID PIO_STATUS_BLOCK io
Definition: file.c:100
static PIO_STATUS_BLOCK iosb
Definition: file.c:98
static void test_tp_io(void)
Definition: threadpool.c:2039
static void CALLBACK unexpected_group_cancel_cleanup_cb(void *object, void *userdata)
Definition: threadpool.c:1027
static DWORD WINAPI io_wait_thread(void *arg)
Definition: threadpool.c:2032
static void CALLBACK wait_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WAIT *wait, TP_WAIT_RESULT result)
Definition: threadpool.c:1638
static void CALLBACK simple_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
Definition: threadpool.c:570
static void CALLBACK disassociate2_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
Definition: threadpool.c:1254
HANDLE semaphore
Definition: threadpool.c:1889
static void CALLBACK work_group_cancel_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
Definition: threadpool.c:974
static void test_tp_work_scheduler(void)
Definition: threadpool.c:771
static void CALLBACK wait_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WAIT *wait, TP_WAIT_RESULT result)
Definition: threadpool.c:865
static void CALLBACK rtl_wait_apc_cb(ULONG_PTR userdata)
Definition: threadpool.c:200
static void test_tp_work(void)
Definition: threadpool.c:727
static void CALLBACK work_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
Definition: threadpool.c:715
static BOOL
Definition: threadpool.c:41
static void CALLBACK group_cancel_cleanup_release2_cb(void *object, void *userdata)
Definition: threadpool.c:992
static HANDLE
Definition: threadpool.c:28
static void test_tp_timer(void)
Definition: threadpool.c:1389
static void CALLBACK instance_semaphore_completion_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
Definition: threadpool.c:1185
static void CALLBACK io_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, void *cvalue, IO_STATUS_BLOCK *iosb, TP_IO *io)
Definition: threadpool.c:2021
static TP_CALLBACK_ENVIRON *static TP_CALLBACK_ENVIRON *static PTP_WORK_CALLBACK
Definition: threadpool.c:32
static void CALLBACK disassociate_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
Definition: threadpool.c:1243
static TP_POOL_STACK_INFORMATION *static LARGE_INTEGER LONG
Definition: threadpool.c:49
static void test_tp_group_cancel(void)
Definition: threadpool.c:1032
static void test_tp_window_length(void)
Definition: threadpool.c:1529
static DWORD CALLBACK rtl_work_cb(void *userdata)
Definition: threadpool.c:125
static PTP_TIMER_CALLBACK
Definition: threadpool.c:30
static void test_tp_wait(void)
Definition: threadpool.c:1651
DWORD result
Definition: threadpool.c:1890
static void CALLBACK timer_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer)
Definition: threadpool.c:1383
static void test_tp_disassociate(void)
Definition: threadpool.c:1276
static void CALLBACK work2_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
Definition: threadpool.c:721
static PTP_IO_CALLBACK
Definition: threadpool.c:28
static void CALLBACK simple_group_cancel_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
Definition: threadpool.c:954
static DWORD
Definition: threadpool.c:34
static void CALLBACK rtl_wait_cb(void *userdata, BOOLEAN timeout)
Definition: threadpool.c:178
static void test_kernel32_tp_io(void)
Definition: threadpool.c:2263
static DWORD group_cancel_tid
Definition: threadpool.c:952
static HANDLE rtl_wait_apc_semaphore
Definition: threadpool.c:198
static void CALLBACK unexpected_work_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
Definition: threadpool.c:1011
static void test_tp_group_wait(void)
Definition: threadpool.c:874
#define GET_PROC(func)
Definition: threadpool.c:64
static void test_tp_multi_wait(void)
Definition: threadpool.c:1906
static void CALLBACK work_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
Definition: threadpool.c:849
static void CALLBACK unexpected_timer_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer)
Definition: threadpool.c:1016
static void CALLBACK disassociate3_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
Definition: threadpool.c:1265
static void test_tp_instance(void)
Definition: threadpool.c:1197
static TP_CALLBACK_ENVIRON *static PTP_WAIT_CALLBACK
Definition: threadpool.c:31
static void CALLBACK group_cancel_cleanup_increment_cb(void *object, void *userdata)
Definition: threadpool.c:1000
static void CALLBACK kernel32_io_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, void *ovl, ULONG ret, ULONG_PTR length, TP_IO *io)
Definition: threadpool.c:2252
static void CALLBACK instance_finalization_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
Definition: threadpool.c:1191
static void CALLBACK simple2_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
Definition: threadpool.c:576
static void CALLBACK group_cancel_cleanup_release_cb(void *object, void *userdata)
Definition: threadpool.c:984
static void test_RtlRegisterWait(void)
Definition: threadpool.c:206
static BOOL init_threadpool(void)
Definition: threadpool.c:72
static void CALLBACK multi_wait_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WAIT *wait, TP_WAIT_RESULT result)
Definition: threadpool.c:1893
static void CALLBACK window_length_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer)
Definition: threadpool.c:1522
static void test_RtlQueueWorkItem(void)
Definition: threadpool.c:132
static void CALLBACK unexpected_simple_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
Definition: threadpool.c:1006
static TP_IO *WINAPI * pCreateThreadpoolIo(HANDLE, PTP_WIN32_IO_CALLBACK, void *, TP_CALLBACK_ENVIRON *)
static struct @1720 multi_wait_info
static void CALLBACK unexpected_wait_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WAIT *wait, TP_WAIT_RESULT result)
Definition: threadpool.c:1021
static void CALLBACK timer_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer)
Definition: threadpool.c:857
static void TP_CALLBACK_ENVIRON *static PVOID
Definition: threadpool.c:29
static void CALLBACK simple_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
Definition: threadpool.c:842
static void test_tp_simple(void)
Definition: threadpool.c:582
NTSYSAPI NTSTATUS NTAPI RtlQueueWorkItem(_In_ WORKERCALLBACKFUNC Function, _In_opt_ PVOID Context, _In_ ULONG Flags)
NTSYSAPI NTSTATUS NTAPI RtlRegisterWait(_In_ PHANDLE phNewWaitObject, _In_ HANDLE hObject, _In_ WAITORTIMERCALLBACKFUNC Callback, _In_ PVOID pvContext, _In_ ULONG ulMilliseconds, _In_ ULONG ulFlags)
NTSYSAPI NTSTATUS NTAPI RtlDeregisterWaitEx(_In_ HANDLE hWaitHandle, _In_opt_ HANDLE hCompletionEvent)
NTSYSAPI NTSTATUS NTAPI RtlDeregisterWait(_In_ HANDLE hWaitHandle)
HANDLE WINAPI CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances, DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
Definition: npipe.c:220
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3402
#define GENERIC_WRITE
Definition: nt_native.h:90
NTSTATUS NTAPI NtQuerySystemTime(OUT PLARGE_INTEGER SystemTime)
Definition: time.c:569
#define STATUS_TOO_MANY_THREADS
Definition: ntstatus.h:533
long LONG
Definition: pedump.c:60
#define win_skip
Definition: test.h:164
#define memset(x, y, z)
Definition: compat.h:39
VOID WINAPI TpReleaseCleanupGroupMembers(TP_CLEANUP_GROUP *group, BOOL cancel_pending, PVOID userdata)
Definition: threadpool.c:2921
VOID WINAPI TpReleaseTimer(TP_TIMER *timer)
Definition: threadpool.c:3030
VOID WINAPI TpReleasePool(TP_POOL *pool)
Definition: threadpool.c:3017
void WINAPI TpStartAsyncIoOperation(TP_IO *io)
Definition: threadpool.c:3276
VOID WINAPI TpDisassociateCallback(TP_CALLBACK_INSTANCE *instance)
Definition: threadpool.c:2853
NTSTATUS WINAPI TpAllocTimer(TP_TIMER **out, PTP_TIMER_CALLBACK callback, PVOID userdata, TP_CALLBACK_ENVIRON *environment)
Definition: threadpool.c:2604
VOID WINAPI TpSetTimer(TP_TIMER *timer, LARGE_INTEGER *timeout, LONG period, LONG window_length)
Definition: threadpool.c:3116
VOID WINAPI TpReleaseCleanupGroup(TP_CLEANUP_GROUP *group)
Definition: threadpool.c:2908
NTSTATUS WINAPI TpCallbackMayRunLong(TP_CALLBACK_INSTANCE *instance)
Definition: threadpool.c:2756
VOID WINAPI TpWaitForWork(TP_WORK *work, BOOL cancel_pending)
Definition: threadpool.c:3334
NTSTATUS WINAPI TpSimpleTryPost(PTP_SIMPLE_CALLBACK callback, PVOID userdata, TP_CALLBACK_ENVIRON *environment)
Definition: threadpool.c:3246
void WINAPI TpReleaseIoCompletion(TP_IO *io)
Definition: threadpool.c:2994
VOID WINAPI TpPostWork(TP_WORK *work)
Definition: threadpool.c:2896
NTSTATUS WINAPI TpAllocWork(TP_WORK **out, PTP_WORK_CALLBACK callback, PVOID userdata, TP_CALLBACK_ENVIRON *environment)
Definition: threadpool.c:2690
NTSTATUS WINAPI TpAllocCleanupGroup(TP_CLEANUP_GROUP **out)
Definition: threadpool.c:2537
NTSTATUS WINAPI TpAllocWait(TP_WAIT **out, PTP_WAIT_CALLBACK callback, PVOID userdata, TP_CALLBACK_ENVIRON *environment)
Definition: threadpool.c:2680
NTSTATUS WINAPI TpQueryPoolStackInformation(TP_POOL *pool, TP_POOL_STACK_INFORMATION *stack_info)
Definition: threadpool.c:3367
VOID WINAPI TpWaitForWait(TP_WAIT *wait, BOOL cancel_pending)
Definition: threadpool.c:3320
VOID WINAPI TpReleaseWork(TP_WORK *work)
Definition: threadpool.c:3058
VOID WINAPI TpWaitForTimer(TP_TIMER *timer, BOOL cancel_pending)
Definition: threadpool.c:3306
void WINAPI TpCancelAsyncIoOperation(TP_IO *io)
Definition: threadpool.c:2721
VOID WINAPI TpReleaseWait(TP_WAIT *wait)
Definition: threadpool.c:3044
VOID WINAPI TpSetWait(TP_WAIT *wait, HANDLE handle, LARGE_INTEGER *timeout)
Definition: threadpool.c:3194
BOOL WINAPI TpIsTimerSet(TP_TIMER *timer)
Definition: threadpool.c:2884
VOID WINAPI TpCallbackReleaseSemaphoreOnCompletion(TP_CALLBACK_INSTANCE *instance, HANDLE semaphore, DWORD count)
Definition: threadpool.c:2811
VOID WINAPI TpSetPoolMaxThreads(TP_POOL *pool, DWORD maximum)
Definition: threadpool.c:3072
NTSTATUS WINAPI TpAllocIoCompletion(TP_IO **out, HANDLE file, PTP_IO_CALLBACK callback, void *userdata, TP_CALLBACK_ENVIRON *environment)
Definition: threadpool.c:2547
NTSTATUS WINAPI TpSetPoolStackInformation(TP_POOL *pool, TP_POOL_STACK_INFORMATION *stack_info)
Definition: threadpool.c:3348
void WINAPI TpWaitForIoCompletion(TP_IO *io, BOOL cancel_pending)
Definition: threadpool.c:3292
NTSTATUS WINAPI TpAllocPool(TP_POOL **out, PVOID reserved)
Definition: threadpool.c:2591
static FILE * client
Definition: client.c:41
#define STATUS_SUCCESS
Definition: shellext.h:65
IMAGE_OPTIONAL_HEADER32 OptionalHeader
Definition: ntddk_ex.h:184
PVOID ImageBaseAddress
Definition: ntddk_ex.h:245
PTP_CLEANUP_GROUP CleanupGroup
Definition: winnt_old.h:4527
PTP_SIMPLE_CALLBACK FinalizationCallback
Definition: winnt_old.h:4531
TP_CALLBACK_PRIORITY CallbackPriority
Definition: winnt_old.h:4540
PTP_CLEANUP_GROUP_CANCEL_CALLBACK CleanupGroupCancelCallback
Definition: winnt_old.h:4528
void * ovl
Definition: threadpool.c:2015
ULONG_PTR length
Definition: threadpool.c:2017
TP_IO * io
Definition: threadpool.c:2018
unsigned int count
Definition: threadpool.c:2014
NTSTATUS ret
Definition: threadpool.c:2016
HANDLE semaphore1
Definition: threadpool.c:171
DWORD wait_result
Definition: threadpool.c:173
DWORD threadid
Definition: threadpool.c:174
HANDLE semaphore2
Definition: threadpool.c:172
Definition: ps.c:97
Definition: dhcpd.h:245
HANDLE semaphore
Definition: threadpool.c:1634
LONG userdata
Definition: threadpool.c:1635
DWORD WINAPI WaitForSingleObject(IN HANDLE hHandle, IN DWORD dwMilliseconds)
Definition: synch.c:82
VOID WINAPI DECLSPEC_HOTPATCH Sleep(IN DWORD dwMilliseconds)
Definition: synch.c:790
HANDLE WINAPI DECLSPEC_HOTPATCH CreateSemaphoreA(IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes OPTIONAL, IN LONG lInitialCount, IN LONG lMaximumCount, IN LPCSTR lpName OPTIONAL)
Definition: synch.c:430
HANDLE WINAPI DECLSPEC_HOTPATCH CreateEventW(IN LPSECURITY_ATTRIBUTES lpEventAttributes OPTIONAL, IN BOOL bManualReset, IN BOOL bInitialState, IN LPCWSTR lpName OPTIONAL)
Definition: synch.c:651
HANDLE WINAPI DECLSPEC_HOTPATCH CreateSemaphoreW(IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes OPTIONAL, IN LONG lInitialCount, IN LONG lMaximumCount, IN LPCWSTR lpName OPTIONAL)
Definition: synch.c:444
BOOL WINAPI DECLSPEC_HOTPATCH ReleaseSemaphore(IN HANDLE hSemaphore, IN LONG lReleaseCount, IN LPLONG lpPreviousCount)
Definition: synch.c:542
uint32_t DWORD_PTR
Definition: typedefs.h:65
uint32_t ULONG_PTR
Definition: typedefs.h:65
uint32_t ULONG
Definition: typedefs.h:59
uint64_t ULONGLONG
Definition: typedefs.h:67
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_CANCELLED
Definition: udferr_usr.h:170
LONGLONG QuadPart
Definition: typedefs.h:114
static rfbScreenInfoPtr server
Definition: vnc.c:74
wchar_t tm const _CrtWcstime_Writes_and_advances_ptr_ count wchar_t ** out
Definition: wcsftime.cpp:383
int ret
#define success(from, fromstr, to, tostr)
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define PIPE_ACCESS_DUPLEX
Definition: winbase.h:165
DWORD WINAPI GetCurrentThreadId(void)
Definition: thread.c:459
#define WAIT_OBJECT_0
Definition: winbase.h:432
VOID(NTAPI * PTP_WIN32_IO_CALLBACK)(PTP_CALLBACK_INSTANCE, PVOID, PVOID, ULONG, ULONG_PTR, PTP_IO)
Definition: winbase.h:4126
void * arg
Definition: msvc.h:10
#define WINAPI
Definition: msvc.h:6
#define ERROR_OPERATION_ABORTED
Definition: winerror.h:575
#define ERROR_NOACCESS
Definition: winerror.h:578
#define WT_TRANSFER_IMPERSONATION
Definition: winnt_old.h:1074
@ TP_CALLBACK_PRIORITY_HIGH
Definition: winnt_old.h:4489
struct _TP_CLEANUP_GROUP TP_CLEANUP_GROUP
Definition: winnt_old.h:4508
#define WT_EXECUTEINPERSISTENTTHREAD
Definition: winnt_old.h:1073
struct _TP_CALLBACK_INSTANCE * PTP_CALLBACK_INSTANCE
Definition: winnt_old.h:4480
#define WT_EXECUTEONLYONCE
Definition: winnt_old.h:1069
struct _TP_POOL TP_POOL
Definition: winnt_old.h:4478
#define WT_EXECUTEINIOTHREAD
Definition: winnt_old.h:1066
DWORD TP_WAIT_RESULT
Definition: winnt_old.h:4485
#define WT_EXECUTELONGFUNCTION
Definition: winnt_old.h:1070
#define WT_EXECUTEINWAITTHREAD
Definition: winnt_old.h:1068
struct _TP_WAIT TP_WAIT
Definition: winnt_old.h:4482
struct _TP_IO * PTP_IO
Definition: winnt_old.h:4483
struct _TP_WORK TP_WORK
Definition: winnt_old.h:4479
struct _TP_IO TP_IO
Definition: winnt_old.h:4483
struct _TP_TIMER TP_TIMER
Definition: winnt_old.h:4481
VOID(NTAPI * PTP_SIMPLE_CALLBACK)(_Inout_ PTP_CALLBACK_INSTANCE Instance, _Inout_opt_ PVOID Context)
Definition: winnt_old.h:4511
struct _TP_CALLBACK_INSTANCE TP_CALLBACK_INSTANCE
Definition: winnt_old.h:4480
#define WT_EXECUTEDEFAULT
Definition: winnt_old.h:1065