2 * Unit test suite for thread pool functions
4 * Copyright 2015 Sebastian Lackner
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.
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.
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
21 #include "ntdll_test.h"
23 static HMODULE hntdll
= 0;
24 static NTSTATUS (WINAPI
*pTpAllocCleanupGroup
)(TP_CLEANUP_GROUP
**);
25 static NTSTATUS (WINAPI
*pTpAllocPool
)(TP_POOL
**,PVOID
);
26 static NTSTATUS (WINAPI
*pTpAllocTimer
)(TP_TIMER
**,PTP_TIMER_CALLBACK
,PVOID
,TP_CALLBACK_ENVIRON
*);
27 static NTSTATUS (WINAPI
*pTpAllocWait
)(TP_WAIT
**,PTP_WAIT_CALLBACK
,PVOID
,TP_CALLBACK_ENVIRON
*);
28 static NTSTATUS (WINAPI
*pTpAllocWork
)(TP_WORK
**,PTP_WORK_CALLBACK
,PVOID
,TP_CALLBACK_ENVIRON
*);
29 static NTSTATUS (WINAPI
*pTpCallbackMayRunLong
)(TP_CALLBACK_INSTANCE
*);
30 static VOID (WINAPI
*pTpCallbackReleaseSemaphoreOnCompletion
)(TP_CALLBACK_INSTANCE
*,HANDLE
,DWORD
);
31 static VOID (WINAPI
*pTpDisassociateCallback
)(TP_CALLBACK_INSTANCE
*);
32 static BOOL (WINAPI
*pTpIsTimerSet
)(TP_TIMER
*);
33 static VOID (WINAPI
*pTpReleaseWait
)(TP_WAIT
*);
34 static VOID (WINAPI
*pTpPostWork
)(TP_WORK
*);
35 static VOID (WINAPI
*pTpReleaseCleanupGroup
)(TP_CLEANUP_GROUP
*);
36 static VOID (WINAPI
*pTpReleaseCleanupGroupMembers
)(TP_CLEANUP_GROUP
*,BOOL
,PVOID
);
37 static VOID (WINAPI
*pTpReleasePool
)(TP_POOL
*);
38 static VOID (WINAPI
*pTpReleaseTimer
)(TP_TIMER
*);
39 static VOID (WINAPI
*pTpReleaseWork
)(TP_WORK
*);
40 static VOID (WINAPI
*pTpSetPoolMaxThreads
)(TP_POOL
*,DWORD
);
41 static VOID (WINAPI
*pTpSetTimer
)(TP_TIMER
*,LARGE_INTEGER
*,LONG
,LONG
);
42 static VOID (WINAPI
*pTpSetWait
)(TP_WAIT
*,HANDLE
,LARGE_INTEGER
*);
43 static NTSTATUS (WINAPI
*pTpSimpleTryPost
)(PTP_SIMPLE_CALLBACK
,PVOID
,TP_CALLBACK_ENVIRON
*);
44 static VOID (WINAPI
*pTpWaitForTimer
)(TP_TIMER
*,BOOL
);
45 static VOID (WINAPI
*pTpWaitForWait
)(TP_WAIT
*,BOOL
);
46 static VOID (WINAPI
*pTpWaitForWork
)(TP_WORK
*,BOOL
);
48 #define NTDLL_GET_PROC(func) \
51 p ## func = (void *)GetProcAddress(hntdll, #func); \
52 if (!p ## func) trace("Failed to get address for %s\n", #func); \
56 static BOOL
init_threadpool(void)
58 hntdll
= GetModuleHandleA("ntdll");
61 win_skip("Could not load ntdll\n");
65 NTDLL_GET_PROC(TpAllocCleanupGroup
);
66 NTDLL_GET_PROC(TpAllocPool
);
67 NTDLL_GET_PROC(TpAllocTimer
);
68 NTDLL_GET_PROC(TpAllocWait
);
69 NTDLL_GET_PROC(TpAllocWork
);
70 NTDLL_GET_PROC(TpCallbackMayRunLong
);
71 NTDLL_GET_PROC(TpCallbackReleaseSemaphoreOnCompletion
);
72 NTDLL_GET_PROC(TpDisassociateCallback
);
73 NTDLL_GET_PROC(TpIsTimerSet
);
74 NTDLL_GET_PROC(TpPostWork
);
75 NTDLL_GET_PROC(TpReleaseCleanupGroup
);
76 NTDLL_GET_PROC(TpReleaseCleanupGroupMembers
);
77 NTDLL_GET_PROC(TpReleasePool
);
78 NTDLL_GET_PROC(TpReleaseTimer
);
79 NTDLL_GET_PROC(TpReleaseWait
);
80 NTDLL_GET_PROC(TpReleaseWork
);
81 NTDLL_GET_PROC(TpSetPoolMaxThreads
);
82 NTDLL_GET_PROC(TpSetTimer
);
83 NTDLL_GET_PROC(TpSetWait
);
84 NTDLL_GET_PROC(TpSimpleTryPost
);
85 NTDLL_GET_PROC(TpWaitForTimer
);
86 NTDLL_GET_PROC(TpWaitForWait
);
87 NTDLL_GET_PROC(TpWaitForWork
);
91 win_skip("Threadpool functions not supported, skipping tests\n");
101 static void CALLBACK
simple_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
)
103 HANDLE semaphore
= userdata
;
104 trace("Running simple callback\n");
105 ReleaseSemaphore(semaphore
, 1, NULL
);
108 static void CALLBACK
simple2_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
)
110 trace("Running simple2 callback\n");
112 InterlockedIncrement((LONG
*)userdata
);
115 static void test_tp_simple(void)
117 TP_CALLBACK_ENVIRON environment
;
118 TP_CLEANUP_GROUP
*group
;
126 semaphore
= CreateSemaphoreA(NULL
, 0, 1, NULL
);
127 ok(semaphore
!= NULL
, "CreateSemaphoreA failed %u\n", GetLastError());
129 /* post the callback using the default threadpool */
130 memset(&environment
, 0, sizeof(environment
));
131 environment
.Version
= 1;
132 environment
.Pool
= NULL
;
133 status
= pTpSimpleTryPost(simple_cb
, semaphore
, &environment
);
134 ok(!status
, "TpSimpleTryPost failed with status %x\n", status
);
135 result
= WaitForSingleObject(semaphore
, 1000);
136 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
138 /* allocate new threadpool */
140 status
= pTpAllocPool(&pool
, NULL
);
141 ok(!status
, "TpAllocPool failed with status %x\n", status
);
142 ok(pool
!= NULL
, "expected pool != NULL\n");
144 /* post the callback using the new threadpool */
145 memset(&environment
, 0, sizeof(environment
));
146 environment
.Version
= 1;
147 environment
.Pool
= pool
;
148 status
= pTpSimpleTryPost(simple_cb
, semaphore
, &environment
);
149 ok(!status
, "TpSimpleTryPost failed with status %x\n", status
);
150 result
= WaitForSingleObject(semaphore
, 1000);
151 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
153 /* test with invalid version number */
154 memset(&environment
, 0, sizeof(environment
));
155 environment
.Version
= 9999;
156 environment
.Pool
= pool
;
157 status
= pTpSimpleTryPost(simple_cb
, semaphore
, &environment
);
159 ok(status
== STATUS_INVALID_PARAMETER
|| broken(!status
) /* Vista/2008 */,
160 "TpSimpleTryPost unexpectedly returned status %x\n", status
);
163 result
= WaitForSingleObject(semaphore
, 1000);
164 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
167 /* allocate a cleanup group for synchronization */
169 status
= pTpAllocCleanupGroup(&group
);
170 ok(!status
, "TpAllocCleanupGroup failed with status %x\n", status
);
171 ok(group
!= NULL
, "expected pool != NULL\n");
173 /* use cleanup group to wait for a simple callback */
175 memset(&environment
, 0, sizeof(environment
));
176 environment
.Version
= 1;
177 environment
.Pool
= pool
;
178 environment
.CleanupGroup
= group
;
179 status
= pTpSimpleTryPost(simple2_cb
, &userdata
, &environment
);
180 ok(!status
, "TpSimpleTryPost failed with status %x\n", status
);
181 pTpReleaseCleanupGroupMembers(group
, FALSE
, NULL
);
182 ok(userdata
== 1, "expected userdata = 1, got %u\n", userdata
);
184 /* test cancellation of pending simple callbacks */
186 memset(&environment
, 0, sizeof(environment
));
187 environment
.Version
= 1;
188 environment
.Pool
= pool
;
189 environment
.CleanupGroup
= group
;
190 for (i
= 0; i
< 100; i
++)
192 status
= pTpSimpleTryPost(simple2_cb
, &userdata
, &environment
);
193 ok(!status
, "TpSimpleTryPost failed with status %x\n", status
);
195 pTpReleaseCleanupGroupMembers(group
, TRUE
, NULL
);
196 ok(userdata
< 100, "expected userdata < 100, got %u\n", userdata
);
199 pTpReleaseCleanupGroup(group
);
200 pTpReleasePool(pool
);
201 CloseHandle(semaphore
);
204 static void CALLBACK
work_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
, TP_WORK
*work
)
206 trace("Running work callback\n");
208 InterlockedIncrement((LONG
*)userdata
);
211 static void CALLBACK
work2_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
, TP_WORK
*work
)
213 trace("Running work2 callback\n");
215 InterlockedExchangeAdd((LONG
*)userdata
, 0x10000);
218 static void test_tp_work(void)
220 TP_CALLBACK_ENVIRON environment
;
227 /* allocate new threadpool */
229 status
= pTpAllocPool(&pool
, NULL
);
230 ok(!status
, "TpAllocPool failed with status %x\n", status
);
231 ok(pool
!= NULL
, "expected pool != NULL\n");
233 /* allocate new work item */
235 memset(&environment
, 0, sizeof(environment
));
236 environment
.Version
= 1;
237 environment
.Pool
= pool
;
238 status
= pTpAllocWork(&work
, work_cb
, &userdata
, &environment
);
239 ok(!status
, "TpAllocWork failed with status %x\n", status
);
240 ok(work
!= NULL
, "expected work != NULL\n");
242 /* post 10 identical work items at once */
244 for (i
= 0; i
< 10; i
++)
246 pTpWaitForWork(work
, FALSE
);
247 ok(userdata
== 10, "expected userdata = 10, got %u\n", userdata
);
249 /* add more tasks and cancel them immediately */
251 for (i
= 0; i
< 10; i
++)
253 pTpWaitForWork(work
, TRUE
);
254 ok(userdata
< 10, "expected userdata < 10, got %u\n", userdata
);
257 pTpReleaseWork(work
);
258 pTpReleasePool(pool
);
261 static void test_tp_work_scheduler(void)
263 TP_CALLBACK_ENVIRON environment
;
264 TP_CLEANUP_GROUP
*group
;
265 TP_WORK
*work
, *work2
;
271 /* allocate new threadpool */
273 status
= pTpAllocPool(&pool
, NULL
);
274 ok(!status
, "TpAllocPool failed with status %x\n", status
);
275 ok(pool
!= NULL
, "expected pool != NULL\n");
277 /* we limit the pool to a single thread */
278 pTpSetPoolMaxThreads(pool
, 1);
280 /* create a cleanup group */
282 status
= pTpAllocCleanupGroup(&group
);
283 ok(!status
, "TpAllocCleanupGroup failed with status %x\n", status
);
284 ok(group
!= NULL
, "expected pool != NULL\n");
286 /* the first work item has no cleanup group associated */
288 memset(&environment
, 0, sizeof(environment
));
289 environment
.Version
= 1;
290 environment
.Pool
= pool
;
291 status
= pTpAllocWork(&work
, work_cb
, &userdata
, &environment
);
292 ok(!status
, "TpAllocWork failed with status %x\n", status
);
293 ok(work
!= NULL
, "expected work != NULL\n");
295 /* allocate a second work item with a cleanup group */
297 memset(&environment
, 0, sizeof(environment
));
298 environment
.Version
= 1;
299 environment
.Pool
= pool
;
300 environment
.CleanupGroup
= group
;
301 status
= pTpAllocWork(&work2
, work2_cb
, &userdata
, &environment
);
302 ok(!status
, "TpAllocWork failed with status %x\n", status
);
303 ok(work2
!= NULL
, "expected work2 != NULL\n");
305 /* the 'work' callbacks are not blocking execution of 'work2' callbacks */
307 for (i
= 0; i
< 10; i
++)
309 for (i
= 0; i
< 10; i
++)
312 pTpWaitForWork(work
, TRUE
);
313 pTpWaitForWork(work2
, TRUE
);
314 ok(userdata
& 0xffff, "expected userdata & 0xffff != 0, got %u\n", userdata
& 0xffff);
315 ok(userdata
>> 16, "expected userdata >> 16 != 0, got %u\n", userdata
>> 16);
317 /* test TpReleaseCleanupGroupMembers on a work item */
319 for (i
= 0; i
< 100; i
++)
321 for (i
= 0; i
< 10; i
++)
323 pTpReleaseCleanupGroupMembers(group
, FALSE
, NULL
);
324 pTpWaitForWork(work
, TRUE
);
325 ok((userdata
& 0xffff) < 100, "expected userdata & 0xffff < 100, got %u\n", userdata
& 0xffff);
326 ok((userdata
>> 16) == 10, "expected userdata >> 16 == 10, got %u\n", userdata
>> 16);
329 pTpReleaseWork(work
);
330 pTpReleaseCleanupGroup(group
);
331 pTpReleasePool(pool
);
334 static DWORD group_cancel_tid
;
336 static void CALLBACK
group_cancel_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
)
338 HANDLE
*semaphores
= userdata
;
342 trace("Running group cancel callback\n");
344 status
= pTpCallbackMayRunLong(instance
);
345 ok(status
== STATUS_TOO_MANY_THREADS
|| broken(status
== 1) /* Win Vista / 2008 */,
346 "expected STATUS_TOO_MANY_THREADS, got %08x\n", status
);
348 result
= WaitForSingleObject(semaphores
[0], 1000);
349 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
350 ReleaseSemaphore(semaphores
[1], 1, NULL
);
353 static void CALLBACK
group_cancel_cleanup_release_cb(void *object
, void *userdata
)
355 HANDLE
*semaphores
= userdata
;
356 trace("Running group cancel cleanup release callback\n");
357 group_cancel_tid
= GetCurrentThreadId();
358 ReleaseSemaphore(semaphores
[0], 1, NULL
);
361 static void CALLBACK
group_cancel_cleanup_increment_cb(void *object
, void *userdata
)
363 trace("Running group cancel cleanup increment callback\n");
364 group_cancel_tid
= GetCurrentThreadId();
365 InterlockedIncrement((LONG
*)userdata
);
368 static void CALLBACK
unexpected_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
)
370 ok(0, "Unexpected callback\n");
373 static void test_tp_group_cancel(void)
375 TP_CALLBACK_ENVIRON environment
;
376 TP_CLEANUP_GROUP
*group
;
377 LONG userdata
, userdata2
;
378 HANDLE semaphores
[2];
385 semaphores
[0] = CreateSemaphoreA(NULL
, 0, 1, NULL
);
386 ok(semaphores
[0] != NULL
, "CreateSemaphoreA failed %u\n", GetLastError());
387 semaphores
[1] = CreateSemaphoreA(NULL
, 0, 1, NULL
);
388 ok(semaphores
[1] != NULL
, "CreateSemaphoreA failed %u\n", GetLastError());
390 /* allocate new threadpool with only one thread */
392 status
= pTpAllocPool(&pool
, NULL
);
393 ok(!status
, "TpAllocPool failed with status %x\n", status
);
394 ok(pool
!= NULL
, "expected pool != NULL\n");
395 pTpSetPoolMaxThreads(pool
, 1);
397 /* allocate a cleanup group */
399 status
= pTpAllocCleanupGroup(&group
);
400 ok(!status
, "TpAllocCleanupGroup failed with status %x\n", status
);
401 ok(group
!= NULL
, "expected pool != NULL\n");
403 /* test execution of cancellation callback */
404 memset(&environment
, 0, sizeof(environment
));
405 environment
.Version
= 1;
406 environment
.Pool
= pool
;
407 status
= pTpSimpleTryPost(group_cancel_cb
, semaphores
, &environment
);
408 ok(!status
, "TpSimpleTryPost failed with status %x\n", status
);
410 memset(&environment
, 0, sizeof(environment
));
411 environment
.Version
= 1;
412 environment
.Pool
= pool
;
413 environment
.CleanupGroup
= group
;
414 environment
.CleanupGroupCancelCallback
= group_cancel_cleanup_release_cb
;
415 status
= pTpSimpleTryPost(unexpected_cb
, NULL
, &environment
);
416 ok(!status
, "TpSimpleTryPost failed with status %x\n", status
);
418 group_cancel_tid
= 0xdeadbeef;
419 pTpReleaseCleanupGroupMembers(group
, TRUE
, semaphores
);
420 result
= WaitForSingleObject(semaphores
[1], 1000);
421 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
422 ok(group_cancel_tid
== GetCurrentThreadId(), "expected tid %x, got %x\n",
423 GetCurrentThreadId(), group_cancel_tid
);
425 /* test cancellation callback for objects with multiple instances */
427 memset(&environment
, 0, sizeof(environment
));
428 environment
.Version
= 1;
429 environment
.Pool
= pool
;
430 environment
.CleanupGroup
= group
;
431 environment
.CleanupGroupCancelCallback
= group_cancel_cleanup_increment_cb
;
432 status
= pTpAllocWork(&work
, work_cb
, &userdata
, &environment
);
433 ok(!status
, "TpAllocWork failed with status %x\n", status
);
434 ok(work
!= NULL
, "expected work != NULL\n");
436 /* post 10 identical work items at once */
437 userdata
= userdata2
= 0;
438 for (i
= 0; i
< 10; i
++)
441 /* check if we get multiple cancellation callbacks */
442 group_cancel_tid
= 0xdeadbeef;
443 pTpReleaseCleanupGroupMembers(group
, TRUE
, &userdata2
);
444 ok(userdata
<= 8, "expected userdata <= 8, got %u\n", userdata
);
445 ok(userdata2
== 1, "expected only one cancellation callback, got %u\n", userdata2
);
446 ok(group_cancel_tid
== GetCurrentThreadId(), "expected tid %x, got %x\n",
447 GetCurrentThreadId(), group_cancel_tid
);
450 pTpReleaseCleanupGroup(group
);
451 pTpReleasePool(pool
);
452 CloseHandle(semaphores
[0]);
453 CloseHandle(semaphores
[1]);
456 static void CALLBACK
instance_semaphore_completion_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
)
458 HANDLE
*semaphores
= userdata
;
459 trace("Running instance completion callback\n");
460 pTpCallbackReleaseSemaphoreOnCompletion(instance
, semaphores
[0], 1);
463 static void CALLBACK
instance_finalization_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
)
465 HANDLE
*semaphores
= userdata
;
468 trace("Running instance finalization callback\n");
470 result
= WaitForSingleObject(semaphores
[0], 100);
471 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
472 ReleaseSemaphore(semaphores
[1], 1, NULL
);
475 static void test_tp_instance(void)
477 TP_CALLBACK_ENVIRON environment
;
478 HANDLE semaphores
[2];
483 semaphores
[0] = CreateSemaphoreW(NULL
, 0, 1, NULL
);
484 ok(semaphores
[0] != NULL
, "failed to create semaphore\n");
485 semaphores
[1] = CreateSemaphoreW(NULL
, 0, 1, NULL
);
486 ok(semaphores
[1] != NULL
, "failed to create semaphore\n");
488 /* allocate new threadpool */
490 status
= pTpAllocPool(&pool
, NULL
);
491 ok(!status
, "TpAllocPool failed with status %x\n", status
);
492 ok(pool
!= NULL
, "expected pool != NULL\n");
494 /* test for TpCallbackReleaseSemaphoreOnCompletion */
495 memset(&environment
, 0, sizeof(environment
));
496 environment
.Version
= 1;
497 environment
.Pool
= pool
;
498 status
= pTpSimpleTryPost(instance_semaphore_completion_cb
, semaphores
, &environment
);
499 ok(!status
, "TpSimpleTryPost failed with status %x\n", status
);
500 result
= WaitForSingleObject(semaphores
[0], 1000);
501 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
503 /* test for finalization callback */
504 memset(&environment
, 0, sizeof(environment
));
505 environment
.Version
= 1;
506 environment
.Pool
= pool
;
507 environment
.FinalizationCallback
= instance_finalization_cb
;
508 status
= pTpSimpleTryPost(instance_semaphore_completion_cb
, semaphores
, &environment
);
509 ok(!status
, "TpSimpleTryPost failed with status %x\n", status
);
510 result
= WaitForSingleObject(semaphores
[0], 1000);
511 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
512 result
= WaitForSingleObject(semaphores
[1], 1000);
513 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
516 pTpReleasePool(pool
);
517 CloseHandle(semaphores
[0]);
518 CloseHandle(semaphores
[1]);
521 static void CALLBACK
disassociate_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
, TP_WORK
*work
)
523 HANDLE
*semaphores
= userdata
;
526 trace("Running disassociate callback\n");
528 pTpDisassociateCallback(instance
);
529 result
= WaitForSingleObject(semaphores
[0], 1000);
530 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
531 ReleaseSemaphore(semaphores
[1], 1, NULL
);
534 static void CALLBACK
disassociate2_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
, TP_WORK
*work
)
536 HANDLE
*semaphores
= userdata
;
539 trace("Running disassociate2 callback\n");
541 pTpDisassociateCallback(instance
);
542 result
= WaitForSingleObject(semaphores
[0], 100);
543 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
544 ReleaseSemaphore(semaphores
[1], 1, NULL
);
547 static void CALLBACK
disassociate3_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
)
549 HANDLE
*semaphores
= userdata
;
552 trace("Running disassociate3 callback\n");
554 pTpDisassociateCallback(instance
);
555 result
= WaitForSingleObject(semaphores
[0], 100);
556 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
557 ReleaseSemaphore(semaphores
[1], 1, NULL
);
560 static void test_tp_disassociate(void)
562 TP_CALLBACK_ENVIRON environment
;
563 TP_CLEANUP_GROUP
*group
;
564 HANDLE semaphores
[2];
570 semaphores
[0] = CreateSemaphoreW(NULL
, 0, 1, NULL
);
571 ok(semaphores
[0] != NULL
, "failed to create semaphore\n");
572 semaphores
[1] = CreateSemaphoreW(NULL
, 0, 1, NULL
);
573 ok(semaphores
[1] != NULL
, "failed to create semaphore\n");
575 /* allocate new threadpool and cleanup group */
577 status
= pTpAllocPool(&pool
, NULL
);
578 ok(!status
, "TpAllocPool failed with status %x\n", status
);
579 ok(pool
!= NULL
, "expected pool != NULL\n");
582 status
= pTpAllocCleanupGroup(&group
);
583 ok(!status
, "TpAllocCleanupGroup failed with status %x\n", status
);
584 ok(group
!= NULL
, "expected pool != NULL\n");
586 /* test TpDisassociateCallback on work objects without group */
588 memset(&environment
, 0, sizeof(environment
));
589 environment
.Version
= 1;
590 environment
.Pool
= pool
;
591 status
= pTpAllocWork(&work
, disassociate_cb
, semaphores
, &environment
);
592 ok(!status
, "TpAllocWork failed with status %x\n", status
);
593 ok(work
!= NULL
, "expected work != NULL\n");
596 pTpWaitForWork(work
, FALSE
);
598 result
= WaitForSingleObject(semaphores
[1], 100);
599 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
600 ReleaseSemaphore(semaphores
[0], 1, NULL
);
601 result
= WaitForSingleObject(semaphores
[1], 1000);
602 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
603 pTpReleaseWork(work
);
605 /* test TpDisassociateCallback on work objects with group (1) */
607 memset(&environment
, 0, sizeof(environment
));
608 environment
.Version
= 1;
609 environment
.Pool
= pool
;
610 environment
.CleanupGroup
= group
;
611 status
= pTpAllocWork(&work
, disassociate_cb
, semaphores
, &environment
);
612 ok(!status
, "TpAllocWork failed with status %x\n", status
);
613 ok(work
!= NULL
, "expected work != NULL\n");
616 pTpWaitForWork(work
, FALSE
);
618 result
= WaitForSingleObject(semaphores
[1], 100);
619 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
620 ReleaseSemaphore(semaphores
[0], 1, NULL
);
621 result
= WaitForSingleObject(semaphores
[1], 1000);
622 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
623 pTpReleaseCleanupGroupMembers(group
, FALSE
, NULL
);
625 /* test TpDisassociateCallback on work objects with group (2) */
627 memset(&environment
, 0, sizeof(environment
));
628 environment
.Version
= 1;
629 environment
.Pool
= pool
;
630 environment
.CleanupGroup
= group
;
631 status
= pTpAllocWork(&work
, disassociate2_cb
, semaphores
, &environment
);
632 ok(!status
, "TpAllocWork failed with status %x\n", status
);
633 ok(work
!= NULL
, "expected work != NULL\n");
636 pTpReleaseCleanupGroupMembers(group
, FALSE
, NULL
);
638 ReleaseSemaphore(semaphores
[0], 1, NULL
);
639 result
= WaitForSingleObject(semaphores
[1], 1000);
640 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
641 result
= WaitForSingleObject(semaphores
[0], 1000);
642 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
644 /* test TpDisassociateCallback on simple callbacks */
645 memset(&environment
, 0, sizeof(environment
));
646 environment
.Version
= 1;
647 environment
.Pool
= pool
;
648 environment
.CleanupGroup
= group
;
649 status
= pTpSimpleTryPost(disassociate3_cb
, semaphores
, &environment
);
650 ok(!status
, "TpSimpleTryPost failed with status %x\n", status
);
652 pTpReleaseCleanupGroupMembers(group
, FALSE
, NULL
);
654 ReleaseSemaphore(semaphores
[0], 1, NULL
);
655 result
= WaitForSingleObject(semaphores
[1], 1000);
656 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
657 result
= WaitForSingleObject(semaphores
[0], 1000);
658 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
661 pTpReleaseCleanupGroup(group
);
662 pTpReleasePool(pool
);
663 CloseHandle(semaphores
[0]);
664 CloseHandle(semaphores
[1]);
667 static void CALLBACK
timer_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
, TP_TIMER
*timer
)
669 HANDLE semaphore
= userdata
;
670 trace("Running timer callback\n");
671 ReleaseSemaphore(semaphore
, 1, NULL
);
674 static void test_tp_timer(void)
676 TP_CALLBACK_ENVIRON environment
;
686 semaphore
= CreateSemaphoreA(NULL
, 0, 1, NULL
);
687 ok(semaphore
!= NULL
, "CreateSemaphoreA failed %u\n", GetLastError());
689 /* allocate new threadpool */
691 status
= pTpAllocPool(&pool
, NULL
);
692 ok(!status
, "TpAllocPool failed with status %x\n", status
);
693 ok(pool
!= NULL
, "expected pool != NULL\n");
695 /* allocate new timer */
697 memset(&environment
, 0, sizeof(environment
));
698 environment
.Version
= 1;
699 environment
.Pool
= pool
;
700 status
= pTpAllocTimer(&timer
, timer_cb
, semaphore
, &environment
);
701 ok(!status
, "TpAllocTimer failed with status %x\n", status
);
702 ok(timer
!= NULL
, "expected timer != NULL\n");
704 success
= pTpIsTimerSet(timer
);
705 ok(!success
, "TpIsTimerSet returned TRUE\n");
707 /* test timer with a relative timeout */
708 when
.QuadPart
= (ULONGLONG
)200 * -10000;
709 pTpSetTimer(timer
, &when
, 0, 0);
710 success
= pTpIsTimerSet(timer
);
711 ok(success
, "TpIsTimerSet returned FALSE\n");
713 pTpWaitForTimer(timer
, FALSE
);
715 result
= WaitForSingleObject(semaphore
, 100);
716 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
717 result
= WaitForSingleObject(semaphore
, 200);
718 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
719 success
= pTpIsTimerSet(timer
);
720 ok(success
, "TpIsTimerSet returned FALSE\n");
722 /* test timer with an absolute timeout */
723 NtQuerySystemTime( &when
);
724 when
.QuadPart
+= (ULONGLONG
)200 * 10000;
725 pTpSetTimer(timer
, &when
, 0, 0);
726 success
= pTpIsTimerSet(timer
);
727 ok(success
, "TpIsTimerSet returned FALSE\n");
729 pTpWaitForTimer(timer
, FALSE
);
731 result
= WaitForSingleObject(semaphore
, 100);
732 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
733 result
= WaitForSingleObject(semaphore
, 200);
734 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
735 success
= pTpIsTimerSet(timer
);
736 ok(success
, "TpIsTimerSet returned FALSE\n");
738 /* test timer with zero timeout */
740 pTpSetTimer(timer
, &when
, 0, 0);
741 success
= pTpIsTimerSet(timer
);
742 ok(success
, "TpIsTimerSet returned FALSE\n");
744 pTpWaitForTimer(timer
, FALSE
);
746 result
= WaitForSingleObject(semaphore
, 50);
747 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
748 success
= pTpIsTimerSet(timer
);
749 ok(success
, "TpIsTimerSet returned FALSE\n");
751 /* unset the timer */
752 pTpSetTimer(timer
, NULL
, 0, 0);
753 success
= pTpIsTimerSet(timer
);
754 ok(!success
, "TpIsTimerSet returned TRUE\n");
755 pTpWaitForTimer(timer
, TRUE
);
757 pTpReleaseTimer(timer
);
758 CloseHandle(semaphore
);
760 semaphore
= CreateSemaphoreA(NULL
, 0, 3, NULL
);
761 ok(semaphore
!= NULL
, "CreateSemaphoreA failed %u\n", GetLastError());
763 /* allocate a new timer */
765 memset(&environment
, 0, sizeof(environment
));
766 environment
.Version
= 1;
767 environment
.Pool
= pool
;
768 status
= pTpAllocTimer(&timer
, timer_cb
, semaphore
, &environment
);
769 ok(!status
, "TpAllocTimer failed with status %x\n", status
);
770 ok(timer
!= NULL
, "expected timer != NULL\n");
772 /* test a relative timeout repeated periodically */
773 when
.QuadPart
= (ULONGLONG
)200 * -10000;
774 pTpSetTimer(timer
, &when
, 200, 0);
775 success
= pTpIsTimerSet(timer
);
776 ok(success
, "TpIsTimerSet returned FALSE\n");
778 /* wait until the timer was triggered three times */
779 ticks
= GetTickCount();
780 for (i
= 0; i
< 3; i
++)
782 result
= WaitForSingleObject(semaphore
, 1000);
783 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
785 ticks
= GetTickCount() - ticks
;
786 ok(ticks
>= 500 && (ticks
<= 700 || broken(ticks
<= 750)) /* Win 7 */,
787 "expected approximately 600 ticks, got %u\n", ticks
);
789 /* unset the timer */
790 pTpSetTimer(timer
, NULL
, 0, 0);
791 success
= pTpIsTimerSet(timer
);
792 ok(!success
, "TpIsTimerSet returned TRUE\n");
793 pTpWaitForTimer(timer
, TRUE
);
796 pTpReleaseTimer(timer
);
797 pTpReleasePool(pool
);
798 CloseHandle(semaphore
);
801 struct window_length_info
807 static void CALLBACK
window_length_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
, TP_TIMER
*timer
)
809 struct window_length_info
*info
= userdata
;
810 trace("Running window length callback\n");
811 info
->ticks
= GetTickCount();
812 ReleaseSemaphore(info
->semaphore
, 1, NULL
);
815 static void test_tp_window_length(void)
817 struct window_length_info info1
, info2
;
818 TP_CALLBACK_ENVIRON environment
;
819 TP_TIMER
*timer1
, *timer2
;
826 semaphore
= CreateSemaphoreA(NULL
, 0, 2, NULL
);
827 ok(semaphore
!= NULL
, "CreateSemaphoreA failed %u\n", GetLastError());
829 /* allocate new threadpool */
831 status
= pTpAllocPool(&pool
, NULL
);
832 ok(!status
, "TpAllocPool failed with status %x\n", status
);
833 ok(pool
!= NULL
, "expected pool != NULL\n");
835 /* allocate two identical timers */
836 memset(&environment
, 0, sizeof(environment
));
837 environment
.Version
= 1;
838 environment
.Pool
= pool
;
841 info1
.semaphore
= semaphore
;
842 status
= pTpAllocTimer(&timer1
, window_length_cb
, &info1
, &environment
);
843 ok(!status
, "TpAllocTimer failed with status %x\n", status
);
844 ok(timer1
!= NULL
, "expected timer1 != NULL\n");
847 info2
.semaphore
= semaphore
;
848 status
= pTpAllocTimer(&timer2
, window_length_cb
, &info2
, &environment
);
849 ok(!status
, "TpAllocTimer failed with status %x\n", status
);
850 ok(timer2
!= NULL
, "expected timer2 != NULL\n");
852 /* choose parameters so that timers are not merged */
856 NtQuerySystemTime( &when
);
857 when
.QuadPart
+= (ULONGLONG
)250 * 10000;
858 pTpSetTimer(timer2
, &when
, 0, 0);
860 when
.QuadPart
-= (ULONGLONG
)150 * 10000;
861 pTpSetTimer(timer1
, &when
, 0, 75);
863 result
= WaitForSingleObject(semaphore
, 1000);
864 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
865 result
= WaitForSingleObject(semaphore
, 1000);
866 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
867 ok(info1
.ticks
!= 0 && info2
.ticks
!= 0, "expected that ticks are nonzero\n");
868 ok(info2
.ticks
>= info1
.ticks
+ 75 || broken(info2
.ticks
< info1
.ticks
+ 75) /* Win 2008 */,
869 "expected that timers are not merged\n");
871 /* timers will be merged */
875 NtQuerySystemTime( &when
);
876 when
.QuadPart
+= (ULONGLONG
)250 * 10000;
877 pTpSetTimer(timer2
, &when
, 0, 0);
879 when
.QuadPart
-= (ULONGLONG
)150 * 10000;
880 pTpSetTimer(timer1
, &when
, 0, 200);
882 result
= WaitForSingleObject(semaphore
, 1000);
883 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
884 result
= WaitForSingleObject(semaphore
, 1000);
885 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
886 ok(info1
.ticks
!= 0 && info2
.ticks
!= 0, "expected that ticks are nonzero\n");
887 ok(info2
.ticks
>= info1
.ticks
- 50 && info2
.ticks
<= info1
.ticks
+ 50,
888 "expected that timers are merged\n");
890 /* on Windows the timers also get merged in this case */
894 NtQuerySystemTime( &when
);
895 when
.QuadPart
+= (ULONGLONG
)100 * 10000;
896 pTpSetTimer(timer1
, &when
, 0, 200);
898 when
.QuadPart
+= (ULONGLONG
)150 * 10000;
899 pTpSetTimer(timer2
, &when
, 0, 0);
901 result
= WaitForSingleObject(semaphore
, 1000);
902 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
903 result
= WaitForSingleObject(semaphore
, 1000);
904 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
905 ok(info1
.ticks
!= 0 && info2
.ticks
!= 0, "expected that ticks are nonzero\n");
907 ok(info2
.ticks
>= info1
.ticks
- 50 && info2
.ticks
<= info1
.ticks
+ 50,
908 "expected that timers are merged\n");
911 pTpReleaseTimer(timer1
);
912 pTpReleaseTimer(timer2
);
913 pTpReleasePool(pool
);
914 CloseHandle(semaphore
);
923 static void CALLBACK
wait_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
,
924 TP_WAIT
*wait
, TP_WAIT_RESULT result
)
926 struct wait_info
*info
= userdata
;
927 trace("Running wait callback\n");
929 if (result
== WAIT_OBJECT_0
)
930 InterlockedIncrement(&info
->userdata
);
931 else if (result
== WAIT_TIMEOUT
)
932 InterlockedExchangeAdd(&info
->userdata
, 0x10000);
934 ok(0, "unexpected result %u\n", result
);
935 ReleaseSemaphore(info
->semaphore
, 1, NULL
);
938 static void test_tp_wait(void)
940 TP_CALLBACK_ENVIRON environment
;
941 TP_WAIT
*wait1
, *wait2
;
942 struct wait_info info
;
943 HANDLE semaphores
[2];
949 semaphores
[0] = CreateSemaphoreW(NULL
, 0, 2, NULL
);
950 ok(semaphores
[0] != NULL
, "failed to create semaphore\n");
951 semaphores
[1] = CreateSemaphoreW(NULL
, 0, 1, NULL
);
952 ok(semaphores
[1] != NULL
, "failed to create semaphore\n");
953 info
.semaphore
= semaphores
[0];
955 /* allocate new threadpool */
957 status
= pTpAllocPool(&pool
, NULL
);
958 ok(!status
, "TpAllocPool failed with status %x\n", status
);
959 ok(pool
!= NULL
, "expected pool != NULL\n");
961 /* allocate new wait items */
962 memset(&environment
, 0, sizeof(environment
));
963 environment
.Version
= 1;
964 environment
.Pool
= pool
;
967 status
= pTpAllocWait(&wait1
, wait_cb
, &info
, &environment
);
968 ok(!status
, "TpAllocWait failed with status %x\n", status
);
969 ok(wait1
!= NULL
, "expected wait1 != NULL\n");
972 status
= pTpAllocWait(&wait2
, wait_cb
, &info
, &environment
);
973 ok(!status
, "TpAllocWait failed with status %x\n", status
);
974 ok(wait2
!= NULL
, "expected wait2 != NULL\n");
976 /* infinite timeout, signal the semaphore immediately */
978 pTpSetWait(wait1
, semaphores
[1], NULL
);
979 ReleaseSemaphore(semaphores
[1], 1, NULL
);
980 result
= WaitForSingleObject(semaphores
[0], 100);
981 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
982 ok(info
.userdata
== 1, "expected info.userdata = 1, got %u\n", info
.userdata
);
983 result
= WaitForSingleObject(semaphores
[1], 0);
984 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
986 /* relative timeout, no event */
988 when
.QuadPart
= (ULONGLONG
)200 * -10000;
989 pTpSetWait(wait1
, semaphores
[1], &when
);
990 result
= WaitForSingleObject(semaphores
[0], 100);
991 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
992 ok(info
.userdata
== 0, "expected info.userdata = 0, got %u\n", info
.userdata
);
993 result
= WaitForSingleObject(semaphores
[0], 200);
994 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
995 ok(info
.userdata
== 0x10000, "expected info.userdata = 0x10000, got %u\n", info
.userdata
);
996 result
= WaitForSingleObject(semaphores
[1], 0);
997 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
999 /* repeat test with call to TpWaitForWait(..., TRUE) */
1001 when
.QuadPart
= (ULONGLONG
)200 * -10000;
1002 pTpSetWait(wait1
, semaphores
[1], &when
);
1003 result
= WaitForSingleObject(semaphores
[0], 100);
1004 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1005 pTpWaitForWait(wait1
, TRUE
);
1006 ok(info
.userdata
== 0, "expected info.userdata = 0, got %u\n", info
.userdata
);
1007 result
= WaitForSingleObject(semaphores
[0], 200);
1008 ok(result
== WAIT_OBJECT_0
|| broken(result
== WAIT_TIMEOUT
) /* Win 8 */,
1009 "WaitForSingleObject returned %u\n", result
);
1010 if (result
== WAIT_OBJECT_0
)
1011 ok(info
.userdata
== 0x10000, "expected info.userdata = 0x10000, got %u\n", info
.userdata
);
1013 ok(info
.userdata
== 0, "expected info.userdata = 0, got %u\n", info
.userdata
);
1014 result
= WaitForSingleObject(semaphores
[1], 0);
1015 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1017 /* relative timeout, with event */
1019 when
.QuadPart
= (ULONGLONG
)200 * -10000;
1020 pTpSetWait(wait1
, semaphores
[1], &when
);
1021 result
= WaitForSingleObject(semaphores
[0], 100);
1022 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1023 ok(info
.userdata
== 0, "expected info.userdata = 0, got %u\n", info
.userdata
);
1024 ReleaseSemaphore(semaphores
[1], 1, NULL
);
1025 result
= WaitForSingleObject(semaphores
[0], 100);
1026 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1027 ok(info
.userdata
== 1, "expected info.userdata = 1, got %u\n", info
.userdata
);
1028 result
= WaitForSingleObject(semaphores
[1], 0);
1029 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1031 /* repeat test with call to TpWaitForWait(..., TRUE) */
1033 when
.QuadPart
= (ULONGLONG
)200 * -10000;
1034 pTpSetWait(wait1
, semaphores
[1], &when
);
1035 result
= WaitForSingleObject(semaphores
[0], 100);
1036 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1037 pTpWaitForWait(wait1
, TRUE
);
1038 ok(info
.userdata
== 0, "expected info.userdata = 0, got %u\n", info
.userdata
);
1039 ReleaseSemaphore(semaphores
[1], 1, NULL
);
1040 result
= WaitForSingleObject(semaphores
[0], 100);
1041 ok(result
== WAIT_OBJECT_0
|| broken(result
== WAIT_TIMEOUT
) /* Win 8 */,
1042 "WaitForSingleObject returned %u\n", result
);
1043 if (result
== WAIT_OBJECT_0
)
1045 ok(info
.userdata
== 1, "expected info.userdata = 1, got %u\n", info
.userdata
);
1046 result
= WaitForSingleObject(semaphores
[1], 0);
1047 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1051 ok(info
.userdata
== 0, "expected info.userdata = 0, got %u\n", info
.userdata
);
1052 result
= WaitForSingleObject(semaphores
[1], 0);
1053 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1056 /* absolute timeout, no event */
1058 NtQuerySystemTime( &when
);
1059 when
.QuadPart
+= (ULONGLONG
)200 * 10000;
1060 pTpSetWait(wait1
, semaphores
[1], &when
);
1061 result
= WaitForSingleObject(semaphores
[0], 100);
1062 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1063 ok(info
.userdata
== 0, "expected info.userdata = 0, got %u\n", info
.userdata
);
1064 result
= WaitForSingleObject(semaphores
[0], 200);
1065 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1066 ok(info
.userdata
== 0x10000, "expected info.userdata = 0x10000, got %u\n", info
.userdata
);
1067 result
= WaitForSingleObject(semaphores
[1], 0);
1068 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1070 /* absolute timeout, with event */
1072 NtQuerySystemTime( &when
);
1073 when
.QuadPart
+= (ULONGLONG
)200 * 10000;
1074 pTpSetWait(wait1
, semaphores
[1], &when
);
1075 result
= WaitForSingleObject(semaphores
[0], 100);
1076 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1077 ok(info
.userdata
== 0, "expected info.userdata = 0, got %u\n", info
.userdata
);
1078 ReleaseSemaphore(semaphores
[1], 1, NULL
);
1079 result
= WaitForSingleObject(semaphores
[0], 100);
1080 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1081 ok(info
.userdata
== 1, "expected info.userdata = 1, got %u\n", info
.userdata
);
1082 result
= WaitForSingleObject(semaphores
[1], 0);
1083 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1085 /* test timeout of zero */
1088 pTpSetWait(wait1
, semaphores
[1], &when
);
1089 result
= WaitForSingleObject(semaphores
[0], 100);
1090 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1091 ok(info
.userdata
== 0x10000, "expected info.userdata = 0x10000, got %u\n", info
.userdata
);
1092 result
= WaitForSingleObject(semaphores
[1], 0);
1093 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1095 /* cancel a pending wait */
1097 when
.QuadPart
= (ULONGLONG
)250 * -10000;
1098 pTpSetWait(wait1
, semaphores
[1], &when
);
1099 result
= WaitForSingleObject(semaphores
[0], 100);
1100 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1101 pTpSetWait(wait1
, NULL
, (void *)0xdeadbeef);
1103 ReleaseSemaphore(semaphores
[1], 1, NULL
);
1104 result
= WaitForSingleObject(semaphores
[0], 100);
1105 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1106 ok(info
.userdata
== 0, "expected info.userdata = 0, got %u\n", info
.userdata
);
1107 result
= WaitForSingleObject(semaphores
[1], 0);
1108 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1110 /* test with INVALID_HANDLE_VALUE */
1113 pTpSetWait(wait1
, INVALID_HANDLE_VALUE
, &when
);
1114 result
= WaitForSingleObject(semaphores
[0], 100);
1115 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1116 ok(info
.userdata
== 0x10000, "expected info.userdata = 0x10000, got %u\n", info
.userdata
);
1118 /* cancel a pending wait with INVALID_HANDLE_VALUE */
1120 when
.QuadPart
= (ULONGLONG
)250 * -10000;
1121 pTpSetWait(wait1
, semaphores
[1], &when
);
1122 result
= WaitForSingleObject(semaphores
[0], 100);
1123 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1125 pTpSetWait(wait1
, INVALID_HANDLE_VALUE
, &when
);
1127 ReleaseSemaphore(semaphores
[1], 1, NULL
);
1128 result
= WaitForSingleObject(semaphores
[0], 100);
1129 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1130 ok(info
.userdata
== 0x10000, "expected info.userdata = 0x10000, got %u\n", info
.userdata
);
1131 result
= WaitForSingleObject(semaphores
[1], 0);
1132 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1134 CloseHandle(semaphores
[1]);
1135 semaphores
[1] = CreateSemaphoreW(NULL
, 0, 2, NULL
);
1136 ok(semaphores
[1] != NULL
, "failed to create semaphore\n");
1138 /* add two wait objects with the same semaphore */
1140 pTpSetWait(wait1
, semaphores
[1], NULL
);
1141 pTpSetWait(wait2
, semaphores
[1], NULL
);
1143 ReleaseSemaphore(semaphores
[1], 1, NULL
);
1144 result
= WaitForSingleObject(semaphores
[0], 100);
1145 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1146 result
= WaitForSingleObject(semaphores
[0], 100);
1147 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1148 ok(info
.userdata
== 1, "expected info.userdata = 1, got %u\n", info
.userdata
);
1149 result
= WaitForSingleObject(semaphores
[1], 0);
1150 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1152 /* repeat test above with release count 2 */
1154 pTpSetWait(wait1
, semaphores
[1], NULL
);
1155 pTpSetWait(wait2
, semaphores
[1], NULL
);
1157 result
= ReleaseSemaphore(semaphores
[1], 2, NULL
);
1158 result
= WaitForSingleObject(semaphores
[0], 100);
1159 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1160 result
= WaitForSingleObject(semaphores
[0], 100);
1161 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1162 ok(info
.userdata
== 2, "expected info.userdata = 2, got %u\n", info
.userdata
);
1163 result
= WaitForSingleObject(semaphores
[1], 0);
1164 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1167 pTpReleaseWait(wait1
);
1168 pTpReleaseWait(wait2
);
1169 pTpReleasePool(pool
);
1170 CloseHandle(semaphores
[0]);
1171 CloseHandle(semaphores
[1]);
1174 START_TEST(threadpool
)
1176 if (!init_threadpool())
1181 test_tp_work_scheduler();
1182 test_tp_group_cancel();
1184 test_tp_disassociate();
1186 test_tp_window_length();