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