windows.networking.hostname/tests: Add IHostNameFactory::CreateHostName() tests.
[wine.git] / dlls / ntdll / tests / threadpool.c
blob1dd96bfd2f3b977b5fc751d8911050738eeacf95
1 /*
2 * Unit test suite for thread pool functions
4 * Copyright 2015-2016 Sebastian Lackner
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "ntdll_test.h"
23 static NTSTATUS (WINAPI *pTpAllocCleanupGroup)(TP_CLEANUP_GROUP **);
24 static NTSTATUS (WINAPI *pTpAllocIoCompletion)(TP_IO **,HANDLE,PTP_IO_CALLBACK,void *,TP_CALLBACK_ENVIRON *);
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 *pTpCancelAsyncIoOperation)(TP_IO *);
32 static VOID (WINAPI *pTpDisassociateCallback)(TP_CALLBACK_INSTANCE *);
33 static BOOL (WINAPI *pTpIsTimerSet)(TP_TIMER *);
34 static VOID (WINAPI *pTpPostWork)(TP_WORK *);
35 static NTSTATUS (WINAPI *pTpQueryPoolStackInformation)(TP_POOL *,TP_POOL_STACK_INFORMATION *);
36 static VOID (WINAPI *pTpReleaseCleanupGroup)(TP_CLEANUP_GROUP *);
37 static VOID (WINAPI *pTpReleaseCleanupGroupMembers)(TP_CLEANUP_GROUP *,BOOL,PVOID);
38 static void (WINAPI *pTpReleaseIoCompletion)(TP_IO *);
39 static VOID (WINAPI *pTpReleasePool)(TP_POOL *);
40 static VOID (WINAPI *pTpReleaseTimer)(TP_TIMER *);
41 static VOID (WINAPI *pTpReleaseWait)(TP_WAIT *);
42 static VOID (WINAPI *pTpReleaseWork)(TP_WORK *);
43 static VOID (WINAPI *pTpSetPoolMaxThreads)(TP_POOL *,DWORD);
44 static NTSTATUS (WINAPI *pTpSetPoolStackInformation)(TP_POOL *,TP_POOL_STACK_INFORMATION *);
45 static VOID (WINAPI *pTpSetTimer)(TP_TIMER *,LARGE_INTEGER *,LONG,LONG);
46 static VOID (WINAPI *pTpSetWait)(TP_WAIT *,HANDLE,LARGE_INTEGER *);
47 static NTSTATUS (WINAPI *pTpSimpleTryPost)(PTP_SIMPLE_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *);
48 static void (WINAPI *pTpStartAsyncIoOperation)(TP_IO *);
49 static void (WINAPI *pTpWaitForIoCompletion)(TP_IO *,BOOL);
50 static VOID (WINAPI *pTpWaitForTimer)(TP_TIMER *,BOOL);
51 static VOID (WINAPI *pTpWaitForWait)(TP_WAIT *,BOOL);
52 static VOID (WINAPI *pTpWaitForWork)(TP_WORK *,BOOL);
54 static void (WINAPI *pCancelThreadpoolIo)(TP_IO *);
55 static void (WINAPI *pCloseThreadpoolIo)(TP_IO *);
56 static TP_IO *(WINAPI *pCreateThreadpoolIo)(HANDLE, PTP_WIN32_IO_CALLBACK, void *, TP_CALLBACK_ENVIRON *);
57 static void (WINAPI *pStartThreadpoolIo)(TP_IO *);
58 static void (WINAPI *pWaitForThreadpoolIoCallbacks)(TP_IO *, BOOL);
60 #define GET_PROC(func) \
61 do \
62 { \
63 p ## func = (void *)GetProcAddress(module, #func); \
64 if (!p ## func) trace("Failed to get address for %s\n", #func); \
65 } \
66 while (0)
68 static BOOL init_threadpool(void)
70 HMODULE module = GetModuleHandleA("ntdll");
71 GET_PROC(TpAllocCleanupGroup);
72 GET_PROC(TpAllocIoCompletion);
73 GET_PROC(TpAllocPool);
74 GET_PROC(TpAllocTimer);
75 GET_PROC(TpAllocWait);
76 GET_PROC(TpAllocWork);
77 GET_PROC(TpCallbackMayRunLong);
78 GET_PROC(TpCallbackReleaseSemaphoreOnCompletion);
79 GET_PROC(TpCancelAsyncIoOperation);
80 GET_PROC(TpDisassociateCallback);
81 GET_PROC(TpIsTimerSet);
82 GET_PROC(TpPostWork);
83 GET_PROC(TpQueryPoolStackInformation);
84 GET_PROC(TpReleaseCleanupGroup);
85 GET_PROC(TpReleaseCleanupGroupMembers);
86 GET_PROC(TpReleaseIoCompletion);
87 GET_PROC(TpReleasePool);
88 GET_PROC(TpReleaseTimer);
89 GET_PROC(TpReleaseWait);
90 GET_PROC(TpReleaseWork);
91 GET_PROC(TpSetPoolMaxThreads);
92 GET_PROC(TpSetPoolStackInformation);
93 GET_PROC(TpSetTimer);
94 GET_PROC(TpSetWait);
95 GET_PROC(TpSimpleTryPost);
96 GET_PROC(TpStartAsyncIoOperation);
97 GET_PROC(TpWaitForIoCompletion);
98 GET_PROC(TpWaitForTimer);
99 GET_PROC(TpWaitForWait);
100 GET_PROC(TpWaitForWork);
102 module = GetModuleHandleA("kernel32");
103 GET_PROC(CancelThreadpoolIo);
104 GET_PROC(CloseThreadpoolIo);
105 GET_PROC(CreateThreadpoolIo);
106 GET_PROC(StartThreadpoolIo);
107 GET_PROC(WaitForThreadpoolIoCallbacks);
109 if (!pTpAllocPool)
111 win_skip("Threadpool functions not supported, skipping tests\n");
112 return FALSE;
115 return TRUE;
118 #undef NTDLL_GET_PROC
121 static DWORD CALLBACK rtl_work_cb(void *userdata)
123 HANDLE semaphore = userdata;
124 ReleaseSemaphore(semaphore, 1, NULL);
125 return 0;
128 static void test_RtlQueueWorkItem(void)
130 HANDLE semaphore;
131 NTSTATUS status;
132 DWORD result;
134 semaphore = CreateSemaphoreA(NULL, 0, 1, NULL);
135 ok(semaphore != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
137 status = RtlQueueWorkItem(rtl_work_cb, semaphore, WT_EXECUTEDEFAULT);
138 ok(!status, "RtlQueueWorkItem failed with status %lx\n", status);
139 result = WaitForSingleObject(semaphore, 1000);
140 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
142 status = RtlQueueWorkItem(rtl_work_cb, semaphore, WT_EXECUTEINIOTHREAD);
143 ok(!status, "RtlQueueWorkItem failed with status %lx\n", status);
144 result = WaitForSingleObject(semaphore, 1000);
145 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
147 status = RtlQueueWorkItem(rtl_work_cb, semaphore, WT_EXECUTEINPERSISTENTTHREAD);
148 ok(!status, "RtlQueueWorkItem failed with status %lx\n", status);
149 result = WaitForSingleObject(semaphore, 1000);
150 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
152 status = RtlQueueWorkItem(rtl_work_cb, semaphore, WT_EXECUTELONGFUNCTION);
153 ok(!status, "RtlQueueWorkItem failed with status %lx\n", status);
154 result = WaitForSingleObject(semaphore, 1000);
155 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
157 status = RtlQueueWorkItem(rtl_work_cb, semaphore, WT_TRANSFER_IMPERSONATION);
158 ok(!status, "RtlQueueWorkItem failed with status %lx\n", status);
159 result = WaitForSingleObject(semaphore, 1000);
160 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
162 CloseHandle(semaphore);
165 struct rtl_wait_info
167 HANDLE semaphore1;
168 HANDLE semaphore2;
169 DWORD wait_result;
170 DWORD threadid;
171 LONG userdata;
174 static void CALLBACK rtl_wait_cb(void *userdata, BOOLEAN timeout)
176 struct rtl_wait_info *info = userdata;
177 DWORD result;
179 if (!timeout)
180 InterlockedIncrement(&info->userdata);
181 else
182 InterlockedExchangeAdd(&info->userdata, 0x10000);
183 info->threadid = GetCurrentThreadId();
184 ReleaseSemaphore(info->semaphore1, 1, NULL);
186 if (info->semaphore2)
188 result = WaitForSingleObject(info->semaphore2, 200);
189 ok(result == info->wait_result, "expected %lu, got %lu\n", info->wait_result, result);
190 ReleaseSemaphore(info->semaphore1, 1, NULL);
194 static HANDLE rtl_wait_apc_semaphore;
196 static void CALLBACK rtl_wait_apc_cb(ULONG_PTR userdata)
198 if (rtl_wait_apc_semaphore)
199 ReleaseSemaphore(rtl_wait_apc_semaphore, 1, NULL);
202 static void test_RtlRegisterWait(void)
204 HANDLE wait1, event, thread;
205 struct rtl_wait_info info;
206 HANDLE semaphores[2];
207 NTSTATUS status;
208 DWORD result, threadid;
210 semaphores[0] = CreateSemaphoreW(NULL, 0, 2, NULL);
211 ok(semaphores[0] != NULL, "failed to create semaphore\n");
212 semaphores[1] = CreateSemaphoreW(NULL, 0, 1, NULL);
213 ok(semaphores[1] != NULL, "failed to create semaphore\n");
214 info.semaphore1 = semaphores[0];
215 info.semaphore2 = NULL;
217 event = CreateEventW(NULL, FALSE, FALSE, NULL);
218 ok(event != NULL, "failed to create event\n");
220 /* basic test for RtlRegisterWait and RtlDeregisterWait */
221 wait1 = NULL;
222 info.userdata = 0;
223 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT);
224 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
225 ok(wait1 != NULL, "expected wait1 != NULL\n");
226 status = RtlDeregisterWait(wait1);
227 ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
228 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
230 /* infinite timeout, signal the semaphore two times */
231 info.userdata = 0;
232 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT);
233 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
234 ReleaseSemaphore(semaphores[1], 1, NULL);
235 result = WaitForSingleObject(semaphores[0], 100);
236 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
237 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
238 ReleaseSemaphore(semaphores[1], 1, NULL);
239 result = WaitForSingleObject(semaphores[0], 100);
240 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
241 ok(info.userdata == 2, "expected info.userdata = 2, got %lu\n", info.userdata);
242 result = WaitForSingleObject(semaphores[1], 0);
243 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
244 Sleep(50);
245 status = RtlDeregisterWait(wait1);
246 ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
248 /* repeat test with WT_EXECUTEONLYONCE */
249 info.userdata = 0;
250 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEONLYONCE);
251 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
252 ReleaseSemaphore(semaphores[1], 1, NULL);
253 result = WaitForSingleObject(semaphores[0], 100);
254 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
255 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
256 ReleaseSemaphore(semaphores[1], 1, NULL);
257 result = WaitForSingleObject(semaphores[0], 100);
258 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
259 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
260 result = WaitForSingleObject(semaphores[1], 0);
261 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
262 Sleep(50);
263 status = RtlDeregisterWait(wait1);
264 ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
266 /* finite timeout, no 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 %lx\n", status);
270 result = WaitForSingleObject(semaphores[0], 100);
271 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
272 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
273 result = WaitForSingleObject(semaphores[0], 200);
274 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
275 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
276 result = WaitForSingleObject(semaphores[1], 0);
277 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
278 Sleep(50);
279 status = RtlDeregisterWait(wait1);
280 ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
282 /* finite timeout, with event */
283 info.userdata = 0;
284 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 200, WT_EXECUTEDEFAULT);
285 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
286 result = WaitForSingleObject(semaphores[0], 100);
287 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
288 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
289 ReleaseSemaphore(semaphores[1], 1, NULL);
290 result = WaitForSingleObject(semaphores[0], 100);
291 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
292 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
293 result = WaitForSingleObject(semaphores[1], 0);
294 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
295 Sleep(50);
296 status = RtlDeregisterWait(wait1);
297 ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
299 /* test RtlRegisterWait WT_EXECUTEINWAITTHREAD flag */
300 info.userdata = 0;
301 info.threadid = 0;
302 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 200, WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE);
303 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
304 ReleaseSemaphore(semaphores[1], 1, NULL);
305 result = WaitForSingleObject(semaphores[0], 200);
306 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
307 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
308 ok(info.threadid && info.threadid != GetCurrentThreadId(), "unexpected wait thread id %lx\n", info.threadid);
309 threadid = info.threadid;
310 result = WaitForSingleObject(semaphores[1], 0);
311 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
312 Sleep(50);
313 status = RtlDeregisterWait(wait1);
314 ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
316 info.userdata = 0;
317 info.threadid = 0;
318 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 200, WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE);
319 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
320 ReleaseSemaphore(semaphores[1], 1, NULL);
321 result = WaitForSingleObject(semaphores[0], 200);
322 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
323 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
324 ok(info.threadid == threadid, "unexpected different wait thread id %lx\n", info.threadid);
325 result = WaitForSingleObject(semaphores[1], 0);
326 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
327 Sleep(50);
328 status = RtlDeregisterWait(wait1);
329 ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
331 /* test RtlRegisterWait WT_EXECUTEINWAITTHREAD flag with 0 timeout */
332 info.userdata = 0;
333 info.threadid = 0;
334 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 0, WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE);
335 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
336 result = WaitForSingleObject(semaphores[0], 100);
337 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
338 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
339 ok(info.threadid == threadid, "unexpected different wait thread id %lx\n", info.threadid);
340 result = WaitForSingleObject(semaphores[1], 0);
341 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
342 Sleep(50);
343 status = RtlDeregisterWait(wait1);
344 ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
346 /* test RtlRegisterWait WT_EXECUTEINWAITTHREAD flag with already signaled event */
347 info.userdata = 0;
348 info.threadid = 0;
349 ReleaseSemaphore(semaphores[1], 1, NULL);
350 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 200, WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE);
351 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
352 result = WaitForSingleObject(semaphores[0], 200);
353 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
354 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
355 ok(info.threadid == threadid, "unexpected different wait thread id %lx\n", info.threadid);
356 result = WaitForSingleObject(semaphores[1], 0);
357 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
358 Sleep(50);
359 status = RtlDeregisterWait(wait1);
360 ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
362 /* test for IO threads */
363 info.userdata = 0;
364 info.threadid = 0;
365 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEINIOTHREAD);
366 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
367 ReleaseSemaphore(semaphores[1], 1, NULL);
368 result = WaitForSingleObject(semaphores[0], 100);
369 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
370 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
371 ok(info.threadid != 0, "expected info.threadid != 0, got %lu\n", info.threadid);
372 thread = OpenThread(THREAD_SET_CONTEXT, FALSE, info.threadid);
373 ok(thread != NULL, "OpenThread failed with %lu\n", GetLastError());
374 rtl_wait_apc_semaphore = semaphores[0];
375 result = QueueUserAPC(rtl_wait_apc_cb, thread, 0);
376 ok(result != 0, "QueueUserAPC failed with %lu\n", GetLastError());
377 result = WaitForSingleObject(semaphores[0], 200);
378 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
379 rtl_wait_apc_semaphore = 0;
380 CloseHandle(thread);
381 ReleaseSemaphore(semaphores[1], 1, NULL);
382 result = WaitForSingleObject(semaphores[0], 100);
383 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
384 ok(info.userdata == 2, "expected info.userdata = 2, got %lu\n", info.userdata);
385 Sleep(50);
386 status = RtlDeregisterWait(wait1);
387 ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
389 info.userdata = 0;
390 info.threadid = 0;
391 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT);
392 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
393 ReleaseSemaphore(semaphores[1], 1, NULL);
394 result = WaitForSingleObject(semaphores[0], 100);
395 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
396 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
397 ok(info.threadid != 0, "expected info.threadid != 0, got %lu\n", info.threadid);
398 thread = OpenThread(THREAD_SET_CONTEXT, FALSE, info.threadid);
399 ok(thread != NULL, "OpenThread failed with %lu\n", GetLastError());
400 rtl_wait_apc_semaphore = semaphores[0];
401 result = QueueUserAPC(rtl_wait_apc_cb, thread, 0);
402 ok(result != 0, "QueueUserAPC failed with %lu\n", GetLastError());
403 result = WaitForSingleObject(semaphores[0], 200);
404 ok(result == WAIT_TIMEOUT || broken(result == WAIT_OBJECT_0) /* >= Win Vista */,
405 "WaitForSingleObject returned %lu\n", result);
406 rtl_wait_apc_semaphore = 0;
407 CloseHandle(thread);
408 ReleaseSemaphore(semaphores[1], 1, NULL);
409 result = WaitForSingleObject(semaphores[0], 100);
410 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
411 ok(info.userdata == 2, "expected info.userdata = 2, got %lu\n", info.userdata);
412 Sleep(50);
413 status = RtlDeregisterWait(wait1);
414 ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
416 /* test RtlDeregisterWaitEx before wait expired */
417 info.userdata = 0;
418 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT);
419 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
420 status = RtlDeregisterWaitEx(wait1, NULL);
421 ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status);
422 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
424 info.userdata = 0;
425 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT);
426 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
427 status = RtlDeregisterWaitEx(wait1, INVALID_HANDLE_VALUE);
428 ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status);
429 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
431 info.userdata = 0;
432 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT);
433 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
434 status = RtlDeregisterWaitEx(wait1, event);
435 ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status);
436 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
437 result = WaitForSingleObject(event, 200);
438 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
440 /* test RtlDeregisterWaitEx after wait expired */
441 info.userdata = 0;
442 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 0, WT_EXECUTEONLYONCE);
443 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
444 result = WaitForSingleObject(semaphores[0], 100);
445 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
446 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
447 Sleep(50);
448 status = RtlDeregisterWaitEx(wait1, NULL);
449 ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status);
450 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
452 info.userdata = 0;
453 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 0, WT_EXECUTEONLYONCE);
454 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
455 result = WaitForSingleObject(semaphores[0], 100);
456 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
457 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
458 Sleep(50);
459 status = RtlDeregisterWaitEx(wait1, INVALID_HANDLE_VALUE);
460 ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status);
461 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
463 info.userdata = 0;
464 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 0, WT_EXECUTEONLYONCE);
465 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
466 result = WaitForSingleObject(semaphores[0], 100);
467 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
468 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
469 Sleep(50);
470 status = RtlDeregisterWaitEx(wait1, event);
471 ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status);
472 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
473 result = WaitForSingleObject(event, 200);
474 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
476 /* test RtlDeregisterWaitEx while callback is running */
477 info.semaphore2 = semaphores[1];
478 info.wait_result = WAIT_OBJECT_0;
480 info.userdata = 0;
481 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEONLYONCE);
482 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
483 ReleaseSemaphore(semaphores[1], 1, NULL);
484 result = WaitForSingleObject(semaphores[0], 1000);
485 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
486 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
487 status = RtlDeregisterWait(wait1);
488 ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %lx\n", status);
489 ReleaseSemaphore(semaphores[1], 1, NULL);
490 result = WaitForSingleObject(semaphores[0], 1000);
491 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
493 info.userdata = 0;
494 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE);
495 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
496 ReleaseSemaphore(semaphores[1], 1, NULL);
497 result = WaitForSingleObject(semaphores[0], 1000);
498 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
499 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
500 status = RtlDeregisterWait(wait1);
501 ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %lx\n", status);
502 ReleaseSemaphore(semaphores[1], 1, NULL);
503 result = WaitForSingleObject(semaphores[0], 1000);
504 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
506 info.userdata = 0;
507 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEONLYONCE);
508 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
509 ReleaseSemaphore(semaphores[1], 1, NULL);
510 result = WaitForSingleObject(semaphores[0], 1000);
511 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
512 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
513 status = RtlDeregisterWaitEx(wait1, NULL);
514 ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %lx\n", status);
515 ReleaseSemaphore(semaphores[1], 1, NULL);
516 result = WaitForSingleObject(semaphores[0], 1000);
517 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
519 info.wait_result = WAIT_TIMEOUT;
520 info.userdata = 0;
521 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEONLYONCE);
522 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
523 ReleaseSemaphore(semaphores[1], 1, NULL);
524 result = WaitForSingleObject(semaphores[0], 1000);
525 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
526 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
527 status = RtlDeregisterWaitEx(wait1, INVALID_HANDLE_VALUE);
528 ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status);
529 result = WaitForSingleObject(semaphores[0], 0);
530 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
532 info.wait_result = WAIT_TIMEOUT;
533 info.userdata = 0;
534 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE);
535 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
536 ReleaseSemaphore(semaphores[1], 1, NULL);
537 result = WaitForSingleObject(semaphores[0], 1000);
538 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
539 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
540 status = RtlDeregisterWaitEx(wait1, INVALID_HANDLE_VALUE);
541 ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status);
542 result = WaitForSingleObject(semaphores[0], 0);
543 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
545 info.wait_result = WAIT_OBJECT_0;
546 info.userdata = 0;
547 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEONLYONCE);
548 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
549 ReleaseSemaphore(semaphores[1], 1, NULL);
550 result = WaitForSingleObject(semaphores[0], 1000);
551 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
552 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
553 status = RtlDeregisterWaitEx(wait1, event);
554 ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %lx\n", status);
555 ReleaseSemaphore(semaphores[1], 1, NULL);
556 result = WaitForSingleObject(event, 1000);
557 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
558 result = WaitForSingleObject(semaphores[0], 0);
559 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
561 CloseHandle(semaphores[0]);
562 CloseHandle(semaphores[1]);
563 CloseHandle(event);
566 static void CALLBACK simple_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
568 HANDLE semaphore = userdata;
569 ReleaseSemaphore(semaphore, 1, NULL);
572 static void CALLBACK simple2_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
574 Sleep(50);
575 InterlockedIncrement((LONG *)userdata);
578 static void test_tp_simple(void)
580 IMAGE_NT_HEADERS *nt = RtlImageNtHeader( NtCurrentTeb()->Peb->ImageBaseAddress );
581 TP_POOL_STACK_INFORMATION stack_info;
582 TP_CALLBACK_ENVIRON environment;
583 TP_CALLBACK_ENVIRON_V3 environment3;
584 TP_CLEANUP_GROUP *group;
585 HANDLE semaphore;
586 NTSTATUS status;
587 TP_POOL *pool;
588 LONG userdata;
589 DWORD result;
590 int i;
592 semaphore = CreateSemaphoreA(NULL, 0, 1, NULL);
593 ok(semaphore != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
595 /* post the callback using the default threadpool */
596 memset(&environment, 0, sizeof(environment));
597 environment.Version = 1;
598 environment.Pool = NULL;
599 status = pTpSimpleTryPost(simple_cb, semaphore, &environment);
600 ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
601 result = WaitForSingleObject(semaphore, 1000);
602 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
604 /* allocate new threadpool */
605 pool = NULL;
606 status = pTpAllocPool(&pool, NULL);
607 ok(!status, "TpAllocPool failed with status %lx\n", status);
608 ok(pool != NULL, "expected pool != NULL\n");
610 /* post the callback using the new threadpool */
611 memset(&environment, 0, sizeof(environment));
612 environment.Version = 1;
613 environment.Pool = pool;
614 status = pTpSimpleTryPost(simple_cb, semaphore, &environment);
615 ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
616 result = WaitForSingleObject(semaphore, 1000);
617 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
619 /* test with environment version 3 */
620 memset(&environment3, 0, sizeof(environment3));
621 environment3.Version = 3;
622 environment3.Pool = pool;
623 environment3.Size = sizeof(environment3);
625 for (i = 0; i < 3; ++i)
627 environment3.CallbackPriority = TP_CALLBACK_PRIORITY_HIGH + i;
628 status = pTpSimpleTryPost(simple_cb, semaphore, (TP_CALLBACK_ENVIRON *)&environment3);
629 ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
630 result = WaitForSingleObject(semaphore, 1000);
631 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
634 environment3.CallbackPriority = 10;
635 status = pTpSimpleTryPost(simple_cb, semaphore, (TP_CALLBACK_ENVIRON *)&environment3);
636 ok(status == STATUS_INVALID_PARAMETER || broken(!status) /* Vista does not support priorities */,
637 "TpSimpleTryPost failed with status %lx\n", status);
639 /* test with invalid version number */
640 memset(&environment, 0, sizeof(environment));
641 environment.Version = 9999;
642 environment.Pool = pool;
643 status = pTpSimpleTryPost(simple_cb, semaphore, &environment);
644 todo_wine
645 ok(status == STATUS_INVALID_PARAMETER || broken(!status) /* Vista/2008 */,
646 "TpSimpleTryPost unexpectedly returned status %lx\n", status);
647 if (!status)
649 result = WaitForSingleObject(semaphore, 1000);
650 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
653 /* allocate a cleanup group for synchronization */
654 group = NULL;
655 status = pTpAllocCleanupGroup(&group);
656 ok(!status, "TpAllocCleanupGroup failed with status %lx\n", status);
657 ok(group != NULL, "expected pool != NULL\n");
659 /* use cleanup group to wait for a simple callback */
660 userdata = 0;
661 memset(&environment, 0, sizeof(environment));
662 environment.Version = 1;
663 environment.Pool = pool;
664 environment.CleanupGroup = group;
665 status = pTpSimpleTryPost(simple2_cb, &userdata, &environment);
666 ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
667 pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
668 ok(userdata == 1, "expected userdata = 1, got %lu\n", userdata);
670 /* test cancellation of pending simple callbacks */
671 userdata = 0;
672 pTpSetPoolMaxThreads(pool, 10);
673 memset(&environment, 0, sizeof(environment));
674 environment.Version = 1;
675 environment.Pool = pool;
676 environment.CleanupGroup = group;
677 for (i = 0; i < 100; i++)
679 status = pTpSimpleTryPost(simple2_cb, &userdata, &environment);
680 ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
682 pTpReleaseCleanupGroupMembers(group, TRUE, NULL);
683 ok(userdata < 100, "expected userdata < 100, got %lu\n", userdata);
685 /* test querying and setting the stack size */
686 status = pTpQueryPoolStackInformation(pool, &stack_info);
687 ok(!status, "TpQueryPoolStackInformation failed: %lx\n", status);
688 ok(stack_info.StackReserve == nt->OptionalHeader.SizeOfStackReserve, "expected default StackReserve, got %Ix\n", stack_info.StackReserve);
689 ok(stack_info.StackCommit == nt->OptionalHeader.SizeOfStackCommit, "expected default StackCommit, got %Ix\n", stack_info.StackCommit);
691 /* threadpool does not validate the stack size values */
692 stack_info.StackReserve = stack_info.StackCommit = 1;
693 status = pTpSetPoolStackInformation(pool, &stack_info);
694 ok(!status, "TpSetPoolStackInformation failed: %lx\n", status);
696 status = pTpQueryPoolStackInformation(pool, &stack_info);
697 ok(!status, "TpQueryPoolStackInformation failed: %lx\n", status);
698 ok(stack_info.StackReserve == 1, "expected 1 byte StackReserve, got %ld\n", (ULONG)stack_info.StackReserve);
699 ok(stack_info.StackCommit == 1, "expected 1 byte StackCommit, got %ld\n", (ULONG)stack_info.StackCommit);
701 /* cleanup */
702 pTpReleaseCleanupGroup(group);
703 pTpReleasePool(pool);
704 CloseHandle(semaphore);
707 static void CALLBACK work_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
709 Sleep(100);
710 InterlockedIncrement((LONG *)userdata);
713 static void CALLBACK work2_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
715 Sleep(100);
716 InterlockedExchangeAdd((LONG *)userdata, 0x10000);
719 static void test_tp_work(void)
721 TP_CALLBACK_ENVIRON environment;
722 TP_WORK *work;
723 TP_POOL *pool;
724 NTSTATUS status;
725 LONG userdata;
726 int i;
728 /* allocate new threadpool with only one thread */
729 pool = NULL;
730 status = pTpAllocPool(&pool, NULL);
731 ok(!status, "TpAllocPool failed with status %lx\n", status);
732 ok(pool != NULL, "expected pool != NULL\n");
733 pTpSetPoolMaxThreads(pool, 1);
735 /* allocate new work item */
736 work = NULL;
737 memset(&environment, 0, sizeof(environment));
738 environment.Version = 1;
739 environment.Pool = pool;
740 status = pTpAllocWork(&work, work_cb, &userdata, &environment);
741 ok(!status, "TpAllocWork failed with status %lx\n", status);
742 ok(work != NULL, "expected work != NULL\n");
744 /* post 5 identical work items at once */
745 userdata = 0;
746 for (i = 0; i < 5; i++)
747 pTpPostWork(work);
748 pTpWaitForWork(work, FALSE);
749 ok(userdata == 5, "expected userdata = 5, got %lu\n", userdata);
751 /* add more tasks and cancel them immediately */
752 userdata = 0;
753 for (i = 0; i < 10; i++)
754 pTpPostWork(work);
755 pTpWaitForWork(work, TRUE);
756 ok(userdata < 10, "expected userdata < 10, got %lu\n", userdata);
758 /* cleanup */
759 pTpReleaseWork(work);
760 pTpReleasePool(pool);
763 static void test_tp_work_scheduler(void)
765 TP_CALLBACK_ENVIRON environment;
766 TP_CLEANUP_GROUP *group;
767 TP_WORK *work, *work2;
768 TP_POOL *pool;
769 NTSTATUS status;
770 LONG userdata;
771 int i;
773 /* allocate new threadpool with only one thread */
774 pool = NULL;
775 status = pTpAllocPool(&pool, NULL);
776 ok(!status, "TpAllocPool failed with status %lx\n", status);
777 ok(pool != NULL, "expected pool != NULL\n");
778 pTpSetPoolMaxThreads(pool, 1);
780 /* create a cleanup group */
781 group = NULL;
782 status = pTpAllocCleanupGroup(&group);
783 ok(!status, "TpAllocCleanupGroup failed with status %lx\n", status);
784 ok(group != NULL, "expected pool != NULL\n");
786 /* the first work item has no cleanup group associated */
787 work = NULL;
788 memset(&environment, 0, sizeof(environment));
789 environment.Version = 1;
790 environment.Pool = pool;
791 status = pTpAllocWork(&work, work_cb, &userdata, &environment);
792 ok(!status, "TpAllocWork failed with status %lx\n", status);
793 ok(work != NULL, "expected work != NULL\n");
795 /* allocate a second work item with a cleanup group */
796 work2 = NULL;
797 memset(&environment, 0, sizeof(environment));
798 environment.Version = 1;
799 environment.Pool = pool;
800 environment.CleanupGroup = group;
801 status = pTpAllocWork(&work2, work2_cb, &userdata, &environment);
802 ok(!status, "TpAllocWork failed with status %lx\n", status);
803 ok(work2 != NULL, "expected work2 != NULL\n");
805 /* the 'work' callbacks are not blocking execution of 'work2' callbacks */
806 userdata = 0;
807 for (i = 0; i < 10; i++)
808 pTpPostWork(work);
809 for (i = 0; i < 10; i++)
810 pTpPostWork(work2);
811 Sleep(500);
812 pTpWaitForWork(work, TRUE);
813 pTpWaitForWork(work2, TRUE);
814 ok(userdata & 0xffff, "expected userdata & 0xffff != 0, got %lu\n", userdata & 0xffff);
815 ok(userdata >> 16, "expected userdata >> 16 != 0, got %lu\n", userdata >> 16);
817 /* test TpReleaseCleanupGroupMembers on a work item */
818 userdata = 0;
819 for (i = 0; i < 10; i++)
820 pTpPostWork(work);
821 for (i = 0; i < 3; i++)
822 pTpPostWork(work2);
823 pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
824 pTpWaitForWork(work, TRUE);
825 ok((userdata & 0xffff) < 10, "expected userdata & 0xffff < 10, got %lu\n", userdata & 0xffff);
826 ok((userdata >> 16) == 3, "expected userdata >> 16 == 3, got %lu\n", userdata >> 16);
828 /* cleanup */
829 pTpReleaseWork(work);
830 pTpReleaseCleanupGroup(group);
831 pTpReleasePool(pool);
834 static void CALLBACK simple_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
836 HANDLE *semaphores = userdata;
837 ReleaseSemaphore(semaphores, 1, NULL);
838 Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */
841 static void CALLBACK work_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
843 HANDLE semaphore = userdata;
844 ReleaseSemaphore(semaphore, 1, NULL);
845 Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */
846 pTpReleaseWork(work);
849 static void CALLBACK timer_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer)
851 HANDLE semaphore = userdata;
852 ReleaseSemaphore(semaphore, 1, NULL);
853 Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */
854 pTpReleaseTimer(timer);
857 static void CALLBACK wait_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata,
858 TP_WAIT *wait, TP_WAIT_RESULT result)
860 HANDLE semaphore = userdata;
861 ReleaseSemaphore(semaphore, 1, NULL);
862 Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */
863 pTpReleaseWait(wait);
866 static void test_tp_group_wait(void)
868 TP_CALLBACK_ENVIRON environment;
869 TP_CLEANUP_GROUP *group;
870 LARGE_INTEGER when;
871 HANDLE semaphore;
872 NTSTATUS status;
873 TP_TIMER *timer;
874 TP_WAIT *wait;
875 TP_WORK *work;
876 TP_POOL *pool;
877 DWORD result;
879 semaphore = CreateSemaphoreA(NULL, 0, 1, NULL);
880 ok(semaphore != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
882 /* allocate new threadpool */
883 pool = NULL;
884 status = pTpAllocPool(&pool, NULL);
885 ok(!status, "TpAllocPool failed with status %lx\n", status);
886 ok(pool != NULL, "expected pool != NULL\n");
888 /* allocate a cleanup group */
889 group = NULL;
890 status = pTpAllocCleanupGroup(&group);
891 ok(!status, "TpAllocCleanupGroup failed with status %lx\n", status);
892 ok(group != NULL, "expected pool != NULL\n");
894 /* release work object during TpReleaseCleanupGroupMembers */
895 work = NULL;
896 memset(&environment, 0, sizeof(environment));
897 environment.Version = 1;
898 environment.Pool = pool;
899 environment.CleanupGroup = group;
900 status = pTpAllocWork(&work, work_release_cb, semaphore, &environment);
901 ok(!status, "TpAllocWork failed with status %lx\n", status);
902 ok(work != NULL, "expected work != NULL\n");
903 pTpPostWork(work);
904 result = WaitForSingleObject(semaphore, 1000);
905 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
906 pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
908 /* release timer object during TpReleaseCleanupGroupMembers */
909 timer = NULL;
910 memset(&environment, 0, sizeof(environment));
911 environment.Version = 1;
912 environment.Pool = pool;
913 environment.CleanupGroup = group;
914 status = pTpAllocTimer(&timer, timer_release_cb, semaphore, &environment);
915 ok(!status, "TpAllocTimer failed with status %lx\n", status);
916 ok(timer != NULL, "expected timer != NULL\n");
917 when.QuadPart = 0;
918 pTpSetTimer(timer, &when, 0, 0);
919 result = WaitForSingleObject(semaphore, 1000);
920 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
921 pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
923 /* release wait object during TpReleaseCleanupGroupMembers */
924 wait = NULL;
925 memset(&environment, 0, sizeof(environment));
926 environment.Version = 1;
927 environment.Pool = pool;
928 environment.CleanupGroup = group;
929 status = pTpAllocWait(&wait, wait_release_cb, semaphore, &environment);
930 ok(!status, "TpAllocWait failed with status %lx\n", status);
931 ok(wait != NULL, "expected wait != NULL\n");
932 when.QuadPart = 0;
933 pTpSetWait(wait, INVALID_HANDLE_VALUE, &when);
934 result = WaitForSingleObject(semaphore, 1000);
935 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
936 pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
938 /* cleanup */
939 pTpReleaseCleanupGroup(group);
940 pTpReleasePool(pool);
941 CloseHandle(semaphore);
944 static DWORD group_cancel_tid;
946 static void CALLBACK simple_group_cancel_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
948 HANDLE *semaphores = userdata;
949 NTSTATUS status;
950 DWORD result;
951 int i;
953 status = pTpCallbackMayRunLong(instance);
954 ok(status == STATUS_TOO_MANY_THREADS || broken(status == 1) /* Win Vista / 2008 */,
955 "expected STATUS_TOO_MANY_THREADS, got %08lx\n", status);
957 ReleaseSemaphore(semaphores[1], 1, NULL);
958 for (i = 0; i < 4; i++)
960 result = WaitForSingleObject(semaphores[0], 1000);
961 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
963 ReleaseSemaphore(semaphores[1], 1, NULL);
966 static void CALLBACK work_group_cancel_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
968 HANDLE *semaphores = userdata;
969 DWORD result;
971 ReleaseSemaphore(semaphores[1], 1, NULL);
972 result = WaitForSingleObject(semaphores[0], 200);
973 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
976 static void CALLBACK group_cancel_cleanup_release_cb(void *object, void *userdata)
978 HANDLE *semaphores = userdata;
979 group_cancel_tid = GetCurrentThreadId();
980 ok(object == (void *)0xdeadbeef, "expected 0xdeadbeef, got %p\n", object);
981 ReleaseSemaphore(semaphores[0], 1, NULL);
984 static void CALLBACK group_cancel_cleanup_release2_cb(void *object, void *userdata)
986 HANDLE *semaphores = userdata;
987 group_cancel_tid = GetCurrentThreadId();
988 ok(object == userdata, "expected %p, got %p\n", userdata, object);
989 ReleaseSemaphore(semaphores[0], 1, NULL);
992 static void CALLBACK group_cancel_cleanup_increment_cb(void *object, void *userdata)
994 group_cancel_tid = GetCurrentThreadId();
995 InterlockedIncrement((LONG *)userdata);
998 static void CALLBACK unexpected_simple_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
1000 ok(0, "Unexpected callback\n");
1003 static void CALLBACK unexpected_work_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
1005 ok(0, "Unexpected callback\n");
1008 static void CALLBACK unexpected_timer_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer)
1010 ok(0, "Unexpected callback\n");
1013 static void CALLBACK unexpected_wait_cb(TP_CALLBACK_INSTANCE *instance, void *userdata,
1014 TP_WAIT *wait, TP_WAIT_RESULT result)
1016 ok(0, "Unexpected callback\n");
1019 static void CALLBACK unexpected_group_cancel_cleanup_cb(void *object, void *userdata)
1021 ok(0, "Unexpected callback\n");
1024 static void test_tp_group_cancel(void)
1026 TP_CALLBACK_ENVIRON environment;
1027 TP_CLEANUP_GROUP *group;
1028 LONG userdata, userdata2;
1029 HANDLE semaphores[2];
1030 NTSTATUS status;
1031 TP_TIMER *timer;
1032 TP_WAIT *wait;
1033 TP_WORK *work;
1034 TP_POOL *pool;
1035 DWORD result;
1036 int i;
1038 semaphores[0] = CreateSemaphoreA(NULL, 0, 4, NULL);
1039 ok(semaphores[0] != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
1040 semaphores[1] = CreateSemaphoreA(NULL, 0, 1, NULL);
1041 ok(semaphores[1] != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
1043 /* allocate new threadpool with only one thread */
1044 pool = NULL;
1045 status = pTpAllocPool(&pool, NULL);
1046 ok(!status, "TpAllocPool failed with status %lx\n", status);
1047 ok(pool != NULL, "expected pool != NULL\n");
1048 pTpSetPoolMaxThreads(pool, 1);
1050 /* allocate a cleanup group */
1051 group = NULL;
1052 status = pTpAllocCleanupGroup(&group);
1053 ok(!status, "TpAllocCleanupGroup failed with status %lx\n", status);
1054 ok(group != NULL, "expected pool != NULL\n");
1056 /* test execution of cancellation callback */
1057 memset(&environment, 0, sizeof(environment));
1058 environment.Version = 1;
1059 environment.Pool = pool;
1060 status = pTpSimpleTryPost(simple_group_cancel_cb, semaphores, &environment);
1061 ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
1062 result = WaitForSingleObject(semaphores[1], 1000);
1063 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1065 memset(&environment, 0, sizeof(environment));
1066 environment.Version = 1;
1067 environment.Pool = pool;
1068 environment.CleanupGroup = group;
1069 environment.CleanupGroupCancelCallback = group_cancel_cleanup_release_cb;
1070 status = pTpSimpleTryPost(unexpected_simple_cb, (void *)0xdeadbeef, &environment);
1071 ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
1073 work = NULL;
1074 status = pTpAllocWork(&work, unexpected_work_cb, (void *)0xdeadbeef, &environment);
1075 ok(!status, "TpAllocWork failed with status %lx\n", status);
1076 ok(work != NULL, "expected work != NULL\n");
1078 timer = NULL;
1079 status = pTpAllocTimer(&timer, unexpected_timer_cb, (void *)0xdeadbeef, &environment);
1080 ok(!status, "TpAllocTimer failed with status %lx\n", status);
1081 ok(timer != NULL, "expected timer != NULL\n");
1083 wait = NULL;
1084 status = pTpAllocWait(&wait, unexpected_wait_cb, (void *)0xdeadbeef, &environment);
1085 ok(!status, "TpAllocWait failed with status %lx\n", status);
1086 ok(wait != NULL, "expected wait != NULL\n");
1088 group_cancel_tid = 0xdeadbeef;
1089 pTpReleaseCleanupGroupMembers(group, TRUE, semaphores);
1090 result = WaitForSingleObject(semaphores[1], 1000);
1091 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1092 ok(group_cancel_tid == GetCurrentThreadId(), "expected tid %lx, got %lx\n",
1093 GetCurrentThreadId(), group_cancel_tid);
1095 /* test if cancellation callbacks are executed before or after wait */
1096 work = NULL;
1097 memset(&environment, 0, sizeof(environment));
1098 environment.Version = 1;
1099 environment.Pool = pool;
1100 environment.CleanupGroup = group;
1101 environment.CleanupGroupCancelCallback = group_cancel_cleanup_release2_cb;
1102 status = pTpAllocWork(&work, work_group_cancel_cb, semaphores, &environment);
1103 ok(!status, "TpAllocWork failed with status %lx\n", status);
1104 ok(work != NULL, "expected work != NULL\n");
1105 pTpPostWork(work);
1106 pTpPostWork(work);
1108 result = WaitForSingleObject(semaphores[1], 1000);
1109 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1111 group_cancel_tid = 0xdeadbeef;
1112 pTpReleaseCleanupGroupMembers(group, TRUE, semaphores);
1113 result = WaitForSingleObject(semaphores[0], 1000);
1114 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1115 ok(group_cancel_tid == GetCurrentThreadId(), "expected tid %lx, got %lx\n",
1116 GetCurrentThreadId(), group_cancel_tid);
1118 /* group cancel callback is not executed if object is destroyed while waiting */
1119 work = NULL;
1120 memset(&environment, 0, sizeof(environment));
1121 environment.Version = 1;
1122 environment.Pool = pool;
1123 environment.CleanupGroup = group;
1124 environment.CleanupGroupCancelCallback = unexpected_group_cancel_cleanup_cb;
1125 status = pTpAllocWork(&work, work_release_cb, semaphores[1], &environment);
1126 ok(!status, "TpAllocWork failed with status %lx\n", status);
1127 ok(work != NULL, "expected work != NULL\n");
1128 pTpPostWork(work);
1130 result = WaitForSingleObject(semaphores[1], 1000);
1131 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1132 pTpReleaseCleanupGroupMembers(group, TRUE, NULL);
1134 /* terminated simple callbacks should not trigger the group cancel callback */
1135 memset(&environment, 0, sizeof(environment));
1136 environment.Version = 1;
1137 environment.Pool = pool;
1138 environment.CleanupGroup = group;
1139 environment.CleanupGroupCancelCallback = unexpected_group_cancel_cleanup_cb;
1140 status = pTpSimpleTryPost(simple_release_cb, semaphores[1], &environment);
1141 ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
1142 result = WaitForSingleObject(semaphores[1], 1000);
1143 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1144 pTpReleaseCleanupGroupMembers(group, TRUE, semaphores);
1146 /* test cancellation callback for objects with multiple instances */
1147 work = NULL;
1148 memset(&environment, 0, sizeof(environment));
1149 environment.Version = 1;
1150 environment.Pool = pool;
1151 environment.CleanupGroup = group;
1152 environment.CleanupGroupCancelCallback = group_cancel_cleanup_increment_cb;
1153 status = pTpAllocWork(&work, work_cb, &userdata, &environment);
1154 ok(!status, "TpAllocWork failed with status %lx\n", status);
1155 ok(work != NULL, "expected work != NULL\n");
1157 /* post 10 identical work items at once */
1158 userdata = userdata2 = 0;
1159 for (i = 0; i < 10; i++)
1160 pTpPostWork(work);
1162 /* check if we get multiple cancellation callbacks */
1163 group_cancel_tid = 0xdeadbeef;
1164 pTpReleaseCleanupGroupMembers(group, TRUE, &userdata2);
1165 ok(userdata <= 5, "expected userdata <= 5, got %lu\n", userdata);
1166 ok(userdata2 == 1, "expected only one cancellation callback, got %lu\n", userdata2);
1167 ok(group_cancel_tid == GetCurrentThreadId(), "expected tid %lx, got %lx\n",
1168 GetCurrentThreadId(), group_cancel_tid);
1170 /* cleanup */
1171 pTpReleaseCleanupGroup(group);
1172 pTpReleasePool(pool);
1173 CloseHandle(semaphores[0]);
1174 CloseHandle(semaphores[1]);
1177 static void CALLBACK instance_semaphore_completion_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
1179 HANDLE *semaphores = userdata;
1180 pTpCallbackReleaseSemaphoreOnCompletion(instance, semaphores[0], 1);
1183 static void CALLBACK instance_finalization_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
1185 HANDLE *semaphores = userdata;
1186 ReleaseSemaphore(semaphores[1], 1, NULL);
1189 static void test_tp_instance(void)
1191 TP_CALLBACK_ENVIRON environment;
1192 HANDLE semaphores[2];
1193 NTSTATUS status;
1194 TP_POOL *pool;
1195 DWORD result;
1197 semaphores[0] = CreateSemaphoreW(NULL, 0, 1, NULL);
1198 ok(semaphores[0] != NULL, "failed to create semaphore\n");
1199 semaphores[1] = CreateSemaphoreW(NULL, 0, 1, NULL);
1200 ok(semaphores[1] != NULL, "failed to create semaphore\n");
1202 /* allocate new threadpool */
1203 pool = NULL;
1204 status = pTpAllocPool(&pool, NULL);
1205 ok(!status, "TpAllocPool failed with status %lx\n", status);
1206 ok(pool != NULL, "expected pool != NULL\n");
1208 /* test for TpCallbackReleaseSemaphoreOnCompletion */
1209 memset(&environment, 0, sizeof(environment));
1210 environment.Version = 1;
1211 environment.Pool = pool;
1212 status = pTpSimpleTryPost(instance_semaphore_completion_cb, semaphores, &environment);
1213 ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
1214 result = WaitForSingleObject(semaphores[0], 1000);
1215 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1217 /* test for finalization callback */
1218 memset(&environment, 0, sizeof(environment));
1219 environment.Version = 1;
1220 environment.Pool = pool;
1221 environment.FinalizationCallback = instance_finalization_cb;
1222 status = pTpSimpleTryPost(instance_semaphore_completion_cb, semaphores, &environment);
1223 ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
1224 result = WaitForSingleObject(semaphores[0], 1000);
1225 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1226 result = WaitForSingleObject(semaphores[1], 1000);
1227 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1229 /* cleanup */
1230 pTpReleasePool(pool);
1231 CloseHandle(semaphores[0]);
1232 CloseHandle(semaphores[1]);
1235 static void CALLBACK disassociate_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
1237 HANDLE *semaphores = userdata;
1238 DWORD result;
1240 pTpDisassociateCallback(instance);
1241 result = WaitForSingleObject(semaphores[0], 1000);
1242 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1243 ReleaseSemaphore(semaphores[1], 1, NULL);
1246 static void CALLBACK disassociate2_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
1248 HANDLE *semaphores = userdata;
1249 DWORD result;
1251 pTpDisassociateCallback(instance);
1252 result = WaitForSingleObject(semaphores[0], 100);
1253 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1254 ReleaseSemaphore(semaphores[1], 1, NULL);
1257 static void CALLBACK disassociate3_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
1259 HANDLE *semaphores = userdata;
1260 DWORD result;
1262 pTpDisassociateCallback(instance);
1263 result = WaitForSingleObject(semaphores[0], 100);
1264 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1265 ReleaseSemaphore(semaphores[1], 1, NULL);
1268 static void test_tp_disassociate(void)
1270 TP_CALLBACK_ENVIRON environment;
1271 TP_CLEANUP_GROUP *group;
1272 HANDLE semaphores[2];
1273 NTSTATUS status;
1274 TP_POOL *pool;
1275 TP_WORK *work;
1276 DWORD result;
1278 semaphores[0] = CreateSemaphoreW(NULL, 0, 1, NULL);
1279 ok(semaphores[0] != NULL, "failed to create semaphore\n");
1280 semaphores[1] = CreateSemaphoreW(NULL, 0, 1, NULL);
1281 ok(semaphores[1] != NULL, "failed to create semaphore\n");
1283 /* allocate new threadpool and cleanup group */
1284 pool = NULL;
1285 status = pTpAllocPool(&pool, NULL);
1286 ok(!status, "TpAllocPool failed with status %lx\n", status);
1287 ok(pool != NULL, "expected pool != NULL\n");
1289 group = NULL;
1290 status = pTpAllocCleanupGroup(&group);
1291 ok(!status, "TpAllocCleanupGroup failed with status %lx\n", status);
1292 ok(group != NULL, "expected pool != NULL\n");
1294 /* test TpDisassociateCallback on work objects without group */
1295 work = NULL;
1296 memset(&environment, 0, sizeof(environment));
1297 environment.Version = 1;
1298 environment.Pool = pool;
1299 status = pTpAllocWork(&work, disassociate_cb, semaphores, &environment);
1300 ok(!status, "TpAllocWork failed with status %lx\n", status);
1301 ok(work != NULL, "expected work != NULL\n");
1303 pTpPostWork(work);
1304 pTpWaitForWork(work, FALSE);
1306 result = WaitForSingleObject(semaphores[1], 100);
1307 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1308 ReleaseSemaphore(semaphores[0], 1, NULL);
1309 result = WaitForSingleObject(semaphores[1], 1000);
1310 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1311 pTpReleaseWork(work);
1313 /* test TpDisassociateCallback on work objects with group (1) */
1314 work = NULL;
1315 memset(&environment, 0, sizeof(environment));
1316 environment.Version = 1;
1317 environment.Pool = pool;
1318 environment.CleanupGroup = group;
1319 status = pTpAllocWork(&work, disassociate_cb, semaphores, &environment);
1320 ok(!status, "TpAllocWork failed with status %lx\n", status);
1321 ok(work != NULL, "expected work != NULL\n");
1323 pTpPostWork(work);
1324 pTpWaitForWork(work, FALSE);
1326 result = WaitForSingleObject(semaphores[1], 100);
1327 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1328 ReleaseSemaphore(semaphores[0], 1, NULL);
1329 result = WaitForSingleObject(semaphores[1], 1000);
1330 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1331 pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
1333 /* test TpDisassociateCallback on work objects with group (2) */
1334 work = NULL;
1335 memset(&environment, 0, sizeof(environment));
1336 environment.Version = 1;
1337 environment.Pool = pool;
1338 environment.CleanupGroup = group;
1339 status = pTpAllocWork(&work, disassociate2_cb, semaphores, &environment);
1340 ok(!status, "TpAllocWork failed with status %lx\n", status);
1341 ok(work != NULL, "expected work != NULL\n");
1343 pTpPostWork(work);
1344 pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
1346 ReleaseSemaphore(semaphores[0], 1, NULL);
1347 result = WaitForSingleObject(semaphores[1], 1000);
1348 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1349 result = WaitForSingleObject(semaphores[0], 1000);
1350 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1352 /* test TpDisassociateCallback on simple callbacks */
1353 memset(&environment, 0, sizeof(environment));
1354 environment.Version = 1;
1355 environment.Pool = pool;
1356 environment.CleanupGroup = group;
1357 status = pTpSimpleTryPost(disassociate3_cb, semaphores, &environment);
1358 ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
1360 pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
1362 ReleaseSemaphore(semaphores[0], 1, NULL);
1363 result = WaitForSingleObject(semaphores[1], 1000);
1364 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1365 result = WaitForSingleObject(semaphores[0], 1000);
1366 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1368 /* cleanup */
1369 pTpReleaseCleanupGroup(group);
1370 pTpReleasePool(pool);
1371 CloseHandle(semaphores[0]);
1372 CloseHandle(semaphores[1]);
1375 static void CALLBACK timer_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer)
1377 HANDLE semaphore = userdata;
1378 ReleaseSemaphore(semaphore, 1, NULL);
1381 static void test_tp_timer(void)
1383 TP_CALLBACK_ENVIRON environment;
1384 DWORD result, ticks;
1385 LARGE_INTEGER when;
1386 HANDLE semaphore;
1387 NTSTATUS status;
1388 TP_TIMER *timer;
1389 TP_POOL *pool;
1390 BOOL success;
1391 int i;
1393 semaphore = CreateSemaphoreA(NULL, 0, 1, NULL);
1394 ok(semaphore != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
1396 /* allocate new threadpool */
1397 pool = NULL;
1398 status = pTpAllocPool(&pool, NULL);
1399 ok(!status, "TpAllocPool failed with status %lx\n", status);
1400 ok(pool != NULL, "expected pool != NULL\n");
1402 /* allocate new timer */
1403 timer = NULL;
1404 memset(&environment, 0, sizeof(environment));
1405 environment.Version = 1;
1406 environment.Pool = pool;
1407 status = pTpAllocTimer(&timer, timer_cb, semaphore, &environment);
1408 ok(!status, "TpAllocTimer failed with status %lx\n", status);
1409 ok(timer != NULL, "expected timer != NULL\n");
1411 success = pTpIsTimerSet(timer);
1412 ok(!success, "TpIsTimerSet returned TRUE\n");
1414 /* test timer with a relative timeout */
1415 when.QuadPart = (ULONGLONG)200 * -10000;
1416 pTpSetTimer(timer, &when, 0, 0);
1417 success = pTpIsTimerSet(timer);
1418 ok(success, "TpIsTimerSet returned FALSE\n");
1420 pTpWaitForTimer(timer, FALSE);
1422 result = WaitForSingleObject(semaphore, 100);
1423 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1424 result = WaitForSingleObject(semaphore, 200);
1425 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1426 success = pTpIsTimerSet(timer);
1427 ok(success, "TpIsTimerSet returned FALSE\n");
1429 /* test timer with an absolute timeout */
1430 NtQuerySystemTime( &when );
1431 when.QuadPart += (ULONGLONG)200 * 10000;
1432 pTpSetTimer(timer, &when, 0, 0);
1433 success = pTpIsTimerSet(timer);
1434 ok(success, "TpIsTimerSet returned FALSE\n");
1436 pTpWaitForTimer(timer, FALSE);
1438 result = WaitForSingleObject(semaphore, 100);
1439 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1440 result = WaitForSingleObject(semaphore, 200);
1441 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1442 success = pTpIsTimerSet(timer);
1443 ok(success, "TpIsTimerSet returned FALSE\n");
1445 /* test timer with zero timeout */
1446 when.QuadPart = 0;
1447 pTpSetTimer(timer, &when, 0, 0);
1448 success = pTpIsTimerSet(timer);
1449 ok(success, "TpIsTimerSet returned FALSE\n");
1451 pTpWaitForTimer(timer, FALSE);
1453 result = WaitForSingleObject(semaphore, 50);
1454 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1455 success = pTpIsTimerSet(timer);
1456 ok(success, "TpIsTimerSet returned FALSE\n");
1458 /* unset the timer */
1459 pTpSetTimer(timer, NULL, 0, 0);
1460 success = pTpIsTimerSet(timer);
1461 ok(!success, "TpIsTimerSet returned TRUE\n");
1462 pTpWaitForTimer(timer, TRUE);
1464 pTpReleaseTimer(timer);
1465 CloseHandle(semaphore);
1467 semaphore = CreateSemaphoreA(NULL, 0, 3, NULL);
1468 ok(semaphore != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
1470 /* allocate a new timer */
1471 timer = NULL;
1472 memset(&environment, 0, sizeof(environment));
1473 environment.Version = 1;
1474 environment.Pool = pool;
1475 status = pTpAllocTimer(&timer, timer_cb, semaphore, &environment);
1476 ok(!status, "TpAllocTimer failed with status %lx\n", status);
1477 ok(timer != NULL, "expected timer != NULL\n");
1479 /* test a relative timeout repeated periodically */
1480 when.QuadPart = (ULONGLONG)200 * -10000;
1481 pTpSetTimer(timer, &when, 200, 0);
1482 success = pTpIsTimerSet(timer);
1483 ok(success, "TpIsTimerSet returned FALSE\n");
1485 /* wait until the timer was triggered three times */
1486 ticks = GetTickCount();
1487 for (i = 0; i < 3; i++)
1489 result = WaitForSingleObject(semaphore, 1000);
1490 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1492 ticks = GetTickCount() - ticks;
1493 ok(ticks >= 500 && (ticks <= 700 || broken(ticks <= 750)) /* Win 7 */,
1494 "expected approximately 600 ticks, got %lu\n", ticks);
1496 /* unset the timer */
1497 pTpSetTimer(timer, NULL, 0, 0);
1498 success = pTpIsTimerSet(timer);
1499 ok(!success, "TpIsTimerSet returned TRUE\n");
1500 pTpWaitForTimer(timer, TRUE);
1502 /* cleanup */
1503 pTpReleaseTimer(timer);
1504 pTpReleasePool(pool);
1505 CloseHandle(semaphore);
1508 struct window_length_info
1510 HANDLE semaphore;
1511 DWORD ticks;
1514 static void CALLBACK window_length_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer)
1516 struct window_length_info *info = userdata;
1517 info->ticks = GetTickCount();
1518 ReleaseSemaphore(info->semaphore, 1, NULL);
1521 static void test_tp_window_length(void)
1523 struct window_length_info info1, info2;
1524 TP_CALLBACK_ENVIRON environment;
1525 TP_TIMER *timer1, *timer2;
1526 LARGE_INTEGER when;
1527 HANDLE semaphore;
1528 NTSTATUS status;
1529 TP_POOL *pool;
1530 DWORD result;
1531 BOOL merged;
1533 semaphore = CreateSemaphoreA(NULL, 0, 2, NULL);
1534 ok(semaphore != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
1536 /* allocate new threadpool */
1537 pool = NULL;
1538 status = pTpAllocPool(&pool, NULL);
1539 ok(!status, "TpAllocPool failed with status %lx\n", status);
1540 ok(pool != NULL, "expected pool != NULL\n");
1542 /* allocate two identical timers */
1543 memset(&environment, 0, sizeof(environment));
1544 environment.Version = 1;
1545 environment.Pool = pool;
1547 timer1 = NULL;
1548 info1.semaphore = semaphore;
1549 status = pTpAllocTimer(&timer1, window_length_cb, &info1, &environment);
1550 ok(!status, "TpAllocTimer failed with status %lx\n", status);
1551 ok(timer1 != NULL, "expected timer1 != NULL\n");
1553 timer2 = NULL;
1554 info2.semaphore = semaphore;
1555 status = pTpAllocTimer(&timer2, window_length_cb, &info2, &environment);
1556 ok(!status, "TpAllocTimer failed with status %lx\n", status);
1557 ok(timer2 != NULL, "expected timer2 != NULL\n");
1559 /* choose parameters so that timers are not merged */
1560 info1.ticks = 0;
1561 info2.ticks = 0;
1563 NtQuerySystemTime( &when );
1564 when.QuadPart += (ULONGLONG)250 * 10000;
1565 pTpSetTimer(timer2, &when, 0, 0);
1566 Sleep(50);
1567 when.QuadPart -= (ULONGLONG)150 * 10000;
1568 pTpSetTimer(timer1, &when, 0, 75);
1570 result = WaitForSingleObject(semaphore, 1000);
1571 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1572 result = WaitForSingleObject(semaphore, 1000);
1573 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1574 ok(info1.ticks != 0 && info2.ticks != 0, "expected that ticks are nonzero\n");
1575 ok(info2.ticks >= info1.ticks + 75 || broken(info2.ticks < info1.ticks + 75) /* Win 2008 */,
1576 "expected that timers are not merged\n");
1578 /* timers will be merged */
1579 info1.ticks = 0;
1580 info2.ticks = 0;
1582 NtQuerySystemTime( &when );
1583 when.QuadPart += (ULONGLONG)250 * 10000;
1584 pTpSetTimer(timer2, &when, 0, 0);
1585 Sleep(50);
1586 when.QuadPart -= (ULONGLONG)150 * 10000;
1587 pTpSetTimer(timer1, &when, 0, 200);
1589 result = WaitForSingleObject(semaphore, 1000);
1590 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1591 result = WaitForSingleObject(semaphore, 1000);
1592 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1593 ok(info1.ticks != 0 && info2.ticks != 0, "expected that ticks are nonzero\n");
1594 merged = info2.ticks >= info1.ticks - 50 && info2.ticks <= info1.ticks + 50;
1595 ok(merged || broken(!merged) /* Win 10 */, "expected that timers are merged\n");
1597 /* on Windows the timers also get merged in this case */
1598 info1.ticks = 0;
1599 info2.ticks = 0;
1601 NtQuerySystemTime( &when );
1602 when.QuadPart += (ULONGLONG)100 * 10000;
1603 pTpSetTimer(timer1, &when, 0, 200);
1604 Sleep(50);
1605 when.QuadPart += (ULONGLONG)150 * 10000;
1606 pTpSetTimer(timer2, &when, 0, 0);
1608 result = WaitForSingleObject(semaphore, 1000);
1609 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1610 result = WaitForSingleObject(semaphore, 1000);
1611 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1612 ok(info1.ticks != 0 && info2.ticks != 0, "expected that ticks are nonzero\n");
1613 merged = info2.ticks >= info1.ticks - 50 && info2.ticks <= info1.ticks + 50;
1614 todo_wine
1615 ok(merged || broken(!merged) /* Win 10 */, "expected that timers are merged\n");
1617 /* cleanup */
1618 pTpReleaseTimer(timer1);
1619 pTpReleaseTimer(timer2);
1620 pTpReleasePool(pool);
1621 CloseHandle(semaphore);
1624 struct wait_info
1626 HANDLE semaphore;
1627 LONG userdata;
1630 static void CALLBACK wait_cb(TP_CALLBACK_INSTANCE *instance, void *userdata,
1631 TP_WAIT *wait, TP_WAIT_RESULT result)
1633 struct wait_info *info = userdata;
1634 if (result == WAIT_OBJECT_0)
1635 InterlockedIncrement(&info->userdata);
1636 else if (result == WAIT_TIMEOUT)
1637 InterlockedExchangeAdd(&info->userdata, 0x10000);
1638 else
1639 ok(0, "unexpected result %lu\n", result);
1640 ReleaseSemaphore(info->semaphore, 1, NULL);
1643 static void test_tp_wait(void)
1645 TP_CALLBACK_ENVIRON environment;
1646 TP_WAIT *wait1, *wait2;
1647 struct wait_info info;
1648 HANDLE semaphores[2];
1649 LARGE_INTEGER when;
1650 NTSTATUS status;
1651 TP_POOL *pool;
1652 DWORD result;
1654 semaphores[0] = CreateSemaphoreW(NULL, 0, 2, NULL);
1655 ok(semaphores[0] != NULL, "failed to create semaphore\n");
1656 semaphores[1] = CreateSemaphoreW(NULL, 0, 1, NULL);
1657 ok(semaphores[1] != NULL, "failed to create semaphore\n");
1658 info.semaphore = semaphores[0];
1660 /* allocate new threadpool */
1661 pool = NULL;
1662 status = pTpAllocPool(&pool, NULL);
1663 ok(!status, "TpAllocPool failed with status %lx\n", status);
1664 ok(pool != NULL, "expected pool != NULL\n");
1666 /* allocate new wait items */
1667 memset(&environment, 0, sizeof(environment));
1668 environment.Version = 1;
1669 environment.Pool = pool;
1671 wait1 = NULL;
1672 status = pTpAllocWait(&wait1, wait_cb, &info, &environment);
1673 ok(!status, "TpAllocWait failed with status %lx\n", status);
1674 ok(wait1 != NULL, "expected wait1 != NULL\n");
1676 wait2 = NULL;
1677 status = pTpAllocWait(&wait2, wait_cb, &info, &environment);
1678 ok(!status, "TpAllocWait failed with status %lx\n", status);
1679 ok(wait2 != NULL, "expected wait2 != NULL\n");
1681 /* infinite timeout, signal the semaphore immediately */
1682 info.userdata = 0;
1683 pTpSetWait(wait1, semaphores[1], NULL);
1684 ReleaseSemaphore(semaphores[1], 1, NULL);
1685 result = WaitForSingleObject(semaphores[0], 100);
1686 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1687 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
1688 result = WaitForSingleObject(semaphores[1], 0);
1689 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1691 /* relative timeout, no event */
1692 info.userdata = 0;
1693 when.QuadPart = (ULONGLONG)200 * -10000;
1694 pTpSetWait(wait1, semaphores[1], &when);
1695 result = WaitForSingleObject(semaphores[0], 100);
1696 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1697 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
1698 result = WaitForSingleObject(semaphores[0], 200);
1699 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1700 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
1701 result = WaitForSingleObject(semaphores[1], 0);
1702 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1704 /* repeat test with call to TpWaitForWait(..., TRUE) */
1705 info.userdata = 0;
1706 when.QuadPart = (ULONGLONG)200 * -10000;
1707 pTpSetWait(wait1, semaphores[1], &when);
1708 result = WaitForSingleObject(semaphores[0], 100);
1709 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1710 pTpWaitForWait(wait1, TRUE);
1711 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
1712 result = WaitForSingleObject(semaphores[0], 200);
1713 ok(result == WAIT_OBJECT_0 || broken(result == WAIT_TIMEOUT) /* Win 8 */,
1714 "WaitForSingleObject returned %lu\n", result);
1715 if (result == WAIT_OBJECT_0)
1716 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
1717 else
1718 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
1719 result = WaitForSingleObject(semaphores[1], 0);
1720 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1722 /* relative timeout, with event */
1723 info.userdata = 0;
1724 when.QuadPart = (ULONGLONG)200 * -10000;
1725 pTpSetWait(wait1, semaphores[1], &when);
1726 result = WaitForSingleObject(semaphores[0], 100);
1727 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1728 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
1729 ReleaseSemaphore(semaphores[1], 1, NULL);
1730 result = WaitForSingleObject(semaphores[0], 100);
1731 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1732 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
1733 result = WaitForSingleObject(semaphores[1], 0);
1734 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1736 /* repeat test with call to TpWaitForWait(..., TRUE) */
1737 info.userdata = 0;
1738 when.QuadPart = (ULONGLONG)200 * -10000;
1739 pTpSetWait(wait1, semaphores[1], &when);
1740 result = WaitForSingleObject(semaphores[0], 100);
1741 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1742 pTpWaitForWait(wait1, TRUE);
1743 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
1744 ReleaseSemaphore(semaphores[1], 1, NULL);
1745 result = WaitForSingleObject(semaphores[0], 100);
1746 ok(result == WAIT_OBJECT_0 || broken(result == WAIT_TIMEOUT) /* Win 8 */,
1747 "WaitForSingleObject returned %lu\n", result);
1748 if (result == WAIT_OBJECT_0)
1750 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
1751 result = WaitForSingleObject(semaphores[1], 0);
1752 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1754 else
1756 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
1757 result = WaitForSingleObject(semaphores[1], 0);
1758 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1761 /* absolute timeout, no event */
1762 info.userdata = 0;
1763 NtQuerySystemTime( &when );
1764 when.QuadPart += (ULONGLONG)200 * 10000;
1765 pTpSetWait(wait1, semaphores[1], &when);
1766 result = WaitForSingleObject(semaphores[0], 100);
1767 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1768 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
1769 result = WaitForSingleObject(semaphores[0], 200);
1770 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1771 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
1772 result = WaitForSingleObject(semaphores[1], 0);
1773 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1775 /* absolute timeout, with event */
1776 info.userdata = 0;
1777 NtQuerySystemTime( &when );
1778 when.QuadPart += (ULONGLONG)200 * 10000;
1779 pTpSetWait(wait1, semaphores[1], &when);
1780 result = WaitForSingleObject(semaphores[0], 100);
1781 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1782 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
1783 ReleaseSemaphore(semaphores[1], 1, NULL);
1784 result = WaitForSingleObject(semaphores[0], 100);
1785 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1786 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
1787 result = WaitForSingleObject(semaphores[1], 0);
1788 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1790 /* test timeout of zero */
1791 info.userdata = 0;
1792 when.QuadPart = 0;
1793 pTpSetWait(wait1, semaphores[1], &when);
1794 result = WaitForSingleObject(semaphores[0], 100);
1795 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1796 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
1797 result = WaitForSingleObject(semaphores[1], 0);
1798 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1800 /* cancel a pending wait */
1801 info.userdata = 0;
1802 when.QuadPart = (ULONGLONG)250 * -10000;
1803 pTpSetWait(wait1, semaphores[1], &when);
1804 result = WaitForSingleObject(semaphores[0], 100);
1805 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1806 pTpSetWait(wait1, NULL, (void *)0xdeadbeef);
1807 Sleep(50);
1808 ReleaseSemaphore(semaphores[1], 1, NULL);
1809 result = WaitForSingleObject(semaphores[0], 100);
1810 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1811 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
1812 result = WaitForSingleObject(semaphores[1], 0);
1813 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1815 /* test with INVALID_HANDLE_VALUE */
1816 info.userdata = 0;
1817 when.QuadPart = 0;
1818 pTpSetWait(wait1, INVALID_HANDLE_VALUE, &when);
1819 result = WaitForSingleObject(semaphores[0], 100);
1820 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1821 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
1823 /* cancel a pending wait with INVALID_HANDLE_VALUE */
1824 info.userdata = 0;
1825 when.QuadPart = (ULONGLONG)250 * -10000;
1826 pTpSetWait(wait1, semaphores[1], &when);
1827 result = WaitForSingleObject(semaphores[0], 100);
1828 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1829 when.QuadPart = 0;
1830 pTpSetWait(wait1, INVALID_HANDLE_VALUE, &when);
1831 Sleep(50);
1832 ReleaseSemaphore(semaphores[1], 1, NULL);
1833 result = WaitForSingleObject(semaphores[0], 100);
1834 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1835 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
1836 result = WaitForSingleObject(semaphores[1], 0);
1837 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1839 CloseHandle(semaphores[1]);
1840 semaphores[1] = CreateSemaphoreW(NULL, 0, 2, NULL);
1841 ok(semaphores[1] != NULL, "failed to create semaphore\n");
1843 /* add two wait objects with the same semaphore */
1844 info.userdata = 0;
1845 pTpSetWait(wait1, semaphores[1], NULL);
1846 pTpSetWait(wait2, semaphores[1], NULL);
1847 Sleep(50);
1848 ReleaseSemaphore(semaphores[1], 1, NULL);
1849 result = WaitForSingleObject(semaphores[0], 100);
1850 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1851 result = WaitForSingleObject(semaphores[0], 100);
1852 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1853 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
1854 result = WaitForSingleObject(semaphores[1], 0);
1855 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1857 /* repeat test above with release count 2 */
1858 info.userdata = 0;
1859 pTpSetWait(wait1, semaphores[1], NULL);
1860 pTpSetWait(wait2, semaphores[1], NULL);
1861 Sleep(50);
1862 result = ReleaseSemaphore(semaphores[1], 2, NULL);
1863 result = WaitForSingleObject(semaphores[0], 100);
1864 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1865 result = WaitForSingleObject(semaphores[0], 100);
1866 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1867 ok(info.userdata == 2, "expected info.userdata = 2, got %lu\n", info.userdata);
1868 result = WaitForSingleObject(semaphores[1], 0);
1869 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1871 /* cleanup */
1872 pTpReleaseWait(wait1);
1873 pTpReleaseWait(wait2);
1874 pTpReleasePool(pool);
1875 CloseHandle(semaphores[0]);
1876 CloseHandle(semaphores[1]);
1879 static struct
1881 HANDLE semaphore;
1882 DWORD result;
1883 } multi_wait_info;
1885 static void CALLBACK multi_wait_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WAIT *wait, TP_WAIT_RESULT result)
1887 DWORD index = (DWORD)(DWORD_PTR)userdata;
1889 if (result == WAIT_OBJECT_0)
1890 multi_wait_info.result = index;
1891 else if (result == WAIT_TIMEOUT)
1892 multi_wait_info.result = 0x10000 | index;
1893 else
1894 ok(0, "unexpected result %lu\n", result);
1895 ReleaseSemaphore(multi_wait_info.semaphore, 1, NULL);
1898 static void test_tp_multi_wait(void)
1900 TP_POOL_STACK_INFORMATION stack_info;
1901 TP_CALLBACK_ENVIRON environment;
1902 HANDLE semaphores[512];
1903 TP_WAIT *waits[512];
1904 LARGE_INTEGER when;
1905 HANDLE semaphore;
1906 NTSTATUS status;
1907 TP_POOL *pool;
1908 DWORD result;
1909 int i;
1911 semaphore = CreateSemaphoreW(NULL, 0, 512, NULL);
1912 ok(semaphore != NULL, "failed to create semaphore\n");
1913 multi_wait_info.semaphore = semaphore;
1915 /* allocate new threadpool */
1916 pool = NULL;
1917 status = pTpAllocPool(&pool, NULL);
1918 ok(!status, "TpAllocPool failed with status %lx\n", status);
1919 ok(pool != NULL, "expected pool != NULL\n");
1920 /* many threads -> use the smallest stack possible */
1921 stack_info.StackReserve = 256 * 1024;
1922 stack_info.StackCommit = 4 * 1024;
1923 status = pTpSetPoolStackInformation(pool, &stack_info);
1924 ok(!status, "TpQueryPoolStackInformation failed: %lx\n", status);
1926 memset(&environment, 0, sizeof(environment));
1927 environment.Version = 1;
1928 environment.Pool = pool;
1930 /* create semaphores and corresponding wait objects */
1931 for (i = 0; i < ARRAY_SIZE(semaphores); i++)
1933 semaphores[i] = CreateSemaphoreW(NULL, 0, 1, NULL);
1934 ok(semaphores[i] != NULL, "failed to create semaphore %i\n", i);
1936 waits[i] = NULL;
1937 status = pTpAllocWait(&waits[i], multi_wait_cb, (void *)(DWORD_PTR)i, &environment);
1938 ok(!status, "TpAllocWait failed with status %lx\n", status);
1939 ok(waits[i] != NULL, "expected waits[%d] != NULL\n", i);
1941 pTpSetWait(waits[i], semaphores[i], NULL);
1944 /* release all semaphores and wait for callback */
1945 for (i = 0; i < ARRAY_SIZE(semaphores); i++)
1947 multi_wait_info.result = 0;
1948 ReleaseSemaphore(semaphores[i], 1, NULL);
1950 result = WaitForSingleObject(semaphore, 2000);
1951 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1952 ok(multi_wait_info.result == i, "expected result %d, got %lu\n", i, multi_wait_info.result);
1954 pTpSetWait(waits[i], semaphores[i], NULL);
1957 /* repeat the same test in reverse order */
1958 for (i = ARRAY_SIZE(semaphores) - 1; i >= 0; i--)
1960 multi_wait_info.result = 0;
1961 ReleaseSemaphore(semaphores[i], 1, NULL);
1963 result = WaitForSingleObject(semaphore, 2000);
1964 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1965 ok(multi_wait_info.result == i, "expected result %d, got %lu\n", i, multi_wait_info.result);
1967 pTpSetWait(waits[i], semaphores[i], NULL);
1970 /* test timeout of wait objects */
1971 multi_wait_info.result = 0;
1972 for (i = 0; i < ARRAY_SIZE(semaphores); i++)
1974 when.QuadPart = (ULONGLONG)50 * -10000;
1975 pTpSetWait(waits[i], semaphores[i], &when);
1978 for (i = 0; i < ARRAY_SIZE(semaphores); i++)
1980 result = WaitForSingleObject(semaphore, 2000);
1981 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1984 ok(multi_wait_info.result >> 16, "expected multi_wait_info.result >> 16 != 0\n");
1986 /* destroy the wait objects and semaphores while waiting */
1987 for (i = 0; i < ARRAY_SIZE(semaphores); i++)
1989 pTpSetWait(waits[i], semaphores[i], NULL);
1992 Sleep(50);
1994 for (i = 0; i < ARRAY_SIZE(semaphores); i++)
1996 pTpReleaseWait(waits[i]);
1997 NtClose(semaphores[i]);
2000 pTpReleasePool(pool);
2001 CloseHandle(semaphore);
2004 struct io_cb_ctx
2006 unsigned int count;
2007 void *ovl;
2008 NTSTATUS ret;
2009 ULONG_PTR length;
2010 TP_IO *io;
2013 static void CALLBACK io_cb(TP_CALLBACK_INSTANCE *instance, void *userdata,
2014 void *cvalue, IO_STATUS_BLOCK *iosb, TP_IO *io)
2016 struct io_cb_ctx *ctx = userdata;
2017 ++ctx->count;
2018 ctx->ovl = cvalue;
2019 ctx->ret = iosb->Status;
2020 ctx->length = iosb->Information;
2021 ctx->io = io;
2024 static DWORD WINAPI io_wait_thread(void *arg)
2026 TP_IO *io = arg;
2027 pTpWaitForIoCompletion(io, FALSE);
2028 return 0;
2031 static void test_tp_io(void)
2033 TP_CALLBACK_ENVIRON environment = {.Version = 1};
2034 OVERLAPPED ovl = {}, ovl2 = {};
2035 HANDLE client, server, thread;
2036 struct io_cb_ctx userdata;
2037 char in[1], in2[1];
2038 const char out[1];
2039 NTSTATUS status;
2040 DWORD ret_size;
2041 TP_POOL *pool;
2042 TP_IO *io;
2043 BOOL ret;
2045 ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
2047 status = pTpAllocPool(&pool, NULL);
2048 ok(!status, "failed to allocate pool, status %#lx\n", status);
2050 server = CreateNamedPipeA("\\\\.\\pipe\\wine_tp_test",
2051 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0, 1, 1024, 1024, 0, NULL);
2052 ok(server != INVALID_HANDLE_VALUE, "Failed to create server pipe, error %lu.\n", GetLastError());
2053 client = CreateFileA("\\\\.\\pipe\\wine_tp_test", GENERIC_READ | GENERIC_WRITE,
2054 0, NULL, OPEN_EXISTING, 0, 0);
2055 ok(client != INVALID_HANDLE_VALUE, "Failed to create client pipe, error %lu.\n", GetLastError());
2057 environment.Pool = pool;
2058 io = NULL;
2059 status = pTpAllocIoCompletion(&io, server, io_cb, &userdata, &environment);
2060 ok(!status, "got %#lx\n", status);
2061 ok(!!io, "expected non-NULL TP_IO\n");
2063 pTpWaitForIoCompletion(io, FALSE);
2065 userdata.count = 0;
2066 pTpStartAsyncIoOperation(io);
2068 thread = CreateThread(NULL, 0, io_wait_thread, io, 0, NULL);
2069 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "TpWaitForIoCompletion() should not return\n");
2071 ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
2072 ok(!ret, "wrong ret %d\n", ret);
2073 ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError());
2075 ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
2076 ok(ret, "WriteFile() failed, error %lu\n", GetLastError());
2078 pTpWaitForIoCompletion(io, FALSE);
2079 ok(userdata.count == 1, "callback ran %u times\n", userdata.count);
2080 ok(userdata.ovl == &ovl, "expected %p, got %p\n", &ovl, userdata.ovl);
2081 ok(userdata.ret == STATUS_SUCCESS, "got status %#lx\n", userdata.ret);
2082 ok(userdata.length == 1, "got length %Iu\n", userdata.length);
2083 ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io);
2085 ok(!WaitForSingleObject(thread, 1000), "wait timed out\n");
2086 CloseHandle(thread);
2088 userdata.count = 0;
2089 pTpStartAsyncIoOperation(io);
2090 pTpStartAsyncIoOperation(io);
2092 ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
2093 ok(!ret, "wrong ret %d\n", ret);
2094 ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError());
2095 ret = ReadFile(server, in2, sizeof(in2), NULL, &ovl2);
2096 ok(!ret, "wrong ret %d\n", ret);
2097 ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError());
2099 ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
2100 ok(ret, "WriteFile() failed, error %lu\n", GetLastError());
2101 ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
2102 ok(ret, "WriteFile() failed, error %lu\n", GetLastError());
2104 pTpWaitForIoCompletion(io, FALSE);
2105 ok(userdata.count == 2, "callback ran %u times\n", userdata.count);
2106 ok(userdata.ret == STATUS_SUCCESS, "got status %#lx\n", userdata.ret);
2107 ok(userdata.length == 1, "got length %Iu\n", userdata.length);
2108 ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io);
2110 /* The documentation is a bit unclear about passing TRUE to
2111 * WaitForThreadpoolIoCallbacks()—"pending I/O requests are not canceled"
2112 * [as with CancelIoEx()], but pending threadpool callbacks are, even those
2113 * which have not yet reached the completion port [as with
2114 * TpCancelAsyncIoOperation()]. */
2115 userdata.count = 0;
2116 pTpStartAsyncIoOperation(io);
2118 pTpWaitForIoCompletion(io, TRUE);
2119 ok(!userdata.count, "callback ran %u times\n", userdata.count);
2121 pTpStartAsyncIoOperation(io);
2123 ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
2124 ok(ret, "WriteFile() failed, error %lu\n", GetLastError());
2126 ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
2127 ok(ret, "wrong ret %d\n", ret);
2129 pTpWaitForIoCompletion(io, FALSE);
2130 ok(userdata.count == 1, "callback ran %u times\n", userdata.count);
2131 ok(userdata.ovl == &ovl, "expected %p, got %p\n", &ovl, userdata.ovl);
2132 ok(userdata.ret == STATUS_SUCCESS, "got status %#lx\n", userdata.ret);
2133 ok(userdata.length == 1, "got length %Iu\n", userdata.length);
2134 ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io);
2136 userdata.count = 0;
2137 pTpStartAsyncIoOperation(io);
2139 ret = ReadFile(server, NULL, 1, NULL, &ovl);
2140 ok(!ret, "wrong ret %d\n", ret);
2141 ok(GetLastError() == ERROR_NOACCESS, "wrong error %lu\n", GetLastError());
2143 pTpCancelAsyncIoOperation(io);
2144 pTpWaitForIoCompletion(io, FALSE);
2145 ok(!userdata.count, "callback ran %u times\n", userdata.count);
2147 userdata.count = 0;
2148 pTpStartAsyncIoOperation(io);
2150 ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
2151 ok(!ret, "wrong ret %d\n", ret);
2152 ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError());
2153 ret = CancelIo(server);
2154 ok(ret, "CancelIo() failed, error %lu\n", GetLastError());
2156 pTpWaitForIoCompletion(io, FALSE);
2157 ok(userdata.count == 1, "callback ran %u times\n", userdata.count);
2158 ok(userdata.ovl == &ovl, "expected %p, got %p\n", &ovl, userdata.ovl);
2159 ok(userdata.ret == STATUS_CANCELLED, "got status %#lx\n", userdata.ret);
2160 ok(!userdata.length, "got length %Iu\n", userdata.length);
2161 ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io);
2163 userdata.count = 0;
2164 pTpStartAsyncIoOperation(io);
2165 pTpCancelAsyncIoOperation(io);
2166 ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
2167 ok(!ret, "wrong ret %d\n", ret);
2168 ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
2169 ok(ret, "WriteFile() failed, error %lu\n", GetLastError());
2170 ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError());
2172 pTpWaitForIoCompletion(io, FALSE);
2173 if (0)
2175 /* Add a sleep to check that callback is not called later. Commented out to
2176 * save the test time. */
2177 Sleep(200);
2179 ok(userdata.count == 0, "callback ran %u times\n", userdata.count);
2181 pTpReleaseIoCompletion(io);
2182 CloseHandle(server);
2184 /* Test TPIO object destruction. */
2185 server = CreateNamedPipeA("\\\\.\\pipe\\wine_tp_test",
2186 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0, 1, 1024, 1024, 0, NULL);
2187 ok(server != INVALID_HANDLE_VALUE, "Failed to create server pipe, error %lu.\n", GetLastError());
2188 io = NULL;
2189 status = pTpAllocIoCompletion(&io, server, io_cb, &userdata, &environment);
2190 ok(!status, "got %#lx\n", status);
2192 ret = HeapValidate(GetProcessHeap(), 0, io);
2193 ok(ret, "Got unexpected ret %#x.\n", ret);
2194 pTpReleaseIoCompletion(io);
2195 ret = HeapValidate(GetProcessHeap(), 0, io);
2196 ok(!ret, "Got unexpected ret %#x.\n", ret);
2197 CloseHandle(server);
2198 CloseHandle(client);
2200 server = CreateNamedPipeA("\\\\.\\pipe\\wine_tp_test",
2201 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0, 1, 1024, 1024, 0, NULL);
2202 ok(server != INVALID_HANDLE_VALUE, "Failed to create server pipe, error %lu.\n", GetLastError());
2203 client = CreateFileA("\\\\.\\pipe\\wine_tp_test", GENERIC_READ | GENERIC_WRITE,
2204 0, NULL, OPEN_EXISTING, 0, 0);
2205 ok(client != INVALID_HANDLE_VALUE, "Failed to create client pipe, error %lu.\n", GetLastError());
2207 io = NULL;
2208 status = pTpAllocIoCompletion(&io, server, io_cb, &userdata, &environment);
2209 ok(!status, "got %#lx\n", status);
2210 pTpStartAsyncIoOperation(io);
2211 pTpWaitForIoCompletion(io, TRUE);
2212 ret = HeapValidate(GetProcessHeap(), 0, io);
2213 ok(ret, "Got unexpected ret %#x.\n", ret);
2214 pTpReleaseIoCompletion(io);
2215 ret = HeapValidate(GetProcessHeap(), 0, io);
2216 ok(ret, "Got unexpected ret %#x.\n", ret);
2218 if (0)
2220 /* Object destruction will wait until one completion arrives (which was started but not cancelled).
2221 * Commented out to save test time. */
2222 Sleep(1000);
2223 ret = HeapValidate(GetProcessHeap(), 0, io);
2224 ok(ret, "Got unexpected ret %#x.\n", ret);
2225 ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
2226 ok(!ret, "wrong ret %d\n", ret);
2227 ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
2228 ok(ret, "WriteFile() failed, error %lu\n", GetLastError());
2229 Sleep(2000);
2230 ret = HeapValidate(GetProcessHeap(), 0, io);
2231 ok(!ret, "Got unexpected ret %#x.\n", ret);
2234 CloseHandle(server);
2235 CloseHandle(ovl.hEvent);
2236 CloseHandle(client);
2237 pTpReleasePool(pool);
2240 static void CALLBACK kernel32_io_cb(TP_CALLBACK_INSTANCE *instance, void *userdata,
2241 void *ovl, ULONG ret, ULONG_PTR length, TP_IO *io)
2243 struct io_cb_ctx *ctx = userdata;
2244 ++ctx->count;
2245 ctx->ovl = ovl;
2246 ctx->ret = ret;
2247 ctx->length = length;
2248 ctx->io = io;
2251 static void test_kernel32_tp_io(void)
2253 TP_CALLBACK_ENVIRON environment = {.Version = 1};
2254 OVERLAPPED ovl = {}, ovl2 = {};
2255 HANDLE client, server, thread;
2256 struct io_cb_ctx userdata;
2257 char in[1], in2[1];
2258 const char out[1];
2259 NTSTATUS status;
2260 DWORD ret_size;
2261 TP_POOL *pool;
2262 TP_IO *io;
2263 BOOL ret;
2265 ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
2267 status = pTpAllocPool(&pool, NULL);
2268 ok(!status, "failed to allocate pool, status %#lx\n", status);
2270 server = CreateNamedPipeA("\\\\.\\pipe\\wine_tp_test",
2271 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0, 1, 1024, 1024, 0, NULL);
2272 ok(server != INVALID_HANDLE_VALUE, "Failed to create server pipe, error %lu.\n", GetLastError());
2273 client = CreateFileA("\\\\.\\pipe\\wine_tp_test", GENERIC_READ | GENERIC_WRITE,
2274 0, NULL, OPEN_EXISTING, 0, 0);
2275 ok(client != INVALID_HANDLE_VALUE, "Failed to create client pipe, error %lu.\n", GetLastError());
2277 environment.Pool = pool;
2278 io = NULL;
2279 io = pCreateThreadpoolIo(server, kernel32_io_cb, &userdata, &environment);
2280 ok(!!io, "expected non-NULL TP_IO\n");
2282 pWaitForThreadpoolIoCallbacks(io, FALSE);
2284 userdata.count = 0;
2285 pStartThreadpoolIo(io);
2287 thread = CreateThread(NULL, 0, io_wait_thread, io, 0, NULL);
2288 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "TpWaitForIoCompletion() should not return\n");
2290 ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
2291 ok(!ret, "wrong ret %d\n", ret);
2292 ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError());
2294 ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
2295 ok(ret, "WriteFile() failed, error %lu\n", GetLastError());
2297 pWaitForThreadpoolIoCallbacks(io, FALSE);
2298 ok(userdata.count == 1, "callback ran %u times\n", userdata.count);
2299 ok(userdata.ovl == &ovl, "expected %p, got %p\n", &ovl, userdata.ovl);
2300 ok(userdata.ret == ERROR_SUCCESS, "got status %#lx\n", userdata.ret);
2301 ok(userdata.length == 1, "got length %Iu\n", userdata.length);
2302 ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io);
2304 ok(!WaitForSingleObject(thread, 1000), "wait timed out\n");
2305 CloseHandle(thread);
2307 userdata.count = 0;
2308 pStartThreadpoolIo(io);
2309 pStartThreadpoolIo(io);
2311 ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
2312 ok(!ret, "wrong ret %d\n", ret);
2313 ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError());
2314 ret = ReadFile(server, in2, sizeof(in2), NULL, &ovl2);
2315 ok(!ret, "wrong ret %d\n", ret);
2316 ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError());
2318 ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
2319 ok(ret, "WriteFile() failed, error %lu\n", GetLastError());
2320 ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
2321 ok(ret, "WriteFile() failed, error %lu\n", GetLastError());
2323 pWaitForThreadpoolIoCallbacks(io, FALSE);
2324 ok(userdata.count == 2, "callback ran %u times\n", userdata.count);
2325 ok(userdata.ret == STATUS_SUCCESS, "got status %#lx\n", userdata.ret);
2326 ok(userdata.length == 1, "got length %Iu\n", userdata.length);
2327 ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io);
2329 userdata.count = 0;
2330 pStartThreadpoolIo(io);
2331 pWaitForThreadpoolIoCallbacks(io, TRUE);
2332 ok(!userdata.count, "callback ran %u times\n", userdata.count);
2334 pStartThreadpoolIo(io);
2336 ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
2337 ok(ret, "WriteFile() failed, error %lu\n", GetLastError());
2339 ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
2340 ok(ret, "wrong ret %d\n", ret);
2342 pWaitForThreadpoolIoCallbacks(io, FALSE);
2343 ok(userdata.count == 1, "callback ran %u times\n", userdata.count);
2344 ok(userdata.ovl == &ovl, "expected %p, got %p\n", &ovl, userdata.ovl);
2345 ok(userdata.ret == ERROR_SUCCESS, "got status %#lx\n", userdata.ret);
2346 ok(userdata.length == 1, "got length %Iu\n", userdata.length);
2347 ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io);
2349 userdata.count = 0;
2350 pStartThreadpoolIo(io);
2352 ret = ReadFile(server, NULL, 1, NULL, &ovl);
2353 ok(!ret, "wrong ret %d\n", ret);
2354 ok(GetLastError() == ERROR_NOACCESS, "wrong error %lu\n", GetLastError());
2356 pCancelThreadpoolIo(io);
2357 pWaitForThreadpoolIoCallbacks(io, FALSE);
2358 ok(!userdata.count, "callback ran %u times\n", userdata.count);
2360 userdata.count = 0;
2361 pStartThreadpoolIo(io);
2363 ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
2364 ok(!ret, "wrong ret %d\n", ret);
2365 ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError());
2366 ret = CancelIo(server);
2367 ok(ret, "CancelIo() failed, error %lu\n", GetLastError());
2369 pWaitForThreadpoolIoCallbacks(io, FALSE);
2370 ok(userdata.count == 1, "callback ran %u times\n", userdata.count);
2371 ok(userdata.ovl == &ovl, "expected %p, got %p\n", &ovl, userdata.ovl);
2372 ok(userdata.ret == ERROR_OPERATION_ABORTED, "got status %#lx\n", userdata.ret);
2373 ok(!userdata.length, "got length %Iu\n", userdata.length);
2374 ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io);
2376 CloseHandle(ovl.hEvent);
2377 CloseHandle(client);
2378 CloseHandle(server);
2379 pCloseThreadpoolIo(io);
2380 pTpReleasePool(pool);
2383 START_TEST(threadpool)
2385 test_RtlQueueWorkItem();
2386 test_RtlRegisterWait();
2388 if (!init_threadpool())
2389 return;
2391 test_tp_simple();
2392 test_tp_work();
2393 test_tp_work_scheduler();
2394 test_tp_group_wait();
2395 test_tp_group_cancel();
2396 test_tp_instance();
2397 test_tp_disassociate();
2398 test_tp_timer();
2399 test_tp_window_length();
2400 test_tp_wait();
2401 test_tp_multi_wait();
2402 test_tp_io();
2403 test_kernel32_tp_io();