2 * Unit test suite for thread pool functions
4 * Copyright 2015-2016 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 DWORD CALLBACK
rtl_work_cb(void *userdata
)
103 HANDLE semaphore
= userdata
;
104 trace("Running rtl_work callback\n");
105 ReleaseSemaphore(semaphore
, 1, NULL
);
109 static void test_RtlQueueWorkItem(void)
115 semaphore
= CreateSemaphoreA(NULL
, 0, 1, NULL
);
116 ok(semaphore
!= NULL
, "CreateSemaphoreA failed %u\n", GetLastError());
118 status
= RtlQueueWorkItem(rtl_work_cb
, semaphore
, WT_EXECUTEDEFAULT
);
119 ok(!status
, "RtlQueueWorkItem failed with status %x\n", status
);
120 result
= WaitForSingleObject(semaphore
, 1000);
121 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
123 status
= RtlQueueWorkItem(rtl_work_cb
, semaphore
, WT_EXECUTEINIOTHREAD
);
124 ok(!status
, "RtlQueueWorkItem failed with status %x\n", status
);
125 result
= WaitForSingleObject(semaphore
, 1000);
126 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
128 status
= RtlQueueWorkItem(rtl_work_cb
, semaphore
, WT_EXECUTEINPERSISTENTTHREAD
);
129 ok(!status
, "RtlQueueWorkItem failed with status %x\n", status
);
130 result
= WaitForSingleObject(semaphore
, 1000);
131 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
133 status
= RtlQueueWorkItem(rtl_work_cb
, semaphore
, WT_EXECUTELONGFUNCTION
);
134 ok(!status
, "RtlQueueWorkItem failed with status %x\n", status
);
135 result
= WaitForSingleObject(semaphore
, 1000);
136 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
138 status
= RtlQueueWorkItem(rtl_work_cb
, semaphore
, WT_TRANSFER_IMPERSONATION
);
139 ok(!status
, "RtlQueueWorkItem failed with status %x\n", status
);
140 result
= WaitForSingleObject(semaphore
, 1000);
141 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
143 CloseHandle(semaphore
);
155 static void CALLBACK
rtl_wait_cb(void *userdata
, BOOLEAN timeout
)
157 struct rtl_wait_info
*info
= userdata
;
160 trace("Running rtl_wait callback\n");
163 InterlockedIncrement(&info
->userdata
);
165 InterlockedExchangeAdd(&info
->userdata
, 0x10000);
166 info
->threadid
= GetCurrentThreadId();
167 ReleaseSemaphore(info
->semaphore1
, 1, NULL
);
169 if (info
->semaphore2
)
171 result
= WaitForSingleObject(info
->semaphore2
, 200);
172 ok(result
== info
->wait_result
, "expected %u, got %u\n", info
->wait_result
, result
);
173 ReleaseSemaphore(info
->semaphore1
, 1, NULL
);
177 static HANDLE rtl_wait_apc_semaphore
;
179 static void CALLBACK
rtl_wait_apc_cb(ULONG_PTR userdata
)
181 trace("Running rtl_wait_apc callback\n");
182 if (rtl_wait_apc_semaphore
)
183 ReleaseSemaphore(rtl_wait_apc_semaphore
, 1, NULL
);
186 static void test_RtlRegisterWait(void)
188 HANDLE wait1
, event
, thread
;
189 struct rtl_wait_info info
;
190 HANDLE semaphores
[2];
194 semaphores
[0] = CreateSemaphoreW(NULL
, 0, 2, NULL
);
195 ok(semaphores
[0] != NULL
, "failed to create semaphore\n");
196 semaphores
[1] = CreateSemaphoreW(NULL
, 0, 1, NULL
);
197 ok(semaphores
[1] != NULL
, "failed to create semaphore\n");
198 info
.semaphore1
= semaphores
[0];
199 info
.semaphore2
= NULL
;
201 event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
202 ok(event
!= NULL
, "failed to create event\n");
204 /* basic test for RtlRegisterWait and RtlDeregisterWait */
207 status
= RtlRegisterWait(&wait1
, semaphores
[1], rtl_wait_cb
, &info
, INFINITE
, WT_EXECUTEDEFAULT
);
208 ok(!status
, "RtlRegisterWait failed with status %x\n", status
);
209 ok(wait1
!= NULL
, "expected wait1 != NULL\n");
210 status
= RtlDeregisterWait(wait1
);
211 ok(!status
, "RtlDeregisterWait failed with status %x\n", status
);
212 ok(info
.userdata
== 0, "expected info.userdata = 0, got %u\n", info
.userdata
);
214 /* infinite timeout, signal the semaphore two times */
216 status
= RtlRegisterWait(&wait1
, semaphores
[1], rtl_wait_cb
, &info
, INFINITE
, WT_EXECUTEDEFAULT
);
217 ok(!status
, "RtlRegisterWait failed with status %x\n", status
);
218 ReleaseSemaphore(semaphores
[1], 1, NULL
);
219 result
= WaitForSingleObject(semaphores
[0], 100);
220 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
221 ok(info
.userdata
== 1, "expected info.userdata = 1, got %u\n", info
.userdata
);
222 ReleaseSemaphore(semaphores
[1], 1, NULL
);
223 result
= WaitForSingleObject(semaphores
[0], 100);
224 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
225 ok(info
.userdata
== 2, "expected info.userdata = 2, got %u\n", info
.userdata
);
226 result
= WaitForSingleObject(semaphores
[1], 0);
227 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
229 status
= RtlDeregisterWait(wait1
);
230 ok(!status
, "RtlDeregisterWait failed with status %x\n", status
);
232 /* repeat test with WT_EXECUTEONLYONCE */
234 status
= RtlRegisterWait(&wait1
, semaphores
[1], rtl_wait_cb
, &info
, INFINITE
, WT_EXECUTEONLYONCE
);
235 ok(!status
, "RtlRegisterWait failed with status %x\n", status
);
236 ReleaseSemaphore(semaphores
[1], 1, NULL
);
237 result
= WaitForSingleObject(semaphores
[0], 100);
238 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
239 ok(info
.userdata
== 1, "expected info.userdata = 1, got %u\n", info
.userdata
);
240 ReleaseSemaphore(semaphores
[1], 1, NULL
);
241 result
= WaitForSingleObject(semaphores
[0], 100);
242 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
243 ok(info
.userdata
== 1, "expected info.userdata = 1, got %u\n", info
.userdata
);
244 result
= WaitForSingleObject(semaphores
[1], 0);
245 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
247 status
= RtlDeregisterWait(wait1
);
248 ok(!status
, "RtlDeregisterWait failed with status %x\n", status
);
250 /* finite timeout, no event */
252 status
= RtlRegisterWait(&wait1
, semaphores
[1], rtl_wait_cb
, &info
, 200, WT_EXECUTEDEFAULT
);
253 ok(!status
, "RtlRegisterWait failed with status %x\n", status
);
254 result
= WaitForSingleObject(semaphores
[0], 100);
255 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
256 ok(info
.userdata
== 0, "expected info.userdata = 0, got %u\n", info
.userdata
);
257 result
= WaitForSingleObject(semaphores
[0], 200);
258 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
259 ok(info
.userdata
== 0x10000, "expected info.userdata = 0x10000, got %u\n", info
.userdata
);
260 result
= WaitForSingleObject(semaphores
[1], 0);
261 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
263 status
= RtlDeregisterWait(wait1
);
264 ok(!status
, "RtlDeregisterWait failed with status %x\n", status
);
266 /* finite timeout, with event */
268 status
= RtlRegisterWait(&wait1
, semaphores
[1], rtl_wait_cb
, &info
, 200, WT_EXECUTEDEFAULT
);
269 ok(!status
, "RtlRegisterWait failed with status %x\n", status
);
270 result
= WaitForSingleObject(semaphores
[0], 100);
271 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
272 ok(info
.userdata
== 0, "expected info.userdata = 0, got %u\n", info
.userdata
);
273 ReleaseSemaphore(semaphores
[1], 1, NULL
);
274 result
= WaitForSingleObject(semaphores
[0], 100);
275 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
276 ok(info
.userdata
== 1, "expected info.userdata = 1, got %u\n", info
.userdata
);
277 result
= WaitForSingleObject(semaphores
[1], 0);
278 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
280 status
= RtlDeregisterWait(wait1
);
281 ok(!status
, "RtlDeregisterWait failed with status %x\n", status
);
283 /* test for IO threads */
286 status
= RtlRegisterWait(&wait1
, semaphores
[1], rtl_wait_cb
, &info
, INFINITE
, WT_EXECUTEINIOTHREAD
);
287 ok(!status
, "RtlRegisterWait failed with status %x\n", status
);
288 ReleaseSemaphore(semaphores
[1], 1, NULL
);
289 result
= WaitForSingleObject(semaphores
[0], 100);
290 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
291 ok(info
.userdata
== 1, "expected info.userdata = 1, got %u\n", info
.userdata
);
292 ok(info
.threadid
!= 0, "expected info.threadid != 0, got %u\n", info
.threadid
);
293 thread
= OpenThread(THREAD_SET_CONTEXT
, FALSE
, info
.threadid
);
294 ok(thread
!= NULL
, "OpenThread failed with %u\n", GetLastError());
295 rtl_wait_apc_semaphore
= semaphores
[0];
296 result
= QueueUserAPC(rtl_wait_apc_cb
, thread
, 0);
297 ok(result
!= 0, "QueueUserAPC failed with %u\n", GetLastError());
298 result
= WaitForSingleObject(semaphores
[0], 200);
299 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
300 rtl_wait_apc_semaphore
= 0;
302 ReleaseSemaphore(semaphores
[1], 1, NULL
);
303 result
= WaitForSingleObject(semaphores
[0], 100);
304 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
305 ok(info
.userdata
== 2, "expected info.userdata = 2, got %u\n", info
.userdata
);
307 status
= RtlDeregisterWait(wait1
);
308 ok(!status
, "RtlDeregisterWait failed with status %x\n", status
);
312 status
= RtlRegisterWait(&wait1
, semaphores
[1], rtl_wait_cb
, &info
, INFINITE
, WT_EXECUTEDEFAULT
);
313 ok(!status
, "RtlRegisterWait failed with status %x\n", status
);
314 ReleaseSemaphore(semaphores
[1], 1, NULL
);
315 result
= WaitForSingleObject(semaphores
[0], 100);
316 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
317 ok(info
.userdata
== 1, "expected info.userdata = 1, got %u\n", info
.userdata
);
318 ok(info
.threadid
!= 0, "expected info.threadid != 0, got %u\n", info
.threadid
);
319 thread
= OpenThread(THREAD_SET_CONTEXT
, FALSE
, info
.threadid
);
320 ok(thread
!= NULL
, "OpenThread failed with %u\n", GetLastError());
321 rtl_wait_apc_semaphore
= semaphores
[0];
322 result
= QueueUserAPC(rtl_wait_apc_cb
, thread
, 0);
323 ok(result
!= 0, "QueueUserAPC failed with %u\n", GetLastError());
324 result
= WaitForSingleObject(semaphores
[0], 200);
325 ok(result
== WAIT_TIMEOUT
|| broken(result
== WAIT_OBJECT_0
) /* >= Win Vista */,
326 "WaitForSingleObject returned %u\n", result
);
327 rtl_wait_apc_semaphore
= 0;
329 ReleaseSemaphore(semaphores
[1], 1, NULL
);
330 result
= WaitForSingleObject(semaphores
[0], 100);
331 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
332 ok(info
.userdata
== 2, "expected info.userdata = 2, got %u\n", info
.userdata
);
334 status
= RtlDeregisterWait(wait1
);
335 ok(!status
, "RtlDeregisterWait failed with status %x\n", status
);
337 /* test RtlDeregisterWaitEx before wait expired */
339 status
= RtlRegisterWait(&wait1
, semaphores
[1], rtl_wait_cb
, &info
, INFINITE
, WT_EXECUTEDEFAULT
);
340 ok(!status
, "RtlRegisterWait failed with status %x\n", status
);
341 status
= RtlDeregisterWaitEx(wait1
, NULL
);
342 ok(!status
, "RtlDeregisterWaitEx failed with status %x\n", status
);
343 ok(info
.userdata
== 0, "expected info.userdata = 0, got %u\n", info
.userdata
);
346 status
= RtlRegisterWait(&wait1
, semaphores
[1], rtl_wait_cb
, &info
, INFINITE
, WT_EXECUTEDEFAULT
);
347 ok(!status
, "RtlRegisterWait failed with status %x\n", status
);
348 status
= RtlDeregisterWaitEx(wait1
, INVALID_HANDLE_VALUE
);
349 ok(!status
, "RtlDeregisterWaitEx failed with status %x\n", status
);
350 ok(info
.userdata
== 0, "expected info.userdata = 0, got %u\n", info
.userdata
);
353 status
= RtlRegisterWait(&wait1
, semaphores
[1], rtl_wait_cb
, &info
, INFINITE
, WT_EXECUTEDEFAULT
);
354 ok(!status
, "RtlRegisterWait failed with status %x\n", status
);
355 status
= RtlDeregisterWaitEx(wait1
, event
);
356 ok(!status
, "RtlDeregisterWaitEx failed with status %x\n", status
);
357 ok(info
.userdata
== 0, "expected info.userdata = 0, got %u\n", info
.userdata
);
358 result
= WaitForSingleObject(event
, 200);
360 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
362 /* test RtlDeregisterWaitEx after wait expired */
364 status
= RtlRegisterWait(&wait1
, semaphores
[1], rtl_wait_cb
, &info
, 0, WT_EXECUTEONLYONCE
);
365 ok(!status
, "RtlRegisterWait failed with status %x\n", status
);
366 result
= WaitForSingleObject(semaphores
[0], 100);
367 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
368 ok(info
.userdata
== 0x10000, "expected info.userdata = 0x10000, got %u\n", info
.userdata
);
370 status
= RtlDeregisterWaitEx(wait1
, NULL
);
371 ok(!status
, "RtlDeregisterWaitEx failed with status %x\n", status
);
372 ok(info
.userdata
== 0x10000, "expected info.userdata = 0x10000, got %u\n", info
.userdata
);
375 status
= RtlRegisterWait(&wait1
, semaphores
[1], rtl_wait_cb
, &info
, 0, WT_EXECUTEONLYONCE
);
376 ok(!status
, "RtlRegisterWait failed with status %x\n", status
);
377 result
= WaitForSingleObject(semaphores
[0], 100);
378 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
379 ok(info
.userdata
== 0x10000, "expected info.userdata = 0x10000, got %u\n", info
.userdata
);
381 status
= RtlDeregisterWaitEx(wait1
, INVALID_HANDLE_VALUE
);
382 ok(!status
, "RtlDeregisterWaitEx failed with status %x\n", status
);
383 ok(info
.userdata
== 0x10000, "expected info.userdata = 0x10000, got %u\n", info
.userdata
);
386 status
= RtlRegisterWait(&wait1
, semaphores
[1], rtl_wait_cb
, &info
, 0, WT_EXECUTEONLYONCE
);
387 ok(!status
, "RtlRegisterWait failed with status %x\n", status
);
388 result
= WaitForSingleObject(semaphores
[0], 100);
389 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
390 ok(info
.userdata
== 0x10000, "expected info.userdata = 0x10000, got %u\n", info
.userdata
);
392 status
= RtlDeregisterWaitEx(wait1
, event
);
393 ok(!status
, "RtlDeregisterWaitEx failed with status %x\n", status
);
394 ok(info
.userdata
== 0x10000, "expected info.userdata = 0x10000, got %u\n", info
.userdata
);
395 result
= WaitForSingleObject(event
, 200);
397 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
399 /* test RtlDeregisterWaitEx while callback is running */
400 info
.semaphore2
= semaphores
[1];
401 info
.wait_result
= WAIT_OBJECT_0
;
404 status
= RtlRegisterWait(&wait1
, semaphores
[1], rtl_wait_cb
, &info
, INFINITE
, WT_EXECUTEONLYONCE
);
405 ok(!status
, "RtlRegisterWait failed with status %x\n", status
);
406 ReleaseSemaphore(semaphores
[1], 1, NULL
);
407 result
= WaitForSingleObject(semaphores
[0], 1000);
408 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
409 ok(info
.userdata
== 1, "expected info.userdata = 1, got %u\n", info
.userdata
);
410 status
= RtlDeregisterWait(wait1
);
411 ok(status
== STATUS_PENDING
, "expected STATUS_PENDING, got %x\n", status
);
412 ReleaseSemaphore(semaphores
[1], 1, NULL
);
413 result
= WaitForSingleObject(semaphores
[0], 1000);
414 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
417 status
= RtlRegisterWait(&wait1
, semaphores
[1], rtl_wait_cb
, &info
, INFINITE
, WT_EXECUTEONLYONCE
);
418 ok(!status
, "RtlRegisterWait failed with status %x\n", status
);
419 ReleaseSemaphore(semaphores
[1], 1, NULL
);
420 result
= WaitForSingleObject(semaphores
[0], 1000);
421 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
422 ok(info
.userdata
== 1, "expected info.userdata = 1, got %u\n", info
.userdata
);
423 status
= RtlDeregisterWaitEx(wait1
, NULL
);
424 ok(status
== STATUS_PENDING
, "expected STATUS_PENDING, got %x\n", status
);
425 ReleaseSemaphore(semaphores
[1], 1, NULL
);
426 result
= WaitForSingleObject(semaphores
[0], 1000);
427 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
429 info
.wait_result
= WAIT_TIMEOUT
;
431 status
= RtlRegisterWait(&wait1
, semaphores
[1], rtl_wait_cb
, &info
, INFINITE
, WT_EXECUTEONLYONCE
);
432 ok(!status
, "RtlRegisterWait failed with status %x\n", status
);
433 ReleaseSemaphore(semaphores
[1], 1, NULL
);
434 result
= WaitForSingleObject(semaphores
[0], 1000);
435 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
436 ok(info
.userdata
== 1, "expected info.userdata = 1, got %u\n", info
.userdata
);
437 status
= RtlDeregisterWaitEx(wait1
, INVALID_HANDLE_VALUE
);
438 ok(!status
, "RtlDeregisterWaitEx failed with status %x\n", status
);
439 result
= WaitForSingleObject(semaphores
[0], 0);
440 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
442 info
.wait_result
= WAIT_OBJECT_0
;
444 status
= RtlRegisterWait(&wait1
, semaphores
[1], rtl_wait_cb
, &info
, INFINITE
, WT_EXECUTEONLYONCE
);
445 ok(!status
, "RtlRegisterWait failed with status %x\n", status
);
446 ReleaseSemaphore(semaphores
[1], 1, NULL
);
447 result
= WaitForSingleObject(semaphores
[0], 1000);
448 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
449 ok(info
.userdata
== 1, "expected info.userdata = 1, got %u\n", info
.userdata
);
450 status
= RtlDeregisterWaitEx(wait1
, event
);
451 ok(status
== STATUS_PENDING
, "expected STATUS_PENDING, got %x\n", status
);
452 ReleaseSemaphore(semaphores
[1], 1, NULL
);
453 result
= WaitForSingleObject(event
, 1000);
454 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
455 result
= WaitForSingleObject(semaphores
[0], 0);
456 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
458 CloseHandle(semaphores
[0]);
459 CloseHandle(semaphores
[1]);
463 static void CALLBACK
simple_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
)
465 HANDLE semaphore
= userdata
;
466 trace("Running simple callback\n");
467 ReleaseSemaphore(semaphore
, 1, NULL
);
470 static void CALLBACK
simple2_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
)
472 trace("Running simple2 callback\n");
474 InterlockedIncrement((LONG
*)userdata
);
477 static void test_tp_simple(void)
479 TP_CALLBACK_ENVIRON environment
;
480 TP_CALLBACK_ENVIRON_V3 environment3
;
481 TP_CLEANUP_GROUP
*group
;
489 semaphore
= CreateSemaphoreA(NULL
, 0, 1, NULL
);
490 ok(semaphore
!= NULL
, "CreateSemaphoreA failed %u\n", GetLastError());
492 /* post the callback using the default threadpool */
493 memset(&environment
, 0, sizeof(environment
));
494 environment
.Version
= 1;
495 environment
.Pool
= NULL
;
496 status
= pTpSimpleTryPost(simple_cb
, semaphore
, &environment
);
497 ok(!status
, "TpSimpleTryPost failed with status %x\n", status
);
498 result
= WaitForSingleObject(semaphore
, 1000);
499 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
501 /* allocate new threadpool */
503 status
= pTpAllocPool(&pool
, NULL
);
504 ok(!status
, "TpAllocPool failed with status %x\n", status
);
505 ok(pool
!= NULL
, "expected pool != NULL\n");
507 /* post the callback using the new threadpool */
508 memset(&environment
, 0, sizeof(environment
));
509 environment
.Version
= 1;
510 environment
.Pool
= pool
;
511 status
= pTpSimpleTryPost(simple_cb
, semaphore
, &environment
);
512 ok(!status
, "TpSimpleTryPost failed with status %x\n", status
);
513 result
= WaitForSingleObject(semaphore
, 1000);
514 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
516 /* test with environment version 3 */
517 memset(&environment3
, 0, sizeof(environment3
));
518 environment3
.Version
= 3;
519 environment3
.Pool
= pool
;
520 environment3
.CallbackPriority
= TP_CALLBACK_PRIORITY_NORMAL
;
521 environment3
.Size
= sizeof(environment3
);
522 status
= pTpSimpleTryPost(simple_cb
, semaphore
, (TP_CALLBACK_ENVIRON
*)&environment3
);
523 ok(!status
, "TpSimpleTryPost failed with status %x\n", status
);
524 result
= WaitForSingleObject(semaphore
, 1000);
525 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
527 /* test with invalid version number */
528 memset(&environment
, 0, sizeof(environment
));
529 environment
.Version
= 9999;
530 environment
.Pool
= pool
;
531 status
= pTpSimpleTryPost(simple_cb
, semaphore
, &environment
);
533 ok(status
== STATUS_INVALID_PARAMETER
|| broken(!status
) /* Vista/2008 */,
534 "TpSimpleTryPost unexpectedly returned status %x\n", status
);
537 result
= WaitForSingleObject(semaphore
, 1000);
538 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
541 /* allocate a cleanup group for synchronization */
543 status
= pTpAllocCleanupGroup(&group
);
544 ok(!status
, "TpAllocCleanupGroup failed with status %x\n", status
);
545 ok(group
!= NULL
, "expected pool != NULL\n");
547 /* use cleanup group to wait for a simple callback */
549 memset(&environment
, 0, sizeof(environment
));
550 environment
.Version
= 1;
551 environment
.Pool
= pool
;
552 environment
.CleanupGroup
= group
;
553 status
= pTpSimpleTryPost(simple2_cb
, &userdata
, &environment
);
554 ok(!status
, "TpSimpleTryPost failed with status %x\n", status
);
555 pTpReleaseCleanupGroupMembers(group
, FALSE
, NULL
);
556 ok(userdata
== 1, "expected userdata = 1, got %u\n", userdata
);
558 /* test cancellation of pending simple callbacks */
560 pTpSetPoolMaxThreads(pool
, 10);
561 memset(&environment
, 0, sizeof(environment
));
562 environment
.Version
= 1;
563 environment
.Pool
= pool
;
564 environment
.CleanupGroup
= group
;
565 for (i
= 0; i
< 100; i
++)
567 status
= pTpSimpleTryPost(simple2_cb
, &userdata
, &environment
);
568 ok(!status
, "TpSimpleTryPost failed with status %x\n", status
);
570 pTpReleaseCleanupGroupMembers(group
, TRUE
, NULL
);
571 ok(userdata
< 100, "expected userdata < 100, got %u\n", userdata
);
574 pTpReleaseCleanupGroup(group
);
575 pTpReleasePool(pool
);
576 CloseHandle(semaphore
);
579 static void CALLBACK
work_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
, TP_WORK
*work
)
581 trace("Running work callback\n");
583 InterlockedIncrement((LONG
*)userdata
);
586 static void CALLBACK
work2_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
, TP_WORK
*work
)
588 trace("Running work2 callback\n");
590 InterlockedExchangeAdd((LONG
*)userdata
, 0x10000);
593 static void test_tp_work(void)
595 TP_CALLBACK_ENVIRON environment
;
602 /* allocate new threadpool with only one thread */
604 status
= pTpAllocPool(&pool
, NULL
);
605 ok(!status
, "TpAllocPool failed with status %x\n", status
);
606 ok(pool
!= NULL
, "expected pool != NULL\n");
607 pTpSetPoolMaxThreads(pool
, 1);
609 /* allocate new work item */
611 memset(&environment
, 0, sizeof(environment
));
612 environment
.Version
= 1;
613 environment
.Pool
= pool
;
614 status
= pTpAllocWork(&work
, work_cb
, &userdata
, &environment
);
615 ok(!status
, "TpAllocWork failed with status %x\n", status
);
616 ok(work
!= NULL
, "expected work != NULL\n");
618 /* post 5 identical work items at once */
620 for (i
= 0; i
< 5; i
++)
622 pTpWaitForWork(work
, FALSE
);
623 ok(userdata
== 5, "expected userdata = 5, got %u\n", userdata
);
625 /* add more tasks and cancel them immediately */
627 for (i
= 0; i
< 10; i
++)
629 pTpWaitForWork(work
, TRUE
);
630 ok(userdata
< 10, "expected userdata < 10, got %u\n", userdata
);
633 pTpReleaseWork(work
);
634 pTpReleasePool(pool
);
637 static void test_tp_work_scheduler(void)
639 TP_CALLBACK_ENVIRON environment
;
640 TP_CLEANUP_GROUP
*group
;
641 TP_WORK
*work
, *work2
;
647 /* allocate new threadpool with only one thread */
649 status
= pTpAllocPool(&pool
, NULL
);
650 ok(!status
, "TpAllocPool failed with status %x\n", status
);
651 ok(pool
!= NULL
, "expected pool != NULL\n");
652 pTpSetPoolMaxThreads(pool
, 1);
654 /* create a cleanup group */
656 status
= pTpAllocCleanupGroup(&group
);
657 ok(!status
, "TpAllocCleanupGroup failed with status %x\n", status
);
658 ok(group
!= NULL
, "expected pool != NULL\n");
660 /* the first work item has no cleanup group associated */
662 memset(&environment
, 0, sizeof(environment
));
663 environment
.Version
= 1;
664 environment
.Pool
= pool
;
665 status
= pTpAllocWork(&work
, work_cb
, &userdata
, &environment
);
666 ok(!status
, "TpAllocWork failed with status %x\n", status
);
667 ok(work
!= NULL
, "expected work != NULL\n");
669 /* allocate a second work item with a cleanup group */
671 memset(&environment
, 0, sizeof(environment
));
672 environment
.Version
= 1;
673 environment
.Pool
= pool
;
674 environment
.CleanupGroup
= group
;
675 status
= pTpAllocWork(&work2
, work2_cb
, &userdata
, &environment
);
676 ok(!status
, "TpAllocWork failed with status %x\n", status
);
677 ok(work2
!= NULL
, "expected work2 != NULL\n");
679 /* the 'work' callbacks are not blocking execution of 'work2' callbacks */
681 for (i
= 0; i
< 10; i
++)
683 for (i
= 0; i
< 10; i
++)
686 pTpWaitForWork(work
, TRUE
);
687 pTpWaitForWork(work2
, TRUE
);
688 ok(userdata
& 0xffff, "expected userdata & 0xffff != 0, got %u\n", userdata
& 0xffff);
689 ok(userdata
>> 16, "expected userdata >> 16 != 0, got %u\n", userdata
>> 16);
691 /* test TpReleaseCleanupGroupMembers on a work item */
693 for (i
= 0; i
< 10; i
++)
695 for (i
= 0; i
< 3; i
++)
697 pTpReleaseCleanupGroupMembers(group
, FALSE
, NULL
);
698 pTpWaitForWork(work
, TRUE
);
699 ok((userdata
& 0xffff) < 10, "expected userdata & 0xffff < 10, got %u\n", userdata
& 0xffff);
700 ok((userdata
>> 16) == 3, "expected userdata >> 16 == 3, got %u\n", userdata
>> 16);
703 pTpReleaseWork(work
);
704 pTpReleaseCleanupGroup(group
);
705 pTpReleasePool(pool
);
708 static void CALLBACK
simple_release_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
)
710 HANDLE
*semaphores
= userdata
;
711 trace("Running simple release callback\n");
712 ReleaseSemaphore(semaphores
, 1, NULL
);
713 Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */
716 static void CALLBACK
work_release_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
, TP_WORK
*work
)
718 HANDLE semaphore
= userdata
;
719 trace("Running work release callback\n");
720 ReleaseSemaphore(semaphore
, 1, NULL
);
721 Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */
722 pTpReleaseWork(work
);
725 static void CALLBACK
timer_release_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
, TP_TIMER
*timer
)
727 HANDLE semaphore
= userdata
;
728 trace("Running timer release callback\n");
729 ReleaseSemaphore(semaphore
, 1, NULL
);
730 Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */
731 pTpReleaseTimer(timer
);
734 static void CALLBACK
wait_release_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
,
735 TP_WAIT
*wait
, TP_WAIT_RESULT result
)
737 HANDLE semaphore
= userdata
;
738 trace("Running wait release callback\n");
739 ReleaseSemaphore(semaphore
, 1, NULL
);
740 Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */
741 pTpReleaseWait(wait
);
744 static void test_tp_group_wait(void)
746 TP_CALLBACK_ENVIRON environment
;
747 TP_CLEANUP_GROUP
*group
;
757 semaphore
= CreateSemaphoreA(NULL
, 0, 1, NULL
);
758 ok(semaphore
!= NULL
, "CreateSemaphoreA failed %u\n", GetLastError());
760 /* allocate new threadpool */
762 status
= pTpAllocPool(&pool
, NULL
);
763 ok(!status
, "TpAllocPool failed with status %x\n", status
);
764 ok(pool
!= NULL
, "expected pool != NULL\n");
766 /* allocate a cleanup group */
768 status
= pTpAllocCleanupGroup(&group
);
769 ok(!status
, "TpAllocCleanupGroup failed with status %x\n", status
);
770 ok(group
!= NULL
, "expected pool != NULL\n");
772 /* release work object during TpReleaseCleanupGroupMembers */
774 memset(&environment
, 0, sizeof(environment
));
775 environment
.Version
= 1;
776 environment
.Pool
= pool
;
777 environment
.CleanupGroup
= group
;
778 status
= pTpAllocWork(&work
, work_release_cb
, semaphore
, &environment
);
779 ok(!status
, "TpAllocWork failed with status %x\n", status
);
780 ok(work
!= NULL
, "expected work != NULL\n");
782 result
= WaitForSingleObject(semaphore
, 1000);
783 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
784 pTpReleaseCleanupGroupMembers(group
, FALSE
, NULL
);
786 /* release timer object during TpReleaseCleanupGroupMembers */
788 memset(&environment
, 0, sizeof(environment
));
789 environment
.Version
= 1;
790 environment
.Pool
= pool
;
791 environment
.CleanupGroup
= group
;
792 status
= pTpAllocTimer(&timer
, timer_release_cb
, semaphore
, &environment
);
793 ok(!status
, "TpAllocTimer failed with status %x\n", status
);
794 ok(timer
!= NULL
, "expected timer != NULL\n");
796 pTpSetTimer(timer
, &when
, 0, 0);
797 result
= WaitForSingleObject(semaphore
, 1000);
798 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
799 pTpReleaseCleanupGroupMembers(group
, FALSE
, NULL
);
801 /* release wait object during TpReleaseCleanupGroupMembers */
803 memset(&environment
, 0, sizeof(environment
));
804 environment
.Version
= 1;
805 environment
.Pool
= pool
;
806 environment
.CleanupGroup
= group
;
807 status
= pTpAllocWait(&wait
, wait_release_cb
, semaphore
, &environment
);
808 ok(!status
, "TpAllocWait failed with status %x\n", status
);
809 ok(wait
!= NULL
, "expected wait != NULL\n");
811 pTpSetWait(wait
, INVALID_HANDLE_VALUE
, &when
);
812 result
= WaitForSingleObject(semaphore
, 1000);
813 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
814 pTpReleaseCleanupGroupMembers(group
, FALSE
, NULL
);
817 pTpReleaseCleanupGroup(group
);
818 pTpReleasePool(pool
);
819 CloseHandle(semaphore
);
822 static DWORD group_cancel_tid
;
824 static void CALLBACK
simple_group_cancel_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
)
826 HANDLE
*semaphores
= userdata
;
831 trace("Running simple group cancel callback\n");
833 status
= pTpCallbackMayRunLong(instance
);
834 ok(status
== STATUS_TOO_MANY_THREADS
|| broken(status
== 1) /* Win Vista / 2008 */,
835 "expected STATUS_TOO_MANY_THREADS, got %08x\n", status
);
837 ReleaseSemaphore(semaphores
[1], 1, NULL
);
838 for (i
= 0; i
< 4; i
++)
840 result
= WaitForSingleObject(semaphores
[0], 1000);
841 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
843 ReleaseSemaphore(semaphores
[1], 1, NULL
);
846 static void CALLBACK
work_group_cancel_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
, TP_WORK
*work
)
848 HANDLE
*semaphores
= userdata
;
851 trace("Running work group cancel callback\n");
853 ReleaseSemaphore(semaphores
[1], 1, NULL
);
854 result
= WaitForSingleObject(semaphores
[0], 200);
855 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
858 static void CALLBACK
group_cancel_cleanup_release_cb(void *object
, void *userdata
)
860 HANDLE
*semaphores
= userdata
;
861 trace("Running group cancel cleanup release callback\n");
862 group_cancel_tid
= GetCurrentThreadId();
863 ok(object
== (void *)0xdeadbeef, "expected 0xdeadbeef, got %p\n", object
);
864 ReleaseSemaphore(semaphores
[0], 1, NULL
);
867 static void CALLBACK
group_cancel_cleanup_release2_cb(void *object
, void *userdata
)
869 HANDLE
*semaphores
= userdata
;
870 trace("Running group cancel cleanup release2 callback\n");
871 group_cancel_tid
= GetCurrentThreadId();
872 ok(object
== userdata
, "expected %p, got %p\n", userdata
, object
);
873 ReleaseSemaphore(semaphores
[0], 1, NULL
);
876 static void CALLBACK
group_cancel_cleanup_increment_cb(void *object
, void *userdata
)
878 trace("Running group cancel cleanup increment callback\n");
879 group_cancel_tid
= GetCurrentThreadId();
880 InterlockedIncrement((LONG
*)userdata
);
883 static void CALLBACK
unexpected_simple_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
)
885 ok(0, "Unexpected callback\n");
888 static void CALLBACK
unexpected_work_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
, TP_WORK
*work
)
890 ok(0, "Unexpected callback\n");
893 static void CALLBACK
unexpected_timer_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
, TP_TIMER
*timer
)
895 ok(0, "Unexpected callback\n");
898 static void CALLBACK
unexpected_wait_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
,
899 TP_WAIT
*wait
, TP_WAIT_RESULT result
)
901 ok(0, "Unexpected callback\n");
904 static void CALLBACK
unexpected_group_cancel_cleanup_cb(void *object
, void *userdata
)
906 ok(0, "Unexpected callback\n");
909 static void test_tp_group_cancel(void)
911 TP_CALLBACK_ENVIRON environment
;
912 TP_CLEANUP_GROUP
*group
;
913 LONG userdata
, userdata2
;
914 HANDLE semaphores
[2];
923 semaphores
[0] = CreateSemaphoreA(NULL
, 0, 4, NULL
);
924 ok(semaphores
[0] != NULL
, "CreateSemaphoreA failed %u\n", GetLastError());
925 semaphores
[1] = CreateSemaphoreA(NULL
, 0, 1, NULL
);
926 ok(semaphores
[1] != NULL
, "CreateSemaphoreA failed %u\n", GetLastError());
928 /* allocate new threadpool with only one thread */
930 status
= pTpAllocPool(&pool
, NULL
);
931 ok(!status
, "TpAllocPool failed with status %x\n", status
);
932 ok(pool
!= NULL
, "expected pool != NULL\n");
933 pTpSetPoolMaxThreads(pool
, 1);
935 /* allocate a cleanup group */
937 status
= pTpAllocCleanupGroup(&group
);
938 ok(!status
, "TpAllocCleanupGroup failed with status %x\n", status
);
939 ok(group
!= NULL
, "expected pool != NULL\n");
941 /* test execution of cancellation callback */
942 memset(&environment
, 0, sizeof(environment
));
943 environment
.Version
= 1;
944 environment
.Pool
= pool
;
945 status
= pTpSimpleTryPost(simple_group_cancel_cb
, semaphores
, &environment
);
946 ok(!status
, "TpSimpleTryPost failed with status %x\n", status
);
947 result
= WaitForSingleObject(semaphores
[1], 1000);
948 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
950 memset(&environment
, 0, sizeof(environment
));
951 environment
.Version
= 1;
952 environment
.Pool
= pool
;
953 environment
.CleanupGroup
= group
;
954 environment
.CleanupGroupCancelCallback
= group_cancel_cleanup_release_cb
;
955 status
= pTpSimpleTryPost(unexpected_simple_cb
, (void *)0xdeadbeef, &environment
);
956 ok(!status
, "TpSimpleTryPost failed with status %x\n", status
);
959 status
= pTpAllocWork(&work
, unexpected_work_cb
, (void *)0xdeadbeef, &environment
);
960 ok(!status
, "TpAllocWork failed with status %x\n", status
);
961 ok(work
!= NULL
, "expected work != NULL\n");
964 status
= pTpAllocTimer(&timer
, unexpected_timer_cb
, (void *)0xdeadbeef, &environment
);
965 ok(!status
, "TpAllocTimer failed with status %x\n", status
);
966 ok(timer
!= NULL
, "expected timer != NULL\n");
969 status
= pTpAllocWait(&wait
, unexpected_wait_cb
, (void *)0xdeadbeef, &environment
);
970 ok(!status
, "TpAllocWait failed with status %x\n", status
);
971 ok(wait
!= NULL
, "expected wait != NULL\n");
973 group_cancel_tid
= 0xdeadbeef;
974 pTpReleaseCleanupGroupMembers(group
, TRUE
, semaphores
);
975 result
= WaitForSingleObject(semaphores
[1], 1000);
976 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
977 ok(group_cancel_tid
== GetCurrentThreadId(), "expected tid %x, got %x\n",
978 GetCurrentThreadId(), group_cancel_tid
);
980 /* test if cancellation callbacks are executed before or after wait */
982 memset(&environment
, 0, sizeof(environment
));
983 environment
.Version
= 1;
984 environment
.Pool
= pool
;
985 environment
.CleanupGroup
= group
;
986 environment
.CleanupGroupCancelCallback
= group_cancel_cleanup_release2_cb
;
987 status
= pTpAllocWork(&work
, work_group_cancel_cb
, semaphores
, &environment
);
988 ok(!status
, "TpAllocWork failed with status %x\n", status
);
989 ok(work
!= NULL
, "expected work != NULL\n");
993 result
= WaitForSingleObject(semaphores
[1], 1000);
994 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
996 group_cancel_tid
= 0xdeadbeef;
997 pTpReleaseCleanupGroupMembers(group
, TRUE
, semaphores
);
998 result
= WaitForSingleObject(semaphores
[0], 1000);
999 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1000 ok(group_cancel_tid
== GetCurrentThreadId(), "expected tid %x, got %x\n",
1001 GetCurrentThreadId(), group_cancel_tid
);
1003 /* group cancel callback is not executed if object is destroyed while waiting */
1005 memset(&environment
, 0, sizeof(environment
));
1006 environment
.Version
= 1;
1007 environment
.Pool
= pool
;
1008 environment
.CleanupGroup
= group
;
1009 environment
.CleanupGroupCancelCallback
= unexpected_group_cancel_cleanup_cb
;
1010 status
= pTpAllocWork(&work
, work_release_cb
, semaphores
[1], &environment
);
1011 ok(!status
, "TpAllocWork failed with status %x\n", status
);
1012 ok(work
!= NULL
, "expected work != NULL\n");
1015 result
= WaitForSingleObject(semaphores
[1], 1000);
1016 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1017 pTpReleaseCleanupGroupMembers(group
, TRUE
, NULL
);
1019 /* terminated simple callbacks should not trigger the group cancel callback */
1020 memset(&environment
, 0, sizeof(environment
));
1021 environment
.Version
= 1;
1022 environment
.Pool
= pool
;
1023 environment
.CleanupGroup
= group
;
1024 environment
.CleanupGroupCancelCallback
= unexpected_group_cancel_cleanup_cb
;
1025 status
= pTpSimpleTryPost(simple_release_cb
, semaphores
[1], &environment
);
1026 ok(!status
, "TpSimpleTryPost failed with status %x\n", status
);
1027 result
= WaitForSingleObject(semaphores
[1], 1000);
1028 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1029 pTpReleaseCleanupGroupMembers(group
, TRUE
, semaphores
);
1031 /* test cancellation callback for objects with multiple instances */
1033 memset(&environment
, 0, sizeof(environment
));
1034 environment
.Version
= 1;
1035 environment
.Pool
= pool
;
1036 environment
.CleanupGroup
= group
;
1037 environment
.CleanupGroupCancelCallback
= group_cancel_cleanup_increment_cb
;
1038 status
= pTpAllocWork(&work
, work_cb
, &userdata
, &environment
);
1039 ok(!status
, "TpAllocWork failed with status %x\n", status
);
1040 ok(work
!= NULL
, "expected work != NULL\n");
1042 /* post 10 identical work items at once */
1043 userdata
= userdata2
= 0;
1044 for (i
= 0; i
< 10; i
++)
1047 /* check if we get multiple cancellation callbacks */
1048 group_cancel_tid
= 0xdeadbeef;
1049 pTpReleaseCleanupGroupMembers(group
, TRUE
, &userdata2
);
1050 ok(userdata
<= 5, "expected userdata <= 5, got %u\n", userdata
);
1051 ok(userdata2
== 1, "expected only one cancellation callback, got %u\n", userdata2
);
1052 ok(group_cancel_tid
== GetCurrentThreadId(), "expected tid %x, got %x\n",
1053 GetCurrentThreadId(), group_cancel_tid
);
1056 pTpReleaseCleanupGroup(group
);
1057 pTpReleasePool(pool
);
1058 CloseHandle(semaphores
[0]);
1059 CloseHandle(semaphores
[1]);
1062 static void CALLBACK
instance_semaphore_completion_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
)
1064 HANDLE
*semaphores
= userdata
;
1065 trace("Running instance completion callback\n");
1066 pTpCallbackReleaseSemaphoreOnCompletion(instance
, semaphores
[0], 1);
1069 static void CALLBACK
instance_finalization_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
)
1071 HANDLE
*semaphores
= userdata
;
1074 trace("Running instance finalization callback\n");
1076 result
= WaitForSingleObject(semaphores
[0], 100);
1077 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1078 ReleaseSemaphore(semaphores
[1], 1, NULL
);
1081 static void test_tp_instance(void)
1083 TP_CALLBACK_ENVIRON environment
;
1084 HANDLE semaphores
[2];
1089 semaphores
[0] = CreateSemaphoreW(NULL
, 0, 1, NULL
);
1090 ok(semaphores
[0] != NULL
, "failed to create semaphore\n");
1091 semaphores
[1] = CreateSemaphoreW(NULL
, 0, 1, NULL
);
1092 ok(semaphores
[1] != NULL
, "failed to create semaphore\n");
1094 /* allocate new threadpool */
1096 status
= pTpAllocPool(&pool
, NULL
);
1097 ok(!status
, "TpAllocPool failed with status %x\n", status
);
1098 ok(pool
!= NULL
, "expected pool != NULL\n");
1100 /* test for TpCallbackReleaseSemaphoreOnCompletion */
1101 memset(&environment
, 0, sizeof(environment
));
1102 environment
.Version
= 1;
1103 environment
.Pool
= pool
;
1104 status
= pTpSimpleTryPost(instance_semaphore_completion_cb
, semaphores
, &environment
);
1105 ok(!status
, "TpSimpleTryPost failed with status %x\n", status
);
1106 result
= WaitForSingleObject(semaphores
[0], 1000);
1107 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1109 /* test for finalization callback */
1110 memset(&environment
, 0, sizeof(environment
));
1111 environment
.Version
= 1;
1112 environment
.Pool
= pool
;
1113 environment
.FinalizationCallback
= instance_finalization_cb
;
1114 status
= pTpSimpleTryPost(instance_semaphore_completion_cb
, semaphores
, &environment
);
1115 ok(!status
, "TpSimpleTryPost failed with status %x\n", status
);
1116 result
= WaitForSingleObject(semaphores
[0], 1000);
1117 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1118 result
= WaitForSingleObject(semaphores
[1], 1000);
1119 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1122 pTpReleasePool(pool
);
1123 CloseHandle(semaphores
[0]);
1124 CloseHandle(semaphores
[1]);
1127 static void CALLBACK
disassociate_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
, TP_WORK
*work
)
1129 HANDLE
*semaphores
= userdata
;
1132 trace("Running disassociate callback\n");
1134 pTpDisassociateCallback(instance
);
1135 result
= WaitForSingleObject(semaphores
[0], 1000);
1136 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1137 ReleaseSemaphore(semaphores
[1], 1, NULL
);
1140 static void CALLBACK
disassociate2_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
, TP_WORK
*work
)
1142 HANDLE
*semaphores
= userdata
;
1145 trace("Running disassociate2 callback\n");
1147 pTpDisassociateCallback(instance
);
1148 result
= WaitForSingleObject(semaphores
[0], 100);
1149 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1150 ReleaseSemaphore(semaphores
[1], 1, NULL
);
1153 static void CALLBACK
disassociate3_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
)
1155 HANDLE
*semaphores
= userdata
;
1158 trace("Running disassociate3 callback\n");
1160 pTpDisassociateCallback(instance
);
1161 result
= WaitForSingleObject(semaphores
[0], 100);
1162 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1163 ReleaseSemaphore(semaphores
[1], 1, NULL
);
1166 static void test_tp_disassociate(void)
1168 TP_CALLBACK_ENVIRON environment
;
1169 TP_CLEANUP_GROUP
*group
;
1170 HANDLE semaphores
[2];
1176 semaphores
[0] = CreateSemaphoreW(NULL
, 0, 1, NULL
);
1177 ok(semaphores
[0] != NULL
, "failed to create semaphore\n");
1178 semaphores
[1] = CreateSemaphoreW(NULL
, 0, 1, NULL
);
1179 ok(semaphores
[1] != NULL
, "failed to create semaphore\n");
1181 /* allocate new threadpool and cleanup group */
1183 status
= pTpAllocPool(&pool
, NULL
);
1184 ok(!status
, "TpAllocPool failed with status %x\n", status
);
1185 ok(pool
!= NULL
, "expected pool != NULL\n");
1188 status
= pTpAllocCleanupGroup(&group
);
1189 ok(!status
, "TpAllocCleanupGroup failed with status %x\n", status
);
1190 ok(group
!= NULL
, "expected pool != NULL\n");
1192 /* test TpDisassociateCallback on work objects without group */
1194 memset(&environment
, 0, sizeof(environment
));
1195 environment
.Version
= 1;
1196 environment
.Pool
= pool
;
1197 status
= pTpAllocWork(&work
, disassociate_cb
, semaphores
, &environment
);
1198 ok(!status
, "TpAllocWork failed with status %x\n", status
);
1199 ok(work
!= NULL
, "expected work != NULL\n");
1202 pTpWaitForWork(work
, FALSE
);
1204 result
= WaitForSingleObject(semaphores
[1], 100);
1205 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1206 ReleaseSemaphore(semaphores
[0], 1, NULL
);
1207 result
= WaitForSingleObject(semaphores
[1], 1000);
1208 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1209 pTpReleaseWork(work
);
1211 /* test TpDisassociateCallback on work objects with group (1) */
1213 memset(&environment
, 0, sizeof(environment
));
1214 environment
.Version
= 1;
1215 environment
.Pool
= pool
;
1216 environment
.CleanupGroup
= group
;
1217 status
= pTpAllocWork(&work
, disassociate_cb
, semaphores
, &environment
);
1218 ok(!status
, "TpAllocWork failed with status %x\n", status
);
1219 ok(work
!= NULL
, "expected work != NULL\n");
1222 pTpWaitForWork(work
, FALSE
);
1224 result
= WaitForSingleObject(semaphores
[1], 100);
1225 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1226 ReleaseSemaphore(semaphores
[0], 1, NULL
);
1227 result
= WaitForSingleObject(semaphores
[1], 1000);
1228 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1229 pTpReleaseCleanupGroupMembers(group
, FALSE
, NULL
);
1231 /* test TpDisassociateCallback on work objects with group (2) */
1233 memset(&environment
, 0, sizeof(environment
));
1234 environment
.Version
= 1;
1235 environment
.Pool
= pool
;
1236 environment
.CleanupGroup
= group
;
1237 status
= pTpAllocWork(&work
, disassociate2_cb
, semaphores
, &environment
);
1238 ok(!status
, "TpAllocWork failed with status %x\n", status
);
1239 ok(work
!= NULL
, "expected work != NULL\n");
1242 pTpReleaseCleanupGroupMembers(group
, FALSE
, NULL
);
1244 ReleaseSemaphore(semaphores
[0], 1, NULL
);
1245 result
= WaitForSingleObject(semaphores
[1], 1000);
1246 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1247 result
= WaitForSingleObject(semaphores
[0], 1000);
1248 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1250 /* test TpDisassociateCallback on simple callbacks */
1251 memset(&environment
, 0, sizeof(environment
));
1252 environment
.Version
= 1;
1253 environment
.Pool
= pool
;
1254 environment
.CleanupGroup
= group
;
1255 status
= pTpSimpleTryPost(disassociate3_cb
, semaphores
, &environment
);
1256 ok(!status
, "TpSimpleTryPost failed with status %x\n", status
);
1258 pTpReleaseCleanupGroupMembers(group
, FALSE
, NULL
);
1260 ReleaseSemaphore(semaphores
[0], 1, NULL
);
1261 result
= WaitForSingleObject(semaphores
[1], 1000);
1262 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1263 result
= WaitForSingleObject(semaphores
[0], 1000);
1264 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1267 pTpReleaseCleanupGroup(group
);
1268 pTpReleasePool(pool
);
1269 CloseHandle(semaphores
[0]);
1270 CloseHandle(semaphores
[1]);
1273 static void CALLBACK
timer_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
, TP_TIMER
*timer
)
1275 HANDLE semaphore
= userdata
;
1276 trace("Running timer callback\n");
1277 ReleaseSemaphore(semaphore
, 1, NULL
);
1280 static void test_tp_timer(void)
1282 TP_CALLBACK_ENVIRON environment
;
1283 DWORD result
, ticks
;
1292 semaphore
= CreateSemaphoreA(NULL
, 0, 1, NULL
);
1293 ok(semaphore
!= NULL
, "CreateSemaphoreA failed %u\n", GetLastError());
1295 /* allocate new threadpool */
1297 status
= pTpAllocPool(&pool
, NULL
);
1298 ok(!status
, "TpAllocPool failed with status %x\n", status
);
1299 ok(pool
!= NULL
, "expected pool != NULL\n");
1301 /* allocate new timer */
1303 memset(&environment
, 0, sizeof(environment
));
1304 environment
.Version
= 1;
1305 environment
.Pool
= pool
;
1306 status
= pTpAllocTimer(&timer
, timer_cb
, semaphore
, &environment
);
1307 ok(!status
, "TpAllocTimer failed with status %x\n", status
);
1308 ok(timer
!= NULL
, "expected timer != NULL\n");
1310 success
= pTpIsTimerSet(timer
);
1311 ok(!success
, "TpIsTimerSet returned TRUE\n");
1313 /* test timer with a relative timeout */
1314 when
.QuadPart
= (ULONGLONG
)200 * -10000;
1315 pTpSetTimer(timer
, &when
, 0, 0);
1316 success
= pTpIsTimerSet(timer
);
1317 ok(success
, "TpIsTimerSet returned FALSE\n");
1319 pTpWaitForTimer(timer
, FALSE
);
1321 result
= WaitForSingleObject(semaphore
, 100);
1322 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1323 result
= WaitForSingleObject(semaphore
, 200);
1324 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1325 success
= pTpIsTimerSet(timer
);
1326 ok(success
, "TpIsTimerSet returned FALSE\n");
1328 /* test timer with an absolute timeout */
1329 NtQuerySystemTime( &when
);
1330 when
.QuadPart
+= (ULONGLONG
)200 * 10000;
1331 pTpSetTimer(timer
, &when
, 0, 0);
1332 success
= pTpIsTimerSet(timer
);
1333 ok(success
, "TpIsTimerSet returned FALSE\n");
1335 pTpWaitForTimer(timer
, FALSE
);
1337 result
= WaitForSingleObject(semaphore
, 100);
1338 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1339 result
= WaitForSingleObject(semaphore
, 200);
1340 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1341 success
= pTpIsTimerSet(timer
);
1342 ok(success
, "TpIsTimerSet returned FALSE\n");
1344 /* test timer with zero timeout */
1346 pTpSetTimer(timer
, &when
, 0, 0);
1347 success
= pTpIsTimerSet(timer
);
1348 ok(success
, "TpIsTimerSet returned FALSE\n");
1350 pTpWaitForTimer(timer
, FALSE
);
1352 result
= WaitForSingleObject(semaphore
, 50);
1353 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1354 success
= pTpIsTimerSet(timer
);
1355 ok(success
, "TpIsTimerSet returned FALSE\n");
1357 /* unset the timer */
1358 pTpSetTimer(timer
, NULL
, 0, 0);
1359 success
= pTpIsTimerSet(timer
);
1360 ok(!success
, "TpIsTimerSet returned TRUE\n");
1361 pTpWaitForTimer(timer
, TRUE
);
1363 pTpReleaseTimer(timer
);
1364 CloseHandle(semaphore
);
1366 semaphore
= CreateSemaphoreA(NULL
, 0, 3, NULL
);
1367 ok(semaphore
!= NULL
, "CreateSemaphoreA failed %u\n", GetLastError());
1369 /* allocate a new timer */
1371 memset(&environment
, 0, sizeof(environment
));
1372 environment
.Version
= 1;
1373 environment
.Pool
= pool
;
1374 status
= pTpAllocTimer(&timer
, timer_cb
, semaphore
, &environment
);
1375 ok(!status
, "TpAllocTimer failed with status %x\n", status
);
1376 ok(timer
!= NULL
, "expected timer != NULL\n");
1378 /* test a relative timeout repeated periodically */
1379 when
.QuadPart
= (ULONGLONG
)200 * -10000;
1380 pTpSetTimer(timer
, &when
, 200, 0);
1381 success
= pTpIsTimerSet(timer
);
1382 ok(success
, "TpIsTimerSet returned FALSE\n");
1384 /* wait until the timer was triggered three times */
1385 ticks
= GetTickCount();
1386 for (i
= 0; i
< 3; i
++)
1388 result
= WaitForSingleObject(semaphore
, 1000);
1389 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1391 ticks
= GetTickCount() - ticks
;
1392 ok(ticks
>= 500 && (ticks
<= 700 || broken(ticks
<= 750)) /* Win 7 */,
1393 "expected approximately 600 ticks, got %u\n", ticks
);
1395 /* unset the timer */
1396 pTpSetTimer(timer
, NULL
, 0, 0);
1397 success
= pTpIsTimerSet(timer
);
1398 ok(!success
, "TpIsTimerSet returned TRUE\n");
1399 pTpWaitForTimer(timer
, TRUE
);
1402 pTpReleaseTimer(timer
);
1403 pTpReleasePool(pool
);
1404 CloseHandle(semaphore
);
1407 struct window_length_info
1413 static void CALLBACK
window_length_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
, TP_TIMER
*timer
)
1415 struct window_length_info
*info
= userdata
;
1416 trace("Running window length callback\n");
1417 info
->ticks
= GetTickCount();
1418 ReleaseSemaphore(info
->semaphore
, 1, NULL
);
1421 static void test_tp_window_length(void)
1423 struct window_length_info info1
, info2
;
1424 TP_CALLBACK_ENVIRON environment
;
1425 TP_TIMER
*timer1
, *timer2
;
1433 semaphore
= CreateSemaphoreA(NULL
, 0, 2, NULL
);
1434 ok(semaphore
!= NULL
, "CreateSemaphoreA failed %u\n", GetLastError());
1436 /* allocate new threadpool */
1438 status
= pTpAllocPool(&pool
, NULL
);
1439 ok(!status
, "TpAllocPool failed with status %x\n", status
);
1440 ok(pool
!= NULL
, "expected pool != NULL\n");
1442 /* allocate two identical timers */
1443 memset(&environment
, 0, sizeof(environment
));
1444 environment
.Version
= 1;
1445 environment
.Pool
= pool
;
1448 info1
.semaphore
= semaphore
;
1449 status
= pTpAllocTimer(&timer1
, window_length_cb
, &info1
, &environment
);
1450 ok(!status
, "TpAllocTimer failed with status %x\n", status
);
1451 ok(timer1
!= NULL
, "expected timer1 != NULL\n");
1454 info2
.semaphore
= semaphore
;
1455 status
= pTpAllocTimer(&timer2
, window_length_cb
, &info2
, &environment
);
1456 ok(!status
, "TpAllocTimer failed with status %x\n", status
);
1457 ok(timer2
!= NULL
, "expected timer2 != NULL\n");
1459 /* choose parameters so that timers are not merged */
1463 NtQuerySystemTime( &when
);
1464 when
.QuadPart
+= (ULONGLONG
)250 * 10000;
1465 pTpSetTimer(timer2
, &when
, 0, 0);
1467 when
.QuadPart
-= (ULONGLONG
)150 * 10000;
1468 pTpSetTimer(timer1
, &when
, 0, 75);
1470 result
= WaitForSingleObject(semaphore
, 1000);
1471 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1472 result
= WaitForSingleObject(semaphore
, 1000);
1473 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1474 ok(info1
.ticks
!= 0 && info2
.ticks
!= 0, "expected that ticks are nonzero\n");
1475 ok(info2
.ticks
>= info1
.ticks
+ 75 || broken(info2
.ticks
< info1
.ticks
+ 75) /* Win 2008 */,
1476 "expected that timers are not merged\n");
1478 /* timers will be merged */
1482 NtQuerySystemTime( &when
);
1483 when
.QuadPart
+= (ULONGLONG
)250 * 10000;
1484 pTpSetTimer(timer2
, &when
, 0, 0);
1486 when
.QuadPart
-= (ULONGLONG
)150 * 10000;
1487 pTpSetTimer(timer1
, &when
, 0, 200);
1489 result
= WaitForSingleObject(semaphore
, 1000);
1490 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1491 result
= WaitForSingleObject(semaphore
, 1000);
1492 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1493 ok(info1
.ticks
!= 0 && info2
.ticks
!= 0, "expected that ticks are nonzero\n");
1494 merged
= info2
.ticks
>= info1
.ticks
- 50 && info2
.ticks
<= info1
.ticks
+ 50;
1495 ok(merged
|| broken(!merged
) /* Win 10 */, "expected that timers are merged\n");
1497 /* on Windows the timers also get merged in this case */
1501 NtQuerySystemTime( &when
);
1502 when
.QuadPart
+= (ULONGLONG
)100 * 10000;
1503 pTpSetTimer(timer1
, &when
, 0, 200);
1505 when
.QuadPart
+= (ULONGLONG
)150 * 10000;
1506 pTpSetTimer(timer2
, &when
, 0, 0);
1508 result
= WaitForSingleObject(semaphore
, 1000);
1509 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1510 result
= WaitForSingleObject(semaphore
, 1000);
1511 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1512 ok(info1
.ticks
!= 0 && info2
.ticks
!= 0, "expected that ticks are nonzero\n");
1513 merged
= info2
.ticks
>= info1
.ticks
- 50 && info2
.ticks
<= info1
.ticks
+ 50;
1515 ok(merged
|| broken(!merged
) /* Win 10 */, "expected that timers are merged\n");
1518 pTpReleaseTimer(timer1
);
1519 pTpReleaseTimer(timer2
);
1520 pTpReleasePool(pool
);
1521 CloseHandle(semaphore
);
1530 static void CALLBACK
wait_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
,
1531 TP_WAIT
*wait
, TP_WAIT_RESULT result
)
1533 struct wait_info
*info
= userdata
;
1534 trace("Running wait callback\n");
1536 if (result
== WAIT_OBJECT_0
)
1537 InterlockedIncrement(&info
->userdata
);
1538 else if (result
== WAIT_TIMEOUT
)
1539 InterlockedExchangeAdd(&info
->userdata
, 0x10000);
1541 ok(0, "unexpected result %u\n", result
);
1542 ReleaseSemaphore(info
->semaphore
, 1, NULL
);
1545 static void test_tp_wait(void)
1547 TP_CALLBACK_ENVIRON environment
;
1548 TP_WAIT
*wait1
, *wait2
;
1549 struct wait_info info
;
1550 HANDLE semaphores
[2];
1556 semaphores
[0] = CreateSemaphoreW(NULL
, 0, 2, NULL
);
1557 ok(semaphores
[0] != NULL
, "failed to create semaphore\n");
1558 semaphores
[1] = CreateSemaphoreW(NULL
, 0, 1, NULL
);
1559 ok(semaphores
[1] != NULL
, "failed to create semaphore\n");
1560 info
.semaphore
= semaphores
[0];
1562 /* allocate new threadpool */
1564 status
= pTpAllocPool(&pool
, NULL
);
1565 ok(!status
, "TpAllocPool failed with status %x\n", status
);
1566 ok(pool
!= NULL
, "expected pool != NULL\n");
1568 /* allocate new wait items */
1569 memset(&environment
, 0, sizeof(environment
));
1570 environment
.Version
= 1;
1571 environment
.Pool
= pool
;
1574 status
= pTpAllocWait(&wait1
, wait_cb
, &info
, &environment
);
1575 ok(!status
, "TpAllocWait failed with status %x\n", status
);
1576 ok(wait1
!= NULL
, "expected wait1 != NULL\n");
1579 status
= pTpAllocWait(&wait2
, wait_cb
, &info
, &environment
);
1580 ok(!status
, "TpAllocWait failed with status %x\n", status
);
1581 ok(wait2
!= NULL
, "expected wait2 != NULL\n");
1583 /* infinite timeout, signal the semaphore immediately */
1585 pTpSetWait(wait1
, semaphores
[1], NULL
);
1586 ReleaseSemaphore(semaphores
[1], 1, NULL
);
1587 result
= WaitForSingleObject(semaphores
[0], 100);
1588 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1589 ok(info
.userdata
== 1, "expected info.userdata = 1, got %u\n", info
.userdata
);
1590 result
= WaitForSingleObject(semaphores
[1], 0);
1591 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1593 /* relative timeout, no event */
1595 when
.QuadPart
= (ULONGLONG
)200 * -10000;
1596 pTpSetWait(wait1
, semaphores
[1], &when
);
1597 result
= WaitForSingleObject(semaphores
[0], 100);
1598 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1599 ok(info
.userdata
== 0, "expected info.userdata = 0, got %u\n", info
.userdata
);
1600 result
= WaitForSingleObject(semaphores
[0], 200);
1601 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1602 ok(info
.userdata
== 0x10000, "expected info.userdata = 0x10000, got %u\n", info
.userdata
);
1603 result
= WaitForSingleObject(semaphores
[1], 0);
1604 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1606 /* repeat test with call to TpWaitForWait(..., TRUE) */
1608 when
.QuadPart
= (ULONGLONG
)200 * -10000;
1609 pTpSetWait(wait1
, semaphores
[1], &when
);
1610 result
= WaitForSingleObject(semaphores
[0], 100);
1611 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1612 pTpWaitForWait(wait1
, TRUE
);
1613 ok(info
.userdata
== 0, "expected info.userdata = 0, got %u\n", info
.userdata
);
1614 result
= WaitForSingleObject(semaphores
[0], 200);
1615 ok(result
== WAIT_OBJECT_0
|| broken(result
== WAIT_TIMEOUT
) /* Win 8 */,
1616 "WaitForSingleObject returned %u\n", result
);
1617 if (result
== WAIT_OBJECT_0
)
1618 ok(info
.userdata
== 0x10000, "expected info.userdata = 0x10000, got %u\n", info
.userdata
);
1620 ok(info
.userdata
== 0, "expected info.userdata = 0, got %u\n", info
.userdata
);
1621 result
= WaitForSingleObject(semaphores
[1], 0);
1622 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1624 /* relative timeout, with event */
1626 when
.QuadPart
= (ULONGLONG
)200 * -10000;
1627 pTpSetWait(wait1
, semaphores
[1], &when
);
1628 result
= WaitForSingleObject(semaphores
[0], 100);
1629 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1630 ok(info
.userdata
== 0, "expected info.userdata = 0, got %u\n", info
.userdata
);
1631 ReleaseSemaphore(semaphores
[1], 1, NULL
);
1632 result
= WaitForSingleObject(semaphores
[0], 100);
1633 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1634 ok(info
.userdata
== 1, "expected info.userdata = 1, got %u\n", info
.userdata
);
1635 result
= WaitForSingleObject(semaphores
[1], 0);
1636 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1638 /* repeat test with call to TpWaitForWait(..., TRUE) */
1640 when
.QuadPart
= (ULONGLONG
)200 * -10000;
1641 pTpSetWait(wait1
, semaphores
[1], &when
);
1642 result
= WaitForSingleObject(semaphores
[0], 100);
1643 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1644 pTpWaitForWait(wait1
, TRUE
);
1645 ok(info
.userdata
== 0, "expected info.userdata = 0, got %u\n", info
.userdata
);
1646 ReleaseSemaphore(semaphores
[1], 1, NULL
);
1647 result
= WaitForSingleObject(semaphores
[0], 100);
1648 ok(result
== WAIT_OBJECT_0
|| broken(result
== WAIT_TIMEOUT
) /* Win 8 */,
1649 "WaitForSingleObject returned %u\n", result
);
1650 if (result
== WAIT_OBJECT_0
)
1652 ok(info
.userdata
== 1, "expected info.userdata = 1, got %u\n", info
.userdata
);
1653 result
= WaitForSingleObject(semaphores
[1], 0);
1654 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1658 ok(info
.userdata
== 0, "expected info.userdata = 0, got %u\n", info
.userdata
);
1659 result
= WaitForSingleObject(semaphores
[1], 0);
1660 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1663 /* absolute timeout, no event */
1665 NtQuerySystemTime( &when
);
1666 when
.QuadPart
+= (ULONGLONG
)200 * 10000;
1667 pTpSetWait(wait1
, semaphores
[1], &when
);
1668 result
= WaitForSingleObject(semaphores
[0], 100);
1669 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1670 ok(info
.userdata
== 0, "expected info.userdata = 0, got %u\n", info
.userdata
);
1671 result
= WaitForSingleObject(semaphores
[0], 200);
1672 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1673 ok(info
.userdata
== 0x10000, "expected info.userdata = 0x10000, got %u\n", info
.userdata
);
1674 result
= WaitForSingleObject(semaphores
[1], 0);
1675 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1677 /* absolute timeout, with event */
1679 NtQuerySystemTime( &when
);
1680 when
.QuadPart
+= (ULONGLONG
)200 * 10000;
1681 pTpSetWait(wait1
, semaphores
[1], &when
);
1682 result
= WaitForSingleObject(semaphores
[0], 100);
1683 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1684 ok(info
.userdata
== 0, "expected info.userdata = 0, got %u\n", info
.userdata
);
1685 ReleaseSemaphore(semaphores
[1], 1, NULL
);
1686 result
= WaitForSingleObject(semaphores
[0], 100);
1687 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1688 ok(info
.userdata
== 1, "expected info.userdata = 1, got %u\n", info
.userdata
);
1689 result
= WaitForSingleObject(semaphores
[1], 0);
1690 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1692 /* test timeout of zero */
1695 pTpSetWait(wait1
, semaphores
[1], &when
);
1696 result
= WaitForSingleObject(semaphores
[0], 100);
1697 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1698 ok(info
.userdata
== 0x10000, "expected info.userdata = 0x10000, got %u\n", info
.userdata
);
1699 result
= WaitForSingleObject(semaphores
[1], 0);
1700 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1702 /* cancel a pending wait */
1704 when
.QuadPart
= (ULONGLONG
)250 * -10000;
1705 pTpSetWait(wait1
, semaphores
[1], &when
);
1706 result
= WaitForSingleObject(semaphores
[0], 100);
1707 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1708 pTpSetWait(wait1
, NULL
, (void *)0xdeadbeef);
1710 ReleaseSemaphore(semaphores
[1], 1, NULL
);
1711 result
= WaitForSingleObject(semaphores
[0], 100);
1712 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1713 ok(info
.userdata
== 0, "expected info.userdata = 0, got %u\n", info
.userdata
);
1714 result
= WaitForSingleObject(semaphores
[1], 0);
1715 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1717 /* test with INVALID_HANDLE_VALUE */
1720 pTpSetWait(wait1
, INVALID_HANDLE_VALUE
, &when
);
1721 result
= WaitForSingleObject(semaphores
[0], 100);
1722 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1723 ok(info
.userdata
== 0x10000, "expected info.userdata = 0x10000, got %u\n", info
.userdata
);
1725 /* cancel a pending wait with INVALID_HANDLE_VALUE */
1727 when
.QuadPart
= (ULONGLONG
)250 * -10000;
1728 pTpSetWait(wait1
, semaphores
[1], &when
);
1729 result
= WaitForSingleObject(semaphores
[0], 100);
1730 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1732 pTpSetWait(wait1
, INVALID_HANDLE_VALUE
, &when
);
1734 ReleaseSemaphore(semaphores
[1], 1, NULL
);
1735 result
= WaitForSingleObject(semaphores
[0], 100);
1736 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1737 ok(info
.userdata
== 0x10000, "expected info.userdata = 0x10000, got %u\n", info
.userdata
);
1738 result
= WaitForSingleObject(semaphores
[1], 0);
1739 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1741 CloseHandle(semaphores
[1]);
1742 semaphores
[1] = CreateSemaphoreW(NULL
, 0, 2, NULL
);
1743 ok(semaphores
[1] != NULL
, "failed to create semaphore\n");
1745 /* add two wait objects with the same semaphore */
1747 pTpSetWait(wait1
, semaphores
[1], NULL
);
1748 pTpSetWait(wait2
, semaphores
[1], NULL
);
1750 ReleaseSemaphore(semaphores
[1], 1, NULL
);
1751 result
= WaitForSingleObject(semaphores
[0], 100);
1752 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1753 result
= WaitForSingleObject(semaphores
[0], 100);
1754 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1755 ok(info
.userdata
== 1, "expected info.userdata = 1, got %u\n", info
.userdata
);
1756 result
= WaitForSingleObject(semaphores
[1], 0);
1757 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1759 /* repeat test above with release count 2 */
1761 pTpSetWait(wait1
, semaphores
[1], NULL
);
1762 pTpSetWait(wait2
, semaphores
[1], NULL
);
1764 result
= ReleaseSemaphore(semaphores
[1], 2, NULL
);
1765 result
= WaitForSingleObject(semaphores
[0], 100);
1766 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1767 result
= WaitForSingleObject(semaphores
[0], 100);
1768 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1769 ok(info
.userdata
== 2, "expected info.userdata = 2, got %u\n", info
.userdata
);
1770 result
= WaitForSingleObject(semaphores
[1], 0);
1771 ok(result
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", result
);
1774 pTpReleaseWait(wait1
);
1775 pTpReleaseWait(wait2
);
1776 pTpReleasePool(pool
);
1777 CloseHandle(semaphores
[0]);
1778 CloseHandle(semaphores
[1]);
1787 static void CALLBACK
multi_wait_cb(TP_CALLBACK_INSTANCE
*instance
, void *userdata
, TP_WAIT
*wait
, TP_WAIT_RESULT result
)
1789 DWORD index
= (DWORD
)(DWORD_PTR
)userdata
;
1791 if (result
== WAIT_OBJECT_0
)
1792 multi_wait_info
.result
= index
;
1793 else if (result
== WAIT_TIMEOUT
)
1794 multi_wait_info
.result
= 0x10000 | index
;
1796 ok(0, "unexpected result %u\n", result
);
1797 ReleaseSemaphore(multi_wait_info
.semaphore
, 1, NULL
);
1800 static void test_tp_multi_wait(void)
1802 TP_CALLBACK_ENVIRON environment
;
1803 HANDLE semaphores
[512];
1804 TP_WAIT
*waits
[512];
1812 semaphore
= CreateSemaphoreW(NULL
, 0, 512, NULL
);
1813 ok(semaphore
!= NULL
, "failed to create semaphore\n");
1814 multi_wait_info
.semaphore
= semaphore
;
1816 /* allocate new threadpool */
1818 status
= pTpAllocPool(&pool
, NULL
);
1819 ok(!status
, "TpAllocPool failed with status %x\n", status
);
1820 ok(pool
!= NULL
, "expected pool != NULL\n");
1822 memset(&environment
, 0, sizeof(environment
));
1823 environment
.Version
= 1;
1824 environment
.Pool
= pool
;
1826 /* create semaphores and corresponding wait objects */
1827 for (i
= 0; i
< sizeof(semaphores
)/sizeof(semaphores
[0]); i
++)
1829 semaphores
[i
] = CreateSemaphoreW(NULL
, 0, 1, NULL
);
1830 ok(semaphores
[i
] != NULL
, "failed to create semaphore %i\n", i
);
1833 status
= pTpAllocWait(&waits
[i
], multi_wait_cb
, (void *)(DWORD_PTR
)i
, &environment
);
1834 ok(!status
, "TpAllocWait failed with status %x\n", status
);
1835 ok(waits
[i
] != NULL
, "expected waits[%d] != NULL\n", i
);
1837 pTpSetWait(waits
[i
], semaphores
[i
], NULL
);
1840 /* release all semaphores and wait for callback */
1841 for (i
= 0; i
< sizeof(semaphores
)/sizeof(semaphores
[0]); i
++)
1843 multi_wait_info
.result
= 0;
1844 ReleaseSemaphore(semaphores
[i
], 1, NULL
);
1846 result
= WaitForSingleObject(semaphore
, 100);
1847 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1848 ok(multi_wait_info
.result
== i
, "expected result %d, got %u\n", i
, multi_wait_info
.result
);
1850 pTpSetWait(waits
[i
], semaphores
[i
], NULL
);
1853 /* repeat the same test in reverse order */
1854 for (i
= sizeof(semaphores
)/sizeof(semaphores
[0]) - 1; i
>= 0; i
--)
1856 multi_wait_info
.result
= 0;
1857 ReleaseSemaphore(semaphores
[i
], 1, NULL
);
1859 result
= WaitForSingleObject(semaphore
, 100);
1860 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1861 ok(multi_wait_info
.result
== i
, "expected result %d, got %u\n", i
, multi_wait_info
.result
);
1863 pTpSetWait(waits
[i
], semaphores
[i
], NULL
);
1866 /* test timeout of wait objects */
1867 multi_wait_info
.result
= 0;
1868 for (i
= 0; i
< sizeof(semaphores
)/sizeof(semaphores
[0]); i
++)
1870 when
.QuadPart
= (ULONGLONG
)50 * -10000;
1871 pTpSetWait(waits
[i
], semaphores
[i
], &when
);
1874 for (i
= 0; i
< sizeof(semaphores
)/sizeof(semaphores
[0]); i
++)
1876 result
= WaitForSingleObject(semaphore
, 150);
1877 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
1880 ok(multi_wait_info
.result
>> 16, "expected multi_wait_info.result >> 16 != 0\n");
1882 /* destroy the wait objects and semaphores while waiting */
1883 for (i
= 0; i
< sizeof(semaphores
)/sizeof(semaphores
[0]); i
++)
1885 pTpSetWait(waits
[i
], semaphores
[i
], NULL
);
1890 for (i
= 0; i
< sizeof(semaphores
)/sizeof(semaphores
[0]); i
++)
1892 pTpReleaseWait(waits
[i
]);
1893 NtClose(semaphores
[i
]);
1896 pTpReleasePool(pool
);
1897 CloseHandle(semaphore
);
1900 START_TEST(threadpool
)
1902 test_RtlQueueWorkItem();
1903 test_RtlRegisterWait();
1905 if (!init_threadpool())
1910 test_tp_work_scheduler();
1911 test_tp_group_wait();
1912 test_tp_group_cancel();
1914 test_tp_disassociate();
1916 test_tp_window_length();
1918 test_tp_multi_wait();