mshtml: Don't crash creating a URI if we have no document.
[wine.git] / dlls / ntdll / tests / threadpool.c
blob1d8b1f953528d1ddfc39d77ed31c47c97e41e67e
1 /*
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) \
49 do \
50 { \
51 p ## func = (void *)GetProcAddress(hntdll, #func); \
52 if (!p ## func) trace("Failed to get address for %s\n", #func); \
53 } \
54 while (0)
56 static BOOL init_threadpool(void)
58 hntdll = GetModuleHandleA("ntdll");
59 if (!hntdll)
61 win_skip("Could not load ntdll\n");
62 return FALSE;
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);
89 if (!pTpAllocPool)
91 win_skip("Threadpool functions not supported, skipping tests\n");
92 return FALSE;
95 return TRUE;
98 #undef NTDLL_GET_PROC
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);
106 return 0;
109 static void test_RtlQueueWorkItem(void)
111 HANDLE semaphore;
112 NTSTATUS status;
113 DWORD result;
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);
146 struct rtl_wait_info
148 HANDLE semaphore1;
149 HANDLE semaphore2;
150 DWORD wait_result;
151 DWORD threadid;
152 LONG userdata;
155 static void CALLBACK rtl_wait_cb(void *userdata, BOOLEAN timeout)
157 struct rtl_wait_info *info = userdata;
158 DWORD result;
160 trace("Running rtl_wait callback\n");
162 if (!timeout)
163 InterlockedIncrement(&info->userdata);
164 else
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];
191 NTSTATUS status;
192 DWORD result;
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 */
205 wait1 = NULL;
206 info.userdata = 0;
207 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT);
208 ok(!status, "RtlRegisterWait failed with status %x\n", status);
209 ok(wait1 != NULL, "expected wait1 != NULL\n");
210 status = RtlDeregisterWait(wait1);
211 ok(!status, "RtlDeregisterWait failed with status %x\n", status);
212 ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata);
214 /* infinite timeout, signal the semaphore two times */
215 info.userdata = 0;
216 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT);
217 ok(!status, "RtlRegisterWait failed with status %x\n", status);
218 ReleaseSemaphore(semaphores[1], 1, NULL);
219 result = WaitForSingleObject(semaphores[0], 100);
220 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
221 ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata);
222 ReleaseSemaphore(semaphores[1], 1, NULL);
223 result = WaitForSingleObject(semaphores[0], 100);
224 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
225 ok(info.userdata == 2, "expected info.userdata = 2, got %u\n", info.userdata);
226 result = WaitForSingleObject(semaphores[1], 0);
227 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
228 Sleep(50);
229 status = RtlDeregisterWait(wait1);
230 ok(!status, "RtlDeregisterWait failed with status %x\n", status);
232 /* repeat test with WT_EXECUTEONLYONCE */
233 info.userdata = 0;
234 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEONLYONCE);
235 ok(!status, "RtlRegisterWait failed with status %x\n", status);
236 ReleaseSemaphore(semaphores[1], 1, NULL);
237 result = WaitForSingleObject(semaphores[0], 100);
238 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
239 ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata);
240 ReleaseSemaphore(semaphores[1], 1, NULL);
241 result = WaitForSingleObject(semaphores[0], 100);
242 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
243 ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata);
244 result = WaitForSingleObject(semaphores[1], 0);
245 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
246 Sleep(50);
247 status = RtlDeregisterWait(wait1);
248 ok(!status, "RtlDeregisterWait failed with status %x\n", status);
250 /* finite timeout, no event */
251 info.userdata = 0;
252 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 200, WT_EXECUTEDEFAULT);
253 ok(!status, "RtlRegisterWait failed with status %x\n", status);
254 result = WaitForSingleObject(semaphores[0], 100);
255 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
256 ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata);
257 result = WaitForSingleObject(semaphores[0], 200);
258 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
259 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata);
260 result = WaitForSingleObject(semaphores[1], 0);
261 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
262 Sleep(50);
263 status = RtlDeregisterWait(wait1);
264 ok(!status, "RtlDeregisterWait failed with status %x\n", status);
266 /* finite timeout, with event */
267 info.userdata = 0;
268 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 200, WT_EXECUTEDEFAULT);
269 ok(!status, "RtlRegisterWait failed with status %x\n", status);
270 result = WaitForSingleObject(semaphores[0], 100);
271 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
272 ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata);
273 ReleaseSemaphore(semaphores[1], 1, NULL);
274 result = WaitForSingleObject(semaphores[0], 100);
275 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
276 ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata);
277 result = WaitForSingleObject(semaphores[1], 0);
278 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
279 Sleep(50);
280 status = RtlDeregisterWait(wait1);
281 ok(!status, "RtlDeregisterWait failed with status %x\n", status);
283 /* test for IO threads */
284 info.userdata = 0;
285 info.threadid = 0;
286 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEINIOTHREAD);
287 ok(!status, "RtlRegisterWait failed with status %x\n", status);
288 ReleaseSemaphore(semaphores[1], 1, NULL);
289 result = WaitForSingleObject(semaphores[0], 100);
290 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
291 ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata);
292 ok(info.threadid != 0, "expected info.threadid != 0, got %u\n", info.threadid);
293 thread = OpenThread(THREAD_SET_CONTEXT, FALSE, info.threadid);
294 ok(thread != NULL, "OpenThread failed with %u\n", GetLastError());
295 rtl_wait_apc_semaphore = semaphores[0];
296 result = QueueUserAPC(rtl_wait_apc_cb, thread, 0);
297 ok(result != 0, "QueueUserAPC failed with %u\n", GetLastError());
298 result = WaitForSingleObject(semaphores[0], 200);
299 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
300 rtl_wait_apc_semaphore = 0;
301 CloseHandle(thread);
302 ReleaseSemaphore(semaphores[1], 1, NULL);
303 result = WaitForSingleObject(semaphores[0], 100);
304 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
305 ok(info.userdata == 2, "expected info.userdata = 2, got %u\n", info.userdata);
306 Sleep(50);
307 status = RtlDeregisterWait(wait1);
308 ok(!status, "RtlDeregisterWait failed with status %x\n", status);
310 info.userdata = 0;
311 info.threadid = 0;
312 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT);
313 ok(!status, "RtlRegisterWait failed with status %x\n", status);
314 ReleaseSemaphore(semaphores[1], 1, NULL);
315 result = WaitForSingleObject(semaphores[0], 100);
316 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
317 ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata);
318 ok(info.threadid != 0, "expected info.threadid != 0, got %u\n", info.threadid);
319 thread = OpenThread(THREAD_SET_CONTEXT, FALSE, info.threadid);
320 ok(thread != NULL, "OpenThread failed with %u\n", GetLastError());
321 rtl_wait_apc_semaphore = semaphores[0];
322 result = QueueUserAPC(rtl_wait_apc_cb, thread, 0);
323 ok(result != 0, "QueueUserAPC failed with %u\n", GetLastError());
324 result = WaitForSingleObject(semaphores[0], 200);
325 ok(result == WAIT_TIMEOUT || broken(result == WAIT_OBJECT_0) /* >= Win Vista */,
326 "WaitForSingleObject returned %u\n", result);
327 rtl_wait_apc_semaphore = 0;
328 CloseHandle(thread);
329 ReleaseSemaphore(semaphores[1], 1, NULL);
330 result = WaitForSingleObject(semaphores[0], 100);
331 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
332 ok(info.userdata == 2, "expected info.userdata = 2, got %u\n", info.userdata);
333 Sleep(50);
334 status = RtlDeregisterWait(wait1);
335 ok(!status, "RtlDeregisterWait failed with status %x\n", status);
337 /* test RtlDeregisterWaitEx before wait expired */
338 info.userdata = 0;
339 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT);
340 ok(!status, "RtlRegisterWait failed with status %x\n", status);
341 status = RtlDeregisterWaitEx(wait1, NULL);
342 ok(!status, "RtlDeregisterWaitEx failed with status %x\n", status);
343 ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata);
345 info.userdata = 0;
346 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT);
347 ok(!status, "RtlRegisterWait failed with status %x\n", status);
348 status = RtlDeregisterWaitEx(wait1, INVALID_HANDLE_VALUE);
349 ok(!status, "RtlDeregisterWaitEx failed with status %x\n", status);
350 ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata);
352 info.userdata = 0;
353 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT);
354 ok(!status, "RtlRegisterWait failed with status %x\n", status);
355 status = RtlDeregisterWaitEx(wait1, event);
356 ok(!status, "RtlDeregisterWaitEx failed with status %x\n", status);
357 ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata);
358 result = WaitForSingleObject(event, 200);
359 todo_wine
360 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
362 /* test RtlDeregisterWaitEx after wait expired */
363 info.userdata = 0;
364 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 0, WT_EXECUTEONLYONCE);
365 ok(!status, "RtlRegisterWait failed with status %x\n", status);
366 result = WaitForSingleObject(semaphores[0], 100);
367 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
368 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata);
369 Sleep(50);
370 status = RtlDeregisterWaitEx(wait1, NULL);
371 ok(!status, "RtlDeregisterWaitEx failed with status %x\n", status);
372 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata);
374 info.userdata = 0;
375 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 0, WT_EXECUTEONLYONCE);
376 ok(!status, "RtlRegisterWait failed with status %x\n", status);
377 result = WaitForSingleObject(semaphores[0], 100);
378 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
379 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata);
380 Sleep(50);
381 status = RtlDeregisterWaitEx(wait1, INVALID_HANDLE_VALUE);
382 ok(!status, "RtlDeregisterWaitEx failed with status %x\n", status);
383 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata);
385 info.userdata = 0;
386 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 0, WT_EXECUTEONLYONCE);
387 ok(!status, "RtlRegisterWait failed with status %x\n", status);
388 result = WaitForSingleObject(semaphores[0], 100);
389 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
390 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata);
391 Sleep(50);
392 status = RtlDeregisterWaitEx(wait1, event);
393 ok(!status, "RtlDeregisterWaitEx failed with status %x\n", status);
394 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata);
395 result = WaitForSingleObject(event, 200);
396 todo_wine
397 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
399 /* test RtlDeregisterWaitEx while callback is running */
400 info.semaphore2 = semaphores[1];
401 info.wait_result = WAIT_OBJECT_0;
403 info.userdata = 0;
404 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEONLYONCE);
405 ok(!status, "RtlRegisterWait failed with status %x\n", status);
406 ReleaseSemaphore(semaphores[1], 1, NULL);
407 result = WaitForSingleObject(semaphores[0], 1000);
408 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
409 ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata);
410 status = RtlDeregisterWait(wait1);
411 ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %x\n", status);
412 ReleaseSemaphore(semaphores[1], 1, NULL);
413 result = WaitForSingleObject(semaphores[0], 1000);
414 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
416 info.userdata = 0;
417 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEONLYONCE);
418 ok(!status, "RtlRegisterWait failed with status %x\n", status);
419 ReleaseSemaphore(semaphores[1], 1, NULL);
420 result = WaitForSingleObject(semaphores[0], 1000);
421 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
422 ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata);
423 status = RtlDeregisterWaitEx(wait1, NULL);
424 ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %x\n", status);
425 ReleaseSemaphore(semaphores[1], 1, NULL);
426 result = WaitForSingleObject(semaphores[0], 1000);
427 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
429 info.wait_result = WAIT_TIMEOUT;
430 info.userdata = 0;
431 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEONLYONCE);
432 ok(!status, "RtlRegisterWait failed with status %x\n", status);
433 ReleaseSemaphore(semaphores[1], 1, NULL);
434 result = WaitForSingleObject(semaphores[0], 1000);
435 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
436 ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata);
437 status = RtlDeregisterWaitEx(wait1, INVALID_HANDLE_VALUE);
438 ok(!status, "RtlDeregisterWaitEx failed with status %x\n", status);
439 result = WaitForSingleObject(semaphores[0], 0);
440 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
442 info.wait_result = WAIT_OBJECT_0;
443 info.userdata = 0;
444 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEONLYONCE);
445 ok(!status, "RtlRegisterWait failed with status %x\n", status);
446 ReleaseSemaphore(semaphores[1], 1, NULL);
447 result = WaitForSingleObject(semaphores[0], 1000);
448 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
449 ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata);
450 status = RtlDeregisterWaitEx(wait1, event);
451 ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %x\n", status);
452 ReleaseSemaphore(semaphores[1], 1, NULL);
453 result = WaitForSingleObject(event, 1000);
454 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
455 result = WaitForSingleObject(semaphores[0], 0);
456 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
458 CloseHandle(semaphores[0]);
459 CloseHandle(semaphores[1]);
460 CloseHandle(event);
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");
473 Sleep(50);
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;
482 HANDLE semaphore;
483 NTSTATUS status;
484 TP_POOL *pool;
485 LONG userdata;
486 DWORD result;
487 int i;
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 */
502 pool = NULL;
503 status = pTpAllocPool(&pool, NULL);
504 ok(!status, "TpAllocPool failed with status %x\n", status);
505 ok(pool != NULL, "expected pool != NULL\n");
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);
532 todo_wine
533 ok(status == STATUS_INVALID_PARAMETER || broken(!status) /* Vista/2008 */,
534 "TpSimpleTryPost unexpectedly returned status %x\n", status);
535 if (!status)
537 result = WaitForSingleObject(semaphore, 1000);
538 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
541 /* allocate a cleanup group for synchronization */
542 group = NULL;
543 status = pTpAllocCleanupGroup(&group);
544 ok(!status, "TpAllocCleanupGroup failed with status %x\n", status);
545 ok(group != NULL, "expected pool != NULL\n");
547 /* use cleanup group to wait for a simple callback */
548 userdata = 0;
549 memset(&environment, 0, sizeof(environment));
550 environment.Version = 1;
551 environment.Pool = pool;
552 environment.CleanupGroup = group;
553 status = pTpSimpleTryPost(simple2_cb, &userdata, &environment);
554 ok(!status, "TpSimpleTryPost failed with status %x\n", status);
555 pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
556 ok(userdata == 1, "expected userdata = 1, got %u\n", userdata);
558 /* test cancellation of pending simple callbacks */
559 userdata = 0;
560 pTpSetPoolMaxThreads(pool, 10);
561 memset(&environment, 0, sizeof(environment));
562 environment.Version = 1;
563 environment.Pool = pool;
564 environment.CleanupGroup = group;
565 for (i = 0; i < 100; i++)
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);
573 /* cleanup */
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");
582 Sleep(10);
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");
589 Sleep(10);
590 InterlockedExchangeAdd((LONG *)userdata, 0x10000);
593 static void test_tp_work(void)
595 TP_CALLBACK_ENVIRON environment;
596 TP_WORK *work;
597 TP_POOL *pool;
598 NTSTATUS status;
599 LONG userdata;
600 int i;
602 /* allocate new threadpool */
603 pool = NULL;
604 status = pTpAllocPool(&pool, NULL);
605 ok(!status, "TpAllocPool failed with status %x\n", status);
606 ok(pool != NULL, "expected pool != NULL\n");
608 /* allocate new work item */
609 work = NULL;
610 memset(&environment, 0, sizeof(environment));
611 environment.Version = 1;
612 environment.Pool = pool;
613 status = pTpAllocWork(&work, work_cb, &userdata, &environment);
614 ok(!status, "TpAllocWork failed with status %x\n", status);
615 ok(work != NULL, "expected work != NULL\n");
617 /* post 10 identical work items at once */
618 userdata = 0;
619 for (i = 0; i < 10; i++)
620 pTpPostWork(work);
621 pTpWaitForWork(work, FALSE);
622 ok(userdata == 10, "expected userdata = 10, got %u\n", userdata);
624 /* add more tasks and cancel them immediately */
625 userdata = 0;
626 for (i = 0; i < 10; i++)
627 pTpPostWork(work);
628 pTpWaitForWork(work, TRUE);
629 ok(userdata < 10, "expected userdata < 10, got %u\n", userdata);
631 /* cleanup */
632 pTpReleaseWork(work);
633 pTpReleasePool(pool);
636 static void test_tp_work_scheduler(void)
638 TP_CALLBACK_ENVIRON environment;
639 TP_CLEANUP_GROUP *group;
640 TP_WORK *work, *work2;
641 TP_POOL *pool;
642 NTSTATUS status;
643 LONG userdata;
644 int i;
646 /* allocate new threadpool */
647 pool = NULL;
648 status = pTpAllocPool(&pool, NULL);
649 ok(!status, "TpAllocPool failed with status %x\n", status);
650 ok(pool != NULL, "expected pool != NULL\n");
652 /* we limit the pool to a single thread */
653 pTpSetPoolMaxThreads(pool, 1);
655 /* create a cleanup group */
656 group = NULL;
657 status = pTpAllocCleanupGroup(&group);
658 ok(!status, "TpAllocCleanupGroup failed with status %x\n", status);
659 ok(group != NULL, "expected pool != NULL\n");
661 /* the first work item has no cleanup group associated */
662 work = NULL;
663 memset(&environment, 0, sizeof(environment));
664 environment.Version = 1;
665 environment.Pool = pool;
666 status = pTpAllocWork(&work, work_cb, &userdata, &environment);
667 ok(!status, "TpAllocWork failed with status %x\n", status);
668 ok(work != NULL, "expected work != NULL\n");
670 /* allocate a second work item with a cleanup group */
671 work2 = NULL;
672 memset(&environment, 0, sizeof(environment));
673 environment.Version = 1;
674 environment.Pool = pool;
675 environment.CleanupGroup = group;
676 status = pTpAllocWork(&work2, work2_cb, &userdata, &environment);
677 ok(!status, "TpAllocWork failed with status %x\n", status);
678 ok(work2 != NULL, "expected work2 != NULL\n");
680 /* the 'work' callbacks are not blocking execution of 'work2' callbacks */
681 userdata = 0;
682 for (i = 0; i < 10; i++)
683 pTpPostWork(work);
684 for (i = 0; i < 10; i++)
685 pTpPostWork(work2);
686 Sleep(30);
687 pTpWaitForWork(work, TRUE);
688 pTpWaitForWork(work2, TRUE);
689 ok(userdata & 0xffff, "expected userdata & 0xffff != 0, got %u\n", userdata & 0xffff);
690 ok(userdata >> 16, "expected userdata >> 16 != 0, got %u\n", userdata >> 16);
692 /* test TpReleaseCleanupGroupMembers on a work item */
693 userdata = 0;
694 for (i = 0; i < 100; i++)
695 pTpPostWork(work);
696 for (i = 0; i < 10; i++)
697 pTpPostWork(work2);
698 pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
699 pTpWaitForWork(work, TRUE);
700 ok((userdata & 0xffff) < 100, "expected userdata & 0xffff < 100, got %u\n", userdata & 0xffff);
701 ok((userdata >> 16) == 10, "expected userdata >> 16 == 10, got %u\n", userdata >> 16);
703 /* cleanup */
704 pTpReleaseWork(work);
705 pTpReleaseCleanupGroup(group);
706 pTpReleasePool(pool);
709 static DWORD group_cancel_tid;
711 static void CALLBACK group_cancel_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
713 HANDLE *semaphores = userdata;
714 NTSTATUS status;
715 DWORD result;
717 trace("Running group cancel callback\n");
719 status = pTpCallbackMayRunLong(instance);
720 ok(status == STATUS_TOO_MANY_THREADS || broken(status == 1) /* Win Vista / 2008 */,
721 "expected STATUS_TOO_MANY_THREADS, got %08x\n", status);
723 result = WaitForSingleObject(semaphores[0], 1000);
724 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
725 ReleaseSemaphore(semaphores[1], 1, NULL);
728 static void CALLBACK group_cancel_cleanup_release_cb(void *object, void *userdata)
730 HANDLE *semaphores = userdata;
731 trace("Running group cancel cleanup release callback\n");
732 group_cancel_tid = GetCurrentThreadId();
733 ReleaseSemaphore(semaphores[0], 1, NULL);
736 static void CALLBACK group_cancel_cleanup_increment_cb(void *object, void *userdata)
738 trace("Running group cancel cleanup increment callback\n");
739 group_cancel_tid = GetCurrentThreadId();
740 InterlockedIncrement((LONG *)userdata);
743 static void CALLBACK unexpected_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
745 ok(0, "Unexpected callback\n");
748 static void test_tp_group_cancel(void)
750 TP_CALLBACK_ENVIRON environment;
751 TP_CLEANUP_GROUP *group;
752 LONG userdata, userdata2;
753 HANDLE semaphores[2];
754 NTSTATUS status;
755 TP_WORK *work;
756 TP_POOL *pool;
757 DWORD result;
758 int i;
760 semaphores[0] = CreateSemaphoreA(NULL, 0, 1, NULL);
761 ok(semaphores[0] != NULL, "CreateSemaphoreA failed %u\n", GetLastError());
762 semaphores[1] = CreateSemaphoreA(NULL, 0, 1, NULL);
763 ok(semaphores[1] != NULL, "CreateSemaphoreA failed %u\n", GetLastError());
765 /* allocate new threadpool with only one thread */
766 pool = NULL;
767 status = pTpAllocPool(&pool, NULL);
768 ok(!status, "TpAllocPool failed with status %x\n", status);
769 ok(pool != NULL, "expected pool != NULL\n");
770 pTpSetPoolMaxThreads(pool, 1);
772 /* allocate a cleanup group */
773 group = NULL;
774 status = pTpAllocCleanupGroup(&group);
775 ok(!status, "TpAllocCleanupGroup failed with status %x\n", status);
776 ok(group != NULL, "expected pool != NULL\n");
778 /* test execution of cancellation callback */
779 memset(&environment, 0, sizeof(environment));
780 environment.Version = 1;
781 environment.Pool = pool;
782 status = pTpSimpleTryPost(group_cancel_cb, semaphores, &environment);
783 ok(!status, "TpSimpleTryPost failed with status %x\n", status);
785 memset(&environment, 0, sizeof(environment));
786 environment.Version = 1;
787 environment.Pool = pool;
788 environment.CleanupGroup = group;
789 environment.CleanupGroupCancelCallback = group_cancel_cleanup_release_cb;
790 status = pTpSimpleTryPost(unexpected_cb, NULL, &environment);
791 ok(!status, "TpSimpleTryPost failed with status %x\n", status);
793 group_cancel_tid = 0xdeadbeef;
794 pTpReleaseCleanupGroupMembers(group, TRUE, semaphores);
795 result = WaitForSingleObject(semaphores[1], 1000);
796 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
797 ok(group_cancel_tid == GetCurrentThreadId(), "expected tid %x, got %x\n",
798 GetCurrentThreadId(), group_cancel_tid);
800 /* test cancellation callback for objects with multiple instances */
801 work = NULL;
802 memset(&environment, 0, sizeof(environment));
803 environment.Version = 1;
804 environment.Pool = pool;
805 environment.CleanupGroup = group;
806 environment.CleanupGroupCancelCallback = group_cancel_cleanup_increment_cb;
807 status = pTpAllocWork(&work, work_cb, &userdata, &environment);
808 ok(!status, "TpAllocWork failed with status %x\n", status);
809 ok(work != NULL, "expected work != NULL\n");
811 /* post 10 identical work items at once */
812 userdata = userdata2 = 0;
813 for (i = 0; i < 10; i++)
814 pTpPostWork(work);
816 /* check if we get multiple cancellation callbacks */
817 group_cancel_tid = 0xdeadbeef;
818 pTpReleaseCleanupGroupMembers(group, TRUE, &userdata2);
819 ok(userdata <= 8, "expected userdata <= 8, got %u\n", userdata);
820 ok(userdata2 == 1, "expected only one cancellation callback, got %u\n", userdata2);
821 ok(group_cancel_tid == GetCurrentThreadId(), "expected tid %x, got %x\n",
822 GetCurrentThreadId(), group_cancel_tid);
824 /* cleanup */
825 pTpReleaseCleanupGroup(group);
826 pTpReleasePool(pool);
827 CloseHandle(semaphores[0]);
828 CloseHandle(semaphores[1]);
831 static void CALLBACK instance_semaphore_completion_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
833 HANDLE *semaphores = userdata;
834 trace("Running instance completion callback\n");
835 pTpCallbackReleaseSemaphoreOnCompletion(instance, semaphores[0], 1);
838 static void CALLBACK instance_finalization_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
840 HANDLE *semaphores = userdata;
841 DWORD result;
843 trace("Running instance finalization callback\n");
845 result = WaitForSingleObject(semaphores[0], 100);
846 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
847 ReleaseSemaphore(semaphores[1], 1, NULL);
850 static void test_tp_instance(void)
852 TP_CALLBACK_ENVIRON environment;
853 HANDLE semaphores[2];
854 NTSTATUS status;
855 TP_POOL *pool;
856 DWORD result;
858 semaphores[0] = CreateSemaphoreW(NULL, 0, 1, NULL);
859 ok(semaphores[0] != NULL, "failed to create semaphore\n");
860 semaphores[1] = CreateSemaphoreW(NULL, 0, 1, NULL);
861 ok(semaphores[1] != NULL, "failed to create semaphore\n");
863 /* allocate new threadpool */
864 pool = NULL;
865 status = pTpAllocPool(&pool, NULL);
866 ok(!status, "TpAllocPool failed with status %x\n", status);
867 ok(pool != NULL, "expected pool != NULL\n");
869 /* test for TpCallbackReleaseSemaphoreOnCompletion */
870 memset(&environment, 0, sizeof(environment));
871 environment.Version = 1;
872 environment.Pool = pool;
873 status = pTpSimpleTryPost(instance_semaphore_completion_cb, semaphores, &environment);
874 ok(!status, "TpSimpleTryPost failed with status %x\n", status);
875 result = WaitForSingleObject(semaphores[0], 1000);
876 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
878 /* test for finalization callback */
879 memset(&environment, 0, sizeof(environment));
880 environment.Version = 1;
881 environment.Pool = pool;
882 environment.FinalizationCallback = instance_finalization_cb;
883 status = pTpSimpleTryPost(instance_semaphore_completion_cb, semaphores, &environment);
884 ok(!status, "TpSimpleTryPost failed with status %x\n", status);
885 result = WaitForSingleObject(semaphores[0], 1000);
886 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
887 result = WaitForSingleObject(semaphores[1], 1000);
888 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
890 /* cleanup */
891 pTpReleasePool(pool);
892 CloseHandle(semaphores[0]);
893 CloseHandle(semaphores[1]);
896 static void CALLBACK disassociate_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
898 HANDLE *semaphores = userdata;
899 DWORD result;
901 trace("Running disassociate callback\n");
903 pTpDisassociateCallback(instance);
904 result = WaitForSingleObject(semaphores[0], 1000);
905 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
906 ReleaseSemaphore(semaphores[1], 1, NULL);
909 static void CALLBACK disassociate2_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
911 HANDLE *semaphores = userdata;
912 DWORD result;
914 trace("Running disassociate2 callback\n");
916 pTpDisassociateCallback(instance);
917 result = WaitForSingleObject(semaphores[0], 100);
918 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
919 ReleaseSemaphore(semaphores[1], 1, NULL);
922 static void CALLBACK disassociate3_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
924 HANDLE *semaphores = userdata;
925 DWORD result;
927 trace("Running disassociate3 callback\n");
929 pTpDisassociateCallback(instance);
930 result = WaitForSingleObject(semaphores[0], 100);
931 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
932 ReleaseSemaphore(semaphores[1], 1, NULL);
935 static void test_tp_disassociate(void)
937 TP_CALLBACK_ENVIRON environment;
938 TP_CLEANUP_GROUP *group;
939 HANDLE semaphores[2];
940 NTSTATUS status;
941 TP_POOL *pool;
942 TP_WORK *work;
943 DWORD result;
945 semaphores[0] = CreateSemaphoreW(NULL, 0, 1, NULL);
946 ok(semaphores[0] != NULL, "failed to create semaphore\n");
947 semaphores[1] = CreateSemaphoreW(NULL, 0, 1, NULL);
948 ok(semaphores[1] != NULL, "failed to create semaphore\n");
950 /* allocate new threadpool and cleanup group */
951 pool = NULL;
952 status = pTpAllocPool(&pool, NULL);
953 ok(!status, "TpAllocPool failed with status %x\n", status);
954 ok(pool != NULL, "expected pool != NULL\n");
956 group = NULL;
957 status = pTpAllocCleanupGroup(&group);
958 ok(!status, "TpAllocCleanupGroup failed with status %x\n", status);
959 ok(group != NULL, "expected pool != NULL\n");
961 /* test TpDisassociateCallback on work objects without group */
962 work = NULL;
963 memset(&environment, 0, sizeof(environment));
964 environment.Version = 1;
965 environment.Pool = pool;
966 status = pTpAllocWork(&work, disassociate_cb, semaphores, &environment);
967 ok(!status, "TpAllocWork failed with status %x\n", status);
968 ok(work != NULL, "expected work != NULL\n");
970 pTpPostWork(work);
971 pTpWaitForWork(work, FALSE);
973 result = WaitForSingleObject(semaphores[1], 100);
974 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
975 ReleaseSemaphore(semaphores[0], 1, NULL);
976 result = WaitForSingleObject(semaphores[1], 1000);
977 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
978 pTpReleaseWork(work);
980 /* test TpDisassociateCallback on work objects with group (1) */
981 work = NULL;
982 memset(&environment, 0, sizeof(environment));
983 environment.Version = 1;
984 environment.Pool = pool;
985 environment.CleanupGroup = group;
986 status = pTpAllocWork(&work, disassociate_cb, semaphores, &environment);
987 ok(!status, "TpAllocWork failed with status %x\n", status);
988 ok(work != NULL, "expected work != NULL\n");
990 pTpPostWork(work);
991 pTpWaitForWork(work, FALSE);
993 result = WaitForSingleObject(semaphores[1], 100);
994 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
995 ReleaseSemaphore(semaphores[0], 1, NULL);
996 result = WaitForSingleObject(semaphores[1], 1000);
997 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
998 pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
1000 /* test TpDisassociateCallback on work objects with group (2) */
1001 work = NULL;
1002 memset(&environment, 0, sizeof(environment));
1003 environment.Version = 1;
1004 environment.Pool = pool;
1005 environment.CleanupGroup = group;
1006 status = pTpAllocWork(&work, disassociate2_cb, semaphores, &environment);
1007 ok(!status, "TpAllocWork failed with status %x\n", status);
1008 ok(work != NULL, "expected work != NULL\n");
1010 pTpPostWork(work);
1011 pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
1013 ReleaseSemaphore(semaphores[0], 1, NULL);
1014 result = WaitForSingleObject(semaphores[1], 1000);
1015 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
1016 result = WaitForSingleObject(semaphores[0], 1000);
1017 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
1019 /* test TpDisassociateCallback on simple callbacks */
1020 memset(&environment, 0, sizeof(environment));
1021 environment.Version = 1;
1022 environment.Pool = pool;
1023 environment.CleanupGroup = group;
1024 status = pTpSimpleTryPost(disassociate3_cb, semaphores, &environment);
1025 ok(!status, "TpSimpleTryPost failed with status %x\n", status);
1027 pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
1029 ReleaseSemaphore(semaphores[0], 1, NULL);
1030 result = WaitForSingleObject(semaphores[1], 1000);
1031 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
1032 result = WaitForSingleObject(semaphores[0], 1000);
1033 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
1035 /* cleanup */
1036 pTpReleaseCleanupGroup(group);
1037 pTpReleasePool(pool);
1038 CloseHandle(semaphores[0]);
1039 CloseHandle(semaphores[1]);
1042 static void CALLBACK timer_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer)
1044 HANDLE semaphore = userdata;
1045 trace("Running timer callback\n");
1046 ReleaseSemaphore(semaphore, 1, NULL);
1049 static void test_tp_timer(void)
1051 TP_CALLBACK_ENVIRON environment;
1052 DWORD result, ticks;
1053 LARGE_INTEGER when;
1054 HANDLE semaphore;
1055 NTSTATUS status;
1056 TP_TIMER *timer;
1057 TP_POOL *pool;
1058 BOOL success;
1059 int i;
1061 semaphore = CreateSemaphoreA(NULL, 0, 1, NULL);
1062 ok(semaphore != NULL, "CreateSemaphoreA failed %u\n", GetLastError());
1064 /* allocate new threadpool */
1065 pool = NULL;
1066 status = pTpAllocPool(&pool, NULL);
1067 ok(!status, "TpAllocPool failed with status %x\n", status);
1068 ok(pool != NULL, "expected pool != NULL\n");
1070 /* allocate new timer */
1071 timer = NULL;
1072 memset(&environment, 0, sizeof(environment));
1073 environment.Version = 1;
1074 environment.Pool = pool;
1075 status = pTpAllocTimer(&timer, timer_cb, semaphore, &environment);
1076 ok(!status, "TpAllocTimer failed with status %x\n", status);
1077 ok(timer != NULL, "expected timer != NULL\n");
1079 success = pTpIsTimerSet(timer);
1080 ok(!success, "TpIsTimerSet returned TRUE\n");
1082 /* test timer with a relative timeout */
1083 when.QuadPart = (ULONGLONG)200 * -10000;
1084 pTpSetTimer(timer, &when, 0, 0);
1085 success = pTpIsTimerSet(timer);
1086 ok(success, "TpIsTimerSet returned FALSE\n");
1088 pTpWaitForTimer(timer, FALSE);
1090 result = WaitForSingleObject(semaphore, 100);
1091 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
1092 result = WaitForSingleObject(semaphore, 200);
1093 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
1094 success = pTpIsTimerSet(timer);
1095 ok(success, "TpIsTimerSet returned FALSE\n");
1097 /* test timer with an absolute timeout */
1098 NtQuerySystemTime( &when );
1099 when.QuadPart += (ULONGLONG)200 * 10000;
1100 pTpSetTimer(timer, &when, 0, 0);
1101 success = pTpIsTimerSet(timer);
1102 ok(success, "TpIsTimerSet returned FALSE\n");
1104 pTpWaitForTimer(timer, FALSE);
1106 result = WaitForSingleObject(semaphore, 100);
1107 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
1108 result = WaitForSingleObject(semaphore, 200);
1109 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
1110 success = pTpIsTimerSet(timer);
1111 ok(success, "TpIsTimerSet returned FALSE\n");
1113 /* test timer with zero timeout */
1114 when.QuadPart = 0;
1115 pTpSetTimer(timer, &when, 0, 0);
1116 success = pTpIsTimerSet(timer);
1117 ok(success, "TpIsTimerSet returned FALSE\n");
1119 pTpWaitForTimer(timer, FALSE);
1121 result = WaitForSingleObject(semaphore, 50);
1122 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
1123 success = pTpIsTimerSet(timer);
1124 ok(success, "TpIsTimerSet returned FALSE\n");
1126 /* unset the timer */
1127 pTpSetTimer(timer, NULL, 0, 0);
1128 success = pTpIsTimerSet(timer);
1129 ok(!success, "TpIsTimerSet returned TRUE\n");
1130 pTpWaitForTimer(timer, TRUE);
1132 pTpReleaseTimer(timer);
1133 CloseHandle(semaphore);
1135 semaphore = CreateSemaphoreA(NULL, 0, 3, NULL);
1136 ok(semaphore != NULL, "CreateSemaphoreA failed %u\n", GetLastError());
1138 /* allocate a new timer */
1139 timer = NULL;
1140 memset(&environment, 0, sizeof(environment));
1141 environment.Version = 1;
1142 environment.Pool = pool;
1143 status = pTpAllocTimer(&timer, timer_cb, semaphore, &environment);
1144 ok(!status, "TpAllocTimer failed with status %x\n", status);
1145 ok(timer != NULL, "expected timer != NULL\n");
1147 /* test a relative timeout repeated periodically */
1148 when.QuadPart = (ULONGLONG)200 * -10000;
1149 pTpSetTimer(timer, &when, 200, 0);
1150 success = pTpIsTimerSet(timer);
1151 ok(success, "TpIsTimerSet returned FALSE\n");
1153 /* wait until the timer was triggered three times */
1154 ticks = GetTickCount();
1155 for (i = 0; i < 3; i++)
1157 result = WaitForSingleObject(semaphore, 1000);
1158 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
1160 ticks = GetTickCount() - ticks;
1161 ok(ticks >= 500 && (ticks <= 700 || broken(ticks <= 750)) /* Win 7 */,
1162 "expected approximately 600 ticks, got %u\n", ticks);
1164 /* unset the timer */
1165 pTpSetTimer(timer, NULL, 0, 0);
1166 success = pTpIsTimerSet(timer);
1167 ok(!success, "TpIsTimerSet returned TRUE\n");
1168 pTpWaitForTimer(timer, TRUE);
1170 /* cleanup */
1171 pTpReleaseTimer(timer);
1172 pTpReleasePool(pool);
1173 CloseHandle(semaphore);
1176 struct window_length_info
1178 HANDLE semaphore;
1179 DWORD ticks;
1182 static void CALLBACK window_length_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer)
1184 struct window_length_info *info = userdata;
1185 trace("Running window length callback\n");
1186 info->ticks = GetTickCount();
1187 ReleaseSemaphore(info->semaphore, 1, NULL);
1190 static void test_tp_window_length(void)
1192 struct window_length_info info1, info2;
1193 TP_CALLBACK_ENVIRON environment;
1194 TP_TIMER *timer1, *timer2;
1195 LARGE_INTEGER when;
1196 HANDLE semaphore;
1197 NTSTATUS status;
1198 TP_POOL *pool;
1199 DWORD result;
1200 BOOL merged;
1202 semaphore = CreateSemaphoreA(NULL, 0, 2, NULL);
1203 ok(semaphore != NULL, "CreateSemaphoreA failed %u\n", GetLastError());
1205 /* allocate new threadpool */
1206 pool = NULL;
1207 status = pTpAllocPool(&pool, NULL);
1208 ok(!status, "TpAllocPool failed with status %x\n", status);
1209 ok(pool != NULL, "expected pool != NULL\n");
1211 /* allocate two identical timers */
1212 memset(&environment, 0, sizeof(environment));
1213 environment.Version = 1;
1214 environment.Pool = pool;
1216 timer1 = NULL;
1217 info1.semaphore = semaphore;
1218 status = pTpAllocTimer(&timer1, window_length_cb, &info1, &environment);
1219 ok(!status, "TpAllocTimer failed with status %x\n", status);
1220 ok(timer1 != NULL, "expected timer1 != NULL\n");
1222 timer2 = NULL;
1223 info2.semaphore = semaphore;
1224 status = pTpAllocTimer(&timer2, window_length_cb, &info2, &environment);
1225 ok(!status, "TpAllocTimer failed with status %x\n", status);
1226 ok(timer2 != NULL, "expected timer2 != NULL\n");
1228 /* choose parameters so that timers are not merged */
1229 info1.ticks = 0;
1230 info2.ticks = 0;
1232 NtQuerySystemTime( &when );
1233 when.QuadPart += (ULONGLONG)250 * 10000;
1234 pTpSetTimer(timer2, &when, 0, 0);
1235 Sleep(50);
1236 when.QuadPart -= (ULONGLONG)150 * 10000;
1237 pTpSetTimer(timer1, &when, 0, 75);
1239 result = WaitForSingleObject(semaphore, 1000);
1240 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
1241 result = WaitForSingleObject(semaphore, 1000);
1242 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
1243 ok(info1.ticks != 0 && info2.ticks != 0, "expected that ticks are nonzero\n");
1244 ok(info2.ticks >= info1.ticks + 75 || broken(info2.ticks < info1.ticks + 75) /* Win 2008 */,
1245 "expected that timers are not merged\n");
1247 /* timers will be merged */
1248 info1.ticks = 0;
1249 info2.ticks = 0;
1251 NtQuerySystemTime( &when );
1252 when.QuadPart += (ULONGLONG)250 * 10000;
1253 pTpSetTimer(timer2, &when, 0, 0);
1254 Sleep(50);
1255 when.QuadPart -= (ULONGLONG)150 * 10000;
1256 pTpSetTimer(timer1, &when, 0, 200);
1258 result = WaitForSingleObject(semaphore, 1000);
1259 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
1260 result = WaitForSingleObject(semaphore, 1000);
1261 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
1262 ok(info1.ticks != 0 && info2.ticks != 0, "expected that ticks are nonzero\n");
1263 merged = info2.ticks >= info1.ticks - 50 && info2.ticks <= info1.ticks + 50;
1264 ok(merged || broken(!merged) /* Win 10 */, "expected that timers are merged\n");
1266 /* on Windows the timers also get merged in this case */
1267 info1.ticks = 0;
1268 info2.ticks = 0;
1270 NtQuerySystemTime( &when );
1271 when.QuadPart += (ULONGLONG)100 * 10000;
1272 pTpSetTimer(timer1, &when, 0, 200);
1273 Sleep(50);
1274 when.QuadPart += (ULONGLONG)150 * 10000;
1275 pTpSetTimer(timer2, &when, 0, 0);
1277 result = WaitForSingleObject(semaphore, 1000);
1278 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
1279 result = WaitForSingleObject(semaphore, 1000);
1280 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
1281 ok(info1.ticks != 0 && info2.ticks != 0, "expected that ticks are nonzero\n");
1282 merged = info2.ticks >= info1.ticks - 50 && info2.ticks <= info1.ticks + 50;
1283 todo_wine
1284 ok(merged || broken(!merged) /* Win 10 */, "expected that timers are merged\n");
1286 /* cleanup */
1287 pTpReleaseTimer(timer1);
1288 pTpReleaseTimer(timer2);
1289 pTpReleasePool(pool);
1290 CloseHandle(semaphore);
1293 struct wait_info
1295 HANDLE semaphore;
1296 LONG userdata;
1299 static void CALLBACK wait_cb(TP_CALLBACK_INSTANCE *instance, void *userdata,
1300 TP_WAIT *wait, TP_WAIT_RESULT result)
1302 struct wait_info *info = userdata;
1303 trace("Running wait callback\n");
1305 if (result == WAIT_OBJECT_0)
1306 InterlockedIncrement(&info->userdata);
1307 else if (result == WAIT_TIMEOUT)
1308 InterlockedExchangeAdd(&info->userdata, 0x10000);
1309 else
1310 ok(0, "unexpected result %u\n", result);
1311 ReleaseSemaphore(info->semaphore, 1, NULL);
1314 static void test_tp_wait(void)
1316 TP_CALLBACK_ENVIRON environment;
1317 TP_WAIT *wait1, *wait2;
1318 struct wait_info info;
1319 HANDLE semaphores[2];
1320 LARGE_INTEGER when;
1321 NTSTATUS status;
1322 TP_POOL *pool;
1323 DWORD result;
1325 semaphores[0] = CreateSemaphoreW(NULL, 0, 2, NULL);
1326 ok(semaphores[0] != NULL, "failed to create semaphore\n");
1327 semaphores[1] = CreateSemaphoreW(NULL, 0, 1, NULL);
1328 ok(semaphores[1] != NULL, "failed to create semaphore\n");
1329 info.semaphore = semaphores[0];
1331 /* allocate new threadpool */
1332 pool = NULL;
1333 status = pTpAllocPool(&pool, NULL);
1334 ok(!status, "TpAllocPool failed with status %x\n", status);
1335 ok(pool != NULL, "expected pool != NULL\n");
1337 /* allocate new wait items */
1338 memset(&environment, 0, sizeof(environment));
1339 environment.Version = 1;
1340 environment.Pool = pool;
1342 wait1 = NULL;
1343 status = pTpAllocWait(&wait1, wait_cb, &info, &environment);
1344 ok(!status, "TpAllocWait failed with status %x\n", status);
1345 ok(wait1 != NULL, "expected wait1 != NULL\n");
1347 wait2 = NULL;
1348 status = pTpAllocWait(&wait2, wait_cb, &info, &environment);
1349 ok(!status, "TpAllocWait failed with status %x\n", status);
1350 ok(wait2 != NULL, "expected wait2 != NULL\n");
1352 /* infinite timeout, signal the semaphore immediately */
1353 info.userdata = 0;
1354 pTpSetWait(wait1, semaphores[1], NULL);
1355 ReleaseSemaphore(semaphores[1], 1, NULL);
1356 result = WaitForSingleObject(semaphores[0], 100);
1357 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
1358 ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata);
1359 result = WaitForSingleObject(semaphores[1], 0);
1360 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
1362 /* relative timeout, no event */
1363 info.userdata = 0;
1364 when.QuadPart = (ULONGLONG)200 * -10000;
1365 pTpSetWait(wait1, semaphores[1], &when);
1366 result = WaitForSingleObject(semaphores[0], 100);
1367 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
1368 ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata);
1369 result = WaitForSingleObject(semaphores[0], 200);
1370 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
1371 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata);
1372 result = WaitForSingleObject(semaphores[1], 0);
1373 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
1375 /* repeat test with call to TpWaitForWait(..., TRUE) */
1376 info.userdata = 0;
1377 when.QuadPart = (ULONGLONG)200 * -10000;
1378 pTpSetWait(wait1, semaphores[1], &when);
1379 result = WaitForSingleObject(semaphores[0], 100);
1380 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
1381 pTpWaitForWait(wait1, TRUE);
1382 ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata);
1383 result = WaitForSingleObject(semaphores[0], 200);
1384 ok(result == WAIT_OBJECT_0 || broken(result == WAIT_TIMEOUT) /* Win 8 */,
1385 "WaitForSingleObject returned %u\n", result);
1386 if (result == WAIT_OBJECT_0)
1387 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata);
1388 else
1389 ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata);
1390 result = WaitForSingleObject(semaphores[1], 0);
1391 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
1393 /* relative timeout, with event */
1394 info.userdata = 0;
1395 when.QuadPart = (ULONGLONG)200 * -10000;
1396 pTpSetWait(wait1, semaphores[1], &when);
1397 result = WaitForSingleObject(semaphores[0], 100);
1398 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
1399 ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata);
1400 ReleaseSemaphore(semaphores[1], 1, NULL);
1401 result = WaitForSingleObject(semaphores[0], 100);
1402 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
1403 ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata);
1404 result = WaitForSingleObject(semaphores[1], 0);
1405 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
1407 /* repeat test with call to TpWaitForWait(..., TRUE) */
1408 info.userdata = 0;
1409 when.QuadPart = (ULONGLONG)200 * -10000;
1410 pTpSetWait(wait1, semaphores[1], &when);
1411 result = WaitForSingleObject(semaphores[0], 100);
1412 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
1413 pTpWaitForWait(wait1, TRUE);
1414 ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata);
1415 ReleaseSemaphore(semaphores[1], 1, NULL);
1416 result = WaitForSingleObject(semaphores[0], 100);
1417 ok(result == WAIT_OBJECT_0 || broken(result == WAIT_TIMEOUT) /* Win 8 */,
1418 "WaitForSingleObject returned %u\n", result);
1419 if (result == WAIT_OBJECT_0)
1421 ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata);
1422 result = WaitForSingleObject(semaphores[1], 0);
1423 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
1425 else
1427 ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata);
1428 result = WaitForSingleObject(semaphores[1], 0);
1429 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
1432 /* absolute timeout, no event */
1433 info.userdata = 0;
1434 NtQuerySystemTime( &when );
1435 when.QuadPart += (ULONGLONG)200 * 10000;
1436 pTpSetWait(wait1, semaphores[1], &when);
1437 result = WaitForSingleObject(semaphores[0], 100);
1438 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
1439 ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata);
1440 result = WaitForSingleObject(semaphores[0], 200);
1441 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
1442 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata);
1443 result = WaitForSingleObject(semaphores[1], 0);
1444 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
1446 /* absolute timeout, with event */
1447 info.userdata = 0;
1448 NtQuerySystemTime( &when );
1449 when.QuadPart += (ULONGLONG)200 * 10000;
1450 pTpSetWait(wait1, semaphores[1], &when);
1451 result = WaitForSingleObject(semaphores[0], 100);
1452 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
1453 ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata);
1454 ReleaseSemaphore(semaphores[1], 1, NULL);
1455 result = WaitForSingleObject(semaphores[0], 100);
1456 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
1457 ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata);
1458 result = WaitForSingleObject(semaphores[1], 0);
1459 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
1461 /* test timeout of zero */
1462 info.userdata = 0;
1463 when.QuadPart = 0;
1464 pTpSetWait(wait1, semaphores[1], &when);
1465 result = WaitForSingleObject(semaphores[0], 100);
1466 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
1467 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata);
1468 result = WaitForSingleObject(semaphores[1], 0);
1469 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
1471 /* cancel a pending wait */
1472 info.userdata = 0;
1473 when.QuadPart = (ULONGLONG)250 * -10000;
1474 pTpSetWait(wait1, semaphores[1], &when);
1475 result = WaitForSingleObject(semaphores[0], 100);
1476 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
1477 pTpSetWait(wait1, NULL, (void *)0xdeadbeef);
1478 Sleep(50);
1479 ReleaseSemaphore(semaphores[1], 1, NULL);
1480 result = WaitForSingleObject(semaphores[0], 100);
1481 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
1482 ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata);
1483 result = WaitForSingleObject(semaphores[1], 0);
1484 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
1486 /* test with INVALID_HANDLE_VALUE */
1487 info.userdata = 0;
1488 when.QuadPart = 0;
1489 pTpSetWait(wait1, INVALID_HANDLE_VALUE, &when);
1490 result = WaitForSingleObject(semaphores[0], 100);
1491 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
1492 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata);
1494 /* cancel a pending wait with INVALID_HANDLE_VALUE */
1495 info.userdata = 0;
1496 when.QuadPart = (ULONGLONG)250 * -10000;
1497 pTpSetWait(wait1, semaphores[1], &when);
1498 result = WaitForSingleObject(semaphores[0], 100);
1499 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
1500 when.QuadPart = 0;
1501 pTpSetWait(wait1, INVALID_HANDLE_VALUE, &when);
1502 Sleep(50);
1503 ReleaseSemaphore(semaphores[1], 1, NULL);
1504 result = WaitForSingleObject(semaphores[0], 100);
1505 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
1506 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %u\n", info.userdata);
1507 result = WaitForSingleObject(semaphores[1], 0);
1508 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
1510 CloseHandle(semaphores[1]);
1511 semaphores[1] = CreateSemaphoreW(NULL, 0, 2, NULL);
1512 ok(semaphores[1] != NULL, "failed to create semaphore\n");
1514 /* add two wait objects with the same semaphore */
1515 info.userdata = 0;
1516 pTpSetWait(wait1, semaphores[1], NULL);
1517 pTpSetWait(wait2, semaphores[1], NULL);
1518 Sleep(50);
1519 ReleaseSemaphore(semaphores[1], 1, NULL);
1520 result = WaitForSingleObject(semaphores[0], 100);
1521 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
1522 result = WaitForSingleObject(semaphores[0], 100);
1523 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
1524 ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata);
1525 result = WaitForSingleObject(semaphores[1], 0);
1526 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
1528 /* repeat test above with release count 2 */
1529 info.userdata = 0;
1530 pTpSetWait(wait1, semaphores[1], NULL);
1531 pTpSetWait(wait2, semaphores[1], NULL);
1532 Sleep(50);
1533 result = ReleaseSemaphore(semaphores[1], 2, NULL);
1534 result = WaitForSingleObject(semaphores[0], 100);
1535 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
1536 result = WaitForSingleObject(semaphores[0], 100);
1537 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
1538 ok(info.userdata == 2, "expected info.userdata = 2, got %u\n", info.userdata);
1539 result = WaitForSingleObject(semaphores[1], 0);
1540 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
1542 /* cleanup */
1543 pTpReleaseWait(wait1);
1544 pTpReleaseWait(wait2);
1545 pTpReleasePool(pool);
1546 CloseHandle(semaphores[0]);
1547 CloseHandle(semaphores[1]);
1550 static struct
1552 HANDLE semaphore;
1553 DWORD result;
1554 } multi_wait_info;
1556 static void CALLBACK multi_wait_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WAIT *wait, TP_WAIT_RESULT result)
1558 DWORD index = (DWORD)(DWORD_PTR)userdata;
1560 if (result == WAIT_OBJECT_0)
1561 multi_wait_info.result = index;
1562 else if (result == WAIT_TIMEOUT)
1563 multi_wait_info.result = 0x10000 | index;
1564 else
1565 ok(0, "unexpected result %u\n", result);
1566 ReleaseSemaphore(multi_wait_info.semaphore, 1, NULL);
1569 static void test_tp_multi_wait(void)
1571 TP_CALLBACK_ENVIRON environment;
1572 HANDLE semaphores[512];
1573 TP_WAIT *waits[512];
1574 LARGE_INTEGER when;
1575 HANDLE semaphore;
1576 NTSTATUS status;
1577 TP_POOL *pool;
1578 DWORD result;
1579 int i;
1581 semaphore = CreateSemaphoreW(NULL, 0, 512, NULL);
1582 ok(semaphore != NULL, "failed to create semaphore\n");
1583 multi_wait_info.semaphore = semaphore;
1585 /* allocate new threadpool */
1586 pool = NULL;
1587 status = pTpAllocPool(&pool, NULL);
1588 ok(!status, "TpAllocPool failed with status %x\n", status);
1589 ok(pool != NULL, "expected pool != NULL\n");
1591 memset(&environment, 0, sizeof(environment));
1592 environment.Version = 1;
1593 environment.Pool = pool;
1595 /* create semaphores and corresponding wait objects */
1596 for (i = 0; i < sizeof(semaphores)/sizeof(semaphores[0]); i++)
1598 semaphores[i] = CreateSemaphoreW(NULL, 0, 1, NULL);
1599 ok(semaphores[i] != NULL, "failed to create semaphore %i\n", i);
1601 waits[i] = NULL;
1602 status = pTpAllocWait(&waits[i], multi_wait_cb, (void *)(DWORD_PTR)i, &environment);
1603 ok(!status, "TpAllocWait failed with status %x\n", status);
1604 ok(waits[i] != NULL, "expected waits[%d] != NULL\n", i);
1606 pTpSetWait(waits[i], semaphores[i], NULL);
1609 /* release all semaphores and wait for callback */
1610 for (i = 0; i < sizeof(semaphores)/sizeof(semaphores[0]); i++)
1612 multi_wait_info.result = 0;
1613 ReleaseSemaphore(semaphores[i], 1, NULL);
1615 result = WaitForSingleObject(semaphore, 100);
1616 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
1617 ok(multi_wait_info.result == i, "expected result %d, got %u\n", i, multi_wait_info.result);
1619 pTpSetWait(waits[i], semaphores[i], NULL);
1622 /* repeat the same test in reverse order */
1623 for (i = sizeof(semaphores)/sizeof(semaphores[0]) - 1; i >= 0; i--)
1625 multi_wait_info.result = 0;
1626 ReleaseSemaphore(semaphores[i], 1, NULL);
1628 result = WaitForSingleObject(semaphore, 100);
1629 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
1630 ok(multi_wait_info.result == i, "expected result %d, got %u\n", i, multi_wait_info.result);
1632 pTpSetWait(waits[i], semaphores[i], NULL);
1635 /* test timeout of wait objects */
1636 multi_wait_info.result = 0;
1637 for (i = 0; i < sizeof(semaphores)/sizeof(semaphores[0]); i++)
1639 when.QuadPart = (ULONGLONG)50 * -10000;
1640 pTpSetWait(waits[i], semaphores[i], &when);
1643 for (i = 0; i < sizeof(semaphores)/sizeof(semaphores[0]); i++)
1645 result = WaitForSingleObject(semaphore, 150);
1646 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
1649 ok(multi_wait_info.result >> 16, "expected multi_wait_info.result >> 16 != 0\n");
1651 /* destroy the wait objects and semaphores while waiting */
1652 for (i = 0; i < sizeof(semaphores)/sizeof(semaphores[0]); i++)
1654 pTpSetWait(waits[i], semaphores[i], NULL);
1657 Sleep(50);
1659 for (i = 0; i < sizeof(semaphores)/sizeof(semaphores[0]); i++)
1661 pTpReleaseWait(waits[i]);
1662 NtClose(semaphores[i]);
1665 pTpReleasePool(pool);
1666 CloseHandle(semaphore);
1669 START_TEST(threadpool)
1671 test_RtlQueueWorkItem();
1672 test_RtlRegisterWait();
1674 if (!init_threadpool())
1675 return;
1677 test_tp_simple();
1678 test_tp_work();
1679 test_tp_work_scheduler();
1680 test_tp_group_cancel();
1681 test_tp_instance();
1682 test_tp_disassociate();
1683 test_tp_timer();
1684 test_tp_window_length();
1685 test_tp_wait();
1686 test_tp_multi_wait();