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