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 }
1920