ReactOS 0.4.17-dev-37-g0bfb40d
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 <stdarg.h>
22
23#include "ntstatus.h"
24#define WIN32_NO_STATUS
25#include "windef.h"
26#include "winbase.h"
27#include "winternl.h"
28#include "wine/test.h"
29
30static NTSTATUS (WINAPI *pTpAllocCleanupGroup)(TP_CLEANUP_GROUP **);
31static NTSTATUS (WINAPI *pTpAllocIoCompletion)(TP_IO **,HANDLE,PTP_IO_CALLBACK,void *,TP_CALLBACK_ENVIRON *);
32static NTSTATUS (WINAPI *pTpAllocPool)(TP_POOL **,PVOID);
36static NTSTATUS (WINAPI *pTpCallbackMayRunLong)(TP_CALLBACK_INSTANCE *);
37static VOID (WINAPI *pTpCallbackReleaseSemaphoreOnCompletion)(TP_CALLBACK_INSTANCE *,HANDLE,DWORD);
38static void (WINAPI *pTpCancelAsyncIoOperation)(TP_IO *);
39static VOID (WINAPI *pTpDisassociateCallback)(TP_CALLBACK_INSTANCE *);
40static BOOL (WINAPI *pTpIsTimerSet)(TP_TIMER *);
41static VOID (WINAPI *pTpPostWork)(TP_WORK *);
42static NTSTATUS (WINAPI *pTpQueryPoolStackInformation)(TP_POOL *,TP_POOL_STACK_INFORMATION *);
43static VOID (WINAPI *pTpReleaseCleanupGroup)(TP_CLEANUP_GROUP *);
44static VOID (WINAPI *pTpReleaseCleanupGroupMembers)(TP_CLEANUP_GROUP *,BOOL,PVOID);
45static void (WINAPI *pTpReleaseIoCompletion)(TP_IO *);
46static VOID (WINAPI *pTpReleasePool)(TP_POOL *);
47static VOID (WINAPI *pTpReleaseTimer)(TP_TIMER *);
48static VOID (WINAPI *pTpReleaseWait)(TP_WAIT *);
49static VOID (WINAPI *pTpReleaseWork)(TP_WORK *);
50static VOID (WINAPI *pTpSetPoolMaxThreads)(TP_POOL *,DWORD);
51static NTSTATUS (WINAPI *pTpSetPoolStackInformation)(TP_POOL *,TP_POOL_STACK_INFORMATION *);
52static VOID (WINAPI *pTpSetTimer)(TP_TIMER *,LARGE_INTEGER *,LONG,LONG);
53static VOID (WINAPI *pTpSetWait)(TP_WAIT *,HANDLE,LARGE_INTEGER *);
54static NTSTATUS (WINAPI *pTpSimpleTryPost)(PTP_SIMPLE_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *);
55static void (WINAPI *pTpStartAsyncIoOperation)(TP_IO *);
56static void (WINAPI *pTpWaitForIoCompletion)(TP_IO *,BOOL);
57static VOID (WINAPI *pTpWaitForTimer)(TP_TIMER *,BOOL);
58static VOID (WINAPI *pTpWaitForWait)(TP_WAIT *,BOOL);
59static VOID (WINAPI *pTpWaitForWork)(TP_WORK *,BOOL);
60
61static void (WINAPI *pCancelThreadpoolIo)(TP_IO *);
62static void (WINAPI *pCloseThreadpoolIo)(TP_IO *);
64static void (WINAPI *pStartThreadpoolIo)(TP_IO *);
65static void (WINAPI *pWaitForThreadpoolIoCallbacks)(TP_IO *, BOOL);
66
67#define GET_PROC(func) \
68 do \
69 { \
70 p ## func = (void *)GetProcAddress(module, #func); \
71 if (!p ## func) trace("Failed to get address for %s\n", #func); \
72 } \
73 while (0)
74
76{
108
109 module = GetModuleHandleA("kernel32");
115
116 if (!pTpAllocPool)
117 {
118 win_skip("Threadpool functions not supported, skipping tests\n");
119 return FALSE;
120 }
121
122 return TRUE;
123}
124
125#undef NTDLL_GET_PROC
126
127
128static DWORD CALLBACK rtl_work_cb(void *userdata)
129{
130 HANDLE semaphore = userdata;
132 return 0;
133}
134
135static void test_RtlQueueWorkItem(void)
136{
140
142 ok(semaphore != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
143
145 ok(!status, "RtlQueueWorkItem failed with status %lx\n", status);
147 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
148
150 ok(!status, "RtlQueueWorkItem failed with status %lx\n", status);
152 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
153
155 ok(!status, "RtlQueueWorkItem failed with status %lx\n", status);
157 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
158
160 ok(!status, "RtlQueueWorkItem failed with status %lx\n", status);
162 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
163
165 ok(!status, "RtlQueueWorkItem failed with status %lx\n", status);
167 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
168
170}
171
173{
179};
180
181static void CALLBACK rtl_wait_cb(void *userdata, BOOLEAN timeout)
182{
183 struct rtl_wait_info *info = userdata;
185
186 if (!timeout)
187 InterlockedIncrement(&info->userdata);
188 else
189 InterlockedExchangeAdd(&info->userdata, 0x10000);
190 info->threadid = GetCurrentThreadId();
191 ReleaseSemaphore(info->semaphore1, 1, NULL);
192
193 if (info->semaphore2)
194 {
195 result = WaitForSingleObject(info->semaphore2, 200);
196 ok(result == info->wait_result, "expected %lu, got %lu\n", info->wait_result, result);
197 ReleaseSemaphore(info->semaphore1, 1, NULL);
198 }
199}
200
202
204{
207}
208
209static void test_RtlRegisterWait(void)
210{
211 HANDLE wait1, event, thread;
212 struct rtl_wait_info info;
213 HANDLE semaphores[2];
216
217 semaphores[0] = CreateSemaphoreW(NULL, 0, 2, NULL);
218 ok(semaphores[0] != NULL, "failed to create semaphore\n");
219 semaphores[1] = CreateSemaphoreW(NULL, 0, 1, NULL);
220 ok(semaphores[1] != NULL, "failed to create semaphore\n");
221 info.semaphore1 = semaphores[0];
222 info.semaphore2 = NULL;
223
224 event = CreateEventW(NULL, FALSE, FALSE, NULL);
225 ok(event != NULL, "failed to create event\n");
226
227 /* basic test for RtlRegisterWait and RtlDeregisterWait */
228 wait1 = NULL;
229 info.userdata = 0;
230 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT);
231 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
232 ok(wait1 != NULL, "expected wait1 != NULL\n");
233 status = RtlDeregisterWait(wait1);
234 ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
235 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
236
237 /* infinite timeout, signal the semaphore two times */
238 info.userdata = 0;
239 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT);
240 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
241 ReleaseSemaphore(semaphores[1], 1, NULL);
242 result = WaitForSingleObject(semaphores[0], 100);
243 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
244 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
245 ReleaseSemaphore(semaphores[1], 1, NULL);
246 result = WaitForSingleObject(semaphores[0], 100);
247 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
248 ok(info.userdata == 2, "expected info.userdata = 2, got %lu\n", info.userdata);
249 result = WaitForSingleObject(semaphores[1], 0);
250 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
251 Sleep(50);
252 status = RtlDeregisterWait(wait1);
253 ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
254
255 /* repeat test with WT_EXECUTEONLYONCE */
256 info.userdata = 0;
258 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
259 ReleaseSemaphore(semaphores[1], 1, NULL);
260 result = WaitForSingleObject(semaphores[0], 100);
261 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
262 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
263 ReleaseSemaphore(semaphores[1], 1, NULL);
264 result = WaitForSingleObject(semaphores[0], 100);
265 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
266 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
267 result = WaitForSingleObject(semaphores[1], 0);
268 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
269 Sleep(50);
270 status = RtlDeregisterWait(wait1);
271 ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
272
273 /* finite timeout, no event */
274 info.userdata = 0;
275 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 200, WT_EXECUTEDEFAULT);
276 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
277 result = WaitForSingleObject(semaphores[0], 100);
278 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
279 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
280 result = WaitForSingleObject(semaphores[0], 200);
281 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
282 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
283 result = WaitForSingleObject(semaphores[1], 0);
284 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
285 Sleep(50);
286 status = RtlDeregisterWait(wait1);
287 ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
288
289 /* finite timeout, with event */
290 info.userdata = 0;
291 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 200, WT_EXECUTEDEFAULT);
292 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
293 result = WaitForSingleObject(semaphores[0], 100);
294 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
295 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
296 ReleaseSemaphore(semaphores[1], 1, NULL);
297 result = WaitForSingleObject(semaphores[0], 100);
298 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
299 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
300 result = WaitForSingleObject(semaphores[1], 0);
301 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
302 Sleep(50);
303 status = RtlDeregisterWait(wait1);
304 ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
305
306 /* test RtlRegisterWait WT_EXECUTEINWAITTHREAD flag */
307 info.userdata = 0;
308 info.threadid = 0;
310 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
311 ReleaseSemaphore(semaphores[1], 1, NULL);
312 result = WaitForSingleObject(semaphores[0], 200);
313 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
314 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
315 ok(info.threadid && info.threadid != GetCurrentThreadId(), "unexpected wait thread id %lx\n", info.threadid);
316 threadid = info.threadid;
317 result = WaitForSingleObject(semaphores[1], 0);
318 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
319 Sleep(50);
320 status = RtlDeregisterWait(wait1);
321 ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
322
323 info.userdata = 0;
324 info.threadid = 0;
326 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
327 ReleaseSemaphore(semaphores[1], 1, NULL);
328 result = WaitForSingleObject(semaphores[0], 200);
329 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
330 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
331 ok(info.threadid == threadid, "unexpected different wait thread id %lx\n", info.threadid);
332 result = WaitForSingleObject(semaphores[1], 0);
333 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
334 Sleep(50);
335 status = RtlDeregisterWait(wait1);
336 ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
337
338 /* test RtlRegisterWait WT_EXECUTEINWAITTHREAD flag with 0 timeout */
339 info.userdata = 0;
340 info.threadid = 0;
342 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
343 result = WaitForSingleObject(semaphores[0], 100);
344 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
345 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
346 ok(info.threadid == threadid, "unexpected different wait thread id %lx\n", info.threadid);
347 result = WaitForSingleObject(semaphores[1], 0);
348 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
349 Sleep(50);
350 status = RtlDeregisterWait(wait1);
351 ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
352
353 /* test RtlRegisterWait WT_EXECUTEINWAITTHREAD flag with already signaled event */
354 info.userdata = 0;
355 info.threadid = 0;
356 ReleaseSemaphore(semaphores[1], 1, NULL);
358 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
359 result = WaitForSingleObject(semaphores[0], 200);
360 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
361 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
362 ok(info.threadid == threadid, "unexpected different wait thread id %lx\n", info.threadid);
363 result = WaitForSingleObject(semaphores[1], 0);
364 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
365 Sleep(50);
366 status = RtlDeregisterWait(wait1);
367 ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
368
369 /* test for IO threads */
370 info.userdata = 0;
371 info.threadid = 0;
373 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
374 ReleaseSemaphore(semaphores[1], 1, NULL);
375 result = WaitForSingleObject(semaphores[0], 100);
376 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
377 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
378 ok(info.threadid != 0, "expected info.threadid != 0, got %lu\n", info.threadid);
380 ok(thread != NULL, "OpenThread failed with %lu\n", GetLastError());
381 rtl_wait_apc_semaphore = semaphores[0];
383 ok(result != 0, "QueueUserAPC failed with %lu\n", GetLastError());
384 result = WaitForSingleObject(semaphores[0], 200);
385 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
388 ReleaseSemaphore(semaphores[1], 1, NULL);
389 result = WaitForSingleObject(semaphores[0], 100);
390 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
391 ok(info.userdata == 2, "expected info.userdata = 2, got %lu\n", info.userdata);
392 Sleep(50);
393 status = RtlDeregisterWait(wait1);
394 ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
395
396 info.userdata = 0;
397 info.threadid = 0;
398 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT);
399 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
400 ReleaseSemaphore(semaphores[1], 1, NULL);
401 result = WaitForSingleObject(semaphores[0], 100);
402 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
403 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
404 ok(info.threadid != 0, "expected info.threadid != 0, got %lu\n", info.threadid);
406 ok(thread != NULL, "OpenThread failed with %lu\n", GetLastError());
407 rtl_wait_apc_semaphore = semaphores[0];
409 ok(result != 0, "QueueUserAPC failed with %lu\n", GetLastError());
410 result = WaitForSingleObject(semaphores[0], 200);
411 ok(result == WAIT_TIMEOUT || broken(result == WAIT_OBJECT_0) /* >= Win Vista */,
412 "WaitForSingleObject returned %lu\n", result);
415 ReleaseSemaphore(semaphores[1], 1, NULL);
416 result = WaitForSingleObject(semaphores[0], 100);
417 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
418 ok(info.userdata == 2, "expected info.userdata = 2, got %lu\n", info.userdata);
419 Sleep(50);
420 status = RtlDeregisterWait(wait1);
421 ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
422
423 /* test RtlDeregisterWaitEx before wait expired */
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);
428 ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status);
429 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
430
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);
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
438 info.userdata = 0;
439 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT);
440 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
442 ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status);
443 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
445 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
446
447 /* test RtlDeregisterWaitEx after wait expired */
448 info.userdata = 0;
449 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 0, WT_EXECUTEONLYONCE);
450 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
451 result = WaitForSingleObject(semaphores[0], 100);
452 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
453 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
454 Sleep(50);
456 ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status);
457 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
458
459 info.userdata = 0;
460 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 0, WT_EXECUTEONLYONCE);
461 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
462 result = WaitForSingleObject(semaphores[0], 100);
463 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
464 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
465 Sleep(50);
467 ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status);
468 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
469
470 info.userdata = 0;
471 status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 0, WT_EXECUTEONLYONCE);
472 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
473 result = WaitForSingleObject(semaphores[0], 100);
474 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
475 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
476 Sleep(50);
478 ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status);
479 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
481 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
482
483 /* test RtlDeregisterWaitEx while callback is running */
484 info.semaphore2 = semaphores[1];
485 info.wait_result = WAIT_OBJECT_0;
486
487 info.userdata = 0;
489 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
490 ReleaseSemaphore(semaphores[1], 1, NULL);
491 result = WaitForSingleObject(semaphores[0], 1000);
492 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
493 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
494 status = RtlDeregisterWait(wait1);
495 ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %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
500 info.userdata = 0;
502 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
503 ReleaseSemaphore(semaphores[1], 1, NULL);
504 result = WaitForSingleObject(semaphores[0], 1000);
505 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
506 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
507 status = RtlDeregisterWait(wait1);
508 ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %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
513 info.userdata = 0;
515 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
516 ReleaseSemaphore(semaphores[1], 1, NULL);
517 result = WaitForSingleObject(semaphores[0], 1000);
518 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
519 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
521 ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %lx\n", status);
522 ReleaseSemaphore(semaphores[1], 1, NULL);
523 result = WaitForSingleObject(semaphores[0], 1000);
524 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
525
526 info.wait_result = WAIT_TIMEOUT;
527 info.userdata = 0;
529 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
530 ReleaseSemaphore(semaphores[1], 1, NULL);
531 result = WaitForSingleObject(semaphores[0], 1000);
532 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
533 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
535 ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status);
536 result = WaitForSingleObject(semaphores[0], 0);
537 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
538
539 info.wait_result = WAIT_TIMEOUT;
540 info.userdata = 0;
542 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
543 ReleaseSemaphore(semaphores[1], 1, NULL);
544 result = WaitForSingleObject(semaphores[0], 1000);
545 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
546 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
548 ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status);
549 result = WaitForSingleObject(semaphores[0], 0);
550 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
551
552 info.wait_result = WAIT_OBJECT_0;
553 info.userdata = 0;
555 ok(!status, "RtlRegisterWait failed with status %lx\n", status);
556 ReleaseSemaphore(semaphores[1], 1, NULL);
557 result = WaitForSingleObject(semaphores[0], 1000);
558 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
559 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
561 ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %lx\n", status);
562 ReleaseSemaphore(semaphores[1], 1, NULL);
564 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
565 result = WaitForSingleObject(semaphores[0], 0);
566 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
567
568 CloseHandle(semaphores[0]);
569 CloseHandle(semaphores[1]);
571}
572
574{
577}
578
580{
581 Sleep(50);
583}
584
585static void test_tp_simple(void)
586{
588 TP_POOL_STACK_INFORMATION stack_info;
589 TP_CALLBACK_ENVIRON environment;
590#if !defined(__REACTOS__) || _WIN32_WINNT >= _WIN32_WINNT_WIN7
591 TP_CALLBACK_ENVIRON_V3 environment3;
592#endif
596 TP_POOL *pool;
599 int i;
600
602 ok(semaphore != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
603
604 /* post the callback using the default threadpool */
605 memset(&environment, 0, sizeof(environment));
606 environment.Version = 1;
607 environment.Pool = NULL;
608 status = pTpSimpleTryPost(simple_cb, semaphore, &environment);
609 ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
611 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
612
613 /* allocate new threadpool */
614 pool = NULL;
615 status = pTpAllocPool(&pool, NULL);
616 ok(!status, "TpAllocPool failed with status %lx\n", status);
617 ok(pool != NULL, "expected pool != NULL\n");
618
619 /* post the callback using the new threadpool */
620 memset(&environment, 0, sizeof(environment));
621 environment.Version = 1;
622 environment.Pool = pool;
623 status = pTpSimpleTryPost(simple_cb, semaphore, &environment);
624 ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
626 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
627
628 /* test with environment version 3 */
629#if !defined(__REACTOS__) || _WIN32_WINNT >= _WIN32_WINNT_WIN7
630 memset(&environment3, 0, sizeof(environment3));
631 environment3.Version = 3;
632 environment3.Pool = pool;
633 environment3.Size = sizeof(environment3);
634
635 for (i = 0; i < 3; ++i)
636 {
638 status = pTpSimpleTryPost(simple_cb, semaphore, (TP_CALLBACK_ENVIRON *)&environment3);
639 ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
641 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
642 }
643
644 environment3.CallbackPriority = 10;
645 status = pTpSimpleTryPost(simple_cb, semaphore, (TP_CALLBACK_ENVIRON *)&environment3);
646 ok(status == STATUS_INVALID_PARAMETER || broken(!status) /* Vista does not support priorities */,
647 "TpSimpleTryPost failed with status %lx\n", status);
648#endif
649
650 /* test with invalid version number */
651 memset(&environment, 0, sizeof(environment));
652 environment.Version = 9999;
653 environment.Pool = pool;
654 status = pTpSimpleTryPost(simple_cb, semaphore, &environment);
656 ok(status == STATUS_INVALID_PARAMETER || broken(!status) /* Vista/2008 */,
657 "TpSimpleTryPost unexpectedly returned status %lx\n", status);
658 if (!status)
659 {
661 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
662 }
663
664 /* allocate a cleanup group for synchronization */
665 group = NULL;
666 status = pTpAllocCleanupGroup(&group);
667 ok(!status, "TpAllocCleanupGroup failed with status %lx\n", status);
668 ok(group != NULL, "expected pool != NULL\n");
669
670 /* use cleanup group to wait for a simple callback */
671 userdata = 0;
672 memset(&environment, 0, sizeof(environment));
673 environment.Version = 1;
674 environment.Pool = pool;
675 environment.CleanupGroup = group;
676 status = pTpSimpleTryPost(simple2_cb, &userdata, &environment);
677 ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
678 pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
679 ok(userdata == 1, "expected userdata = 1, got %lu\n", userdata);
680
681 /* test cancellation of pending simple callbacks */
682 userdata = 0;
683 pTpSetPoolMaxThreads(pool, 10);
684 memset(&environment, 0, sizeof(environment));
685 environment.Version = 1;
686 environment.Pool = pool;
687 environment.CleanupGroup = group;
688 for (i = 0; i < 100; i++)
689 {
690 status = pTpSimpleTryPost(simple2_cb, &userdata, &environment);
691 ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
692 }
693 pTpReleaseCleanupGroupMembers(group, TRUE, NULL);
694 ok(userdata < 100, "expected userdata < 100, got %lu\n", userdata);
695
696#ifdef __REACTOS__
697 if (!pTpQueryPoolStackInformation)
698 {
699 skip("TpQueryPoolStackInformation not available\n");
700 }
701 else
702 {
703#endif
704 /* test querying and setting the stack size */
705 status = pTpQueryPoolStackInformation(pool, &stack_info);
706 ok(!status, "TpQueryPoolStackInformation failed: %lx\n", status);
707 ok(stack_info.StackReserve == nt->OptionalHeader.SizeOfStackReserve, "expected default StackReserve, got %Ix\n", stack_info.StackReserve);
708 ok(stack_info.StackCommit == nt->OptionalHeader.SizeOfStackCommit, "expected default StackCommit, got %Ix\n", stack_info.StackCommit);
709
710 /* threadpool does not validate the stack size values */
711 stack_info.StackReserve = stack_info.StackCommit = 1;
712 status = pTpSetPoolStackInformation(pool, &stack_info);
713 ok(!status, "TpSetPoolStackInformation failed: %lx\n", status);
714
715 status = pTpQueryPoolStackInformation(pool, &stack_info);
716 ok(!status, "TpQueryPoolStackInformation failed: %lx\n", status);
717 ok(stack_info.StackReserve == 1, "expected 1 byte StackReserve, got %ld\n", (ULONG)stack_info.StackReserve);
718 ok(stack_info.StackCommit == 1, "expected 1 byte StackCommit, got %ld\n", (ULONG)stack_info.StackCommit);
719#ifdef __REACTOS__
720 }
721#endif
722
723 /* cleanup */
724 pTpReleaseCleanupGroup(group);
725 pTpReleasePool(pool);
727}
728
730{
731 Sleep(100);
733}
734
736{
737 Sleep(100);
739}
740
741static void test_tp_work(void)
742{
743 TP_CALLBACK_ENVIRON environment;
744 TP_WORK *work;
745 TP_POOL *pool;
748 int i;
749
750 /* allocate new threadpool with only one thread */
751 pool = NULL;
752 status = pTpAllocPool(&pool, NULL);
753 ok(!status, "TpAllocPool failed with status %lx\n", status);
754 ok(pool != NULL, "expected pool != NULL\n");
755 pTpSetPoolMaxThreads(pool, 1);
756
757 /* allocate new work item */
758 work = NULL;
759 memset(&environment, 0, sizeof(environment));
760 environment.Version = 1;
761 environment.Pool = pool;
762 status = pTpAllocWork(&work, work_cb, &userdata, &environment);
763 ok(!status, "TpAllocWork failed with status %lx\n", status);
764 ok(work != NULL, "expected work != NULL\n");
765
766 /* post 5 identical work items at once */
767 userdata = 0;
768 for (i = 0; i < 5; i++)
769 pTpPostWork(work);
770 pTpWaitForWork(work, FALSE);
771 ok(userdata == 5, "expected userdata = 5, got %lu\n", userdata);
772
773 /* add more tasks and cancel them immediately */
774 userdata = 0;
775 for (i = 0; i < 10; i++)
776 pTpPostWork(work);
777 pTpWaitForWork(work, TRUE);
778 ok(userdata < 10, "expected userdata < 10, got %lu\n", userdata);
779
780 /* cleanup */
781 pTpReleaseWork(work);
782 pTpReleasePool(pool);
783}
784
785static void test_tp_work_scheduler(void)
786{
787 TP_CALLBACK_ENVIRON environment;
789 TP_WORK *work, *work2;
790 TP_POOL *pool;
793 int i;
794
795 /* allocate new threadpool with only one thread */
796 pool = NULL;
797 status = pTpAllocPool(&pool, NULL);
798 ok(!status, "TpAllocPool failed with status %lx\n", status);
799 ok(pool != NULL, "expected pool != NULL\n");
800 pTpSetPoolMaxThreads(pool, 1);
801
802 /* create a cleanup group */
803 group = NULL;
804 status = pTpAllocCleanupGroup(&group);
805 ok(!status, "TpAllocCleanupGroup failed with status %lx\n", status);
806 ok(group != NULL, "expected pool != NULL\n");
807
808 /* the first work item has no cleanup group associated */
809 work = NULL;
810 memset(&environment, 0, sizeof(environment));
811 environment.Version = 1;
812 environment.Pool = pool;
813 status = pTpAllocWork(&work, work_cb, &userdata, &environment);
814 ok(!status, "TpAllocWork failed with status %lx\n", status);
815 ok(work != NULL, "expected work != NULL\n");
816
817 /* allocate a second work item with a cleanup group */
818 work2 = NULL;
819 memset(&environment, 0, sizeof(environment));
820 environment.Version = 1;
821 environment.Pool = pool;
822 environment.CleanupGroup = group;
823 status = pTpAllocWork(&work2, work2_cb, &userdata, &environment);
824 ok(!status, "TpAllocWork failed with status %lx\n", status);
825 ok(work2 != NULL, "expected work2 != NULL\n");
826
827 /* the 'work' callbacks are not blocking execution of 'work2' callbacks */
828 userdata = 0;
829 for (i = 0; i < 10; i++)
830 pTpPostWork(work);
831 for (i = 0; i < 10; i++)
832 pTpPostWork(work2);
833 Sleep(500);
834 pTpWaitForWork(work, TRUE);
835 pTpWaitForWork(work2, TRUE);
836 ok(userdata & 0xffff, "expected userdata & 0xffff != 0, got %lu\n", userdata & 0xffff);
837 ok(userdata >> 16, "expected userdata >> 16 != 0, got %lu\n", userdata >> 16);
838
839 /* test TpReleaseCleanupGroupMembers on a work item */
840 userdata = 0;
841 for (i = 0; i < 10; i++)
842 pTpPostWork(work);
843 for (i = 0; i < 3; i++)
844 pTpPostWork(work2);
845 pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
846 pTpWaitForWork(work, TRUE);
847 ok((userdata & 0xffff) < 10, "expected userdata & 0xffff < 10, got %lu\n", userdata & 0xffff);
848 ok((userdata >> 16) == 3, "expected userdata >> 16 == 3, got %lu\n", userdata >> 16);
849
850 /* cleanup */
851 pTpReleaseWork(work);
852 pTpReleaseCleanupGroup(group);
853 pTpReleasePool(pool);
854}
855
857{
858 HANDLE *semaphores = userdata;
859 ReleaseSemaphore(semaphores, 1, NULL);
860 Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */
861}
862
864{
867 Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */
868 pTpReleaseWork(work);
869}
870
872{
875 Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */
876 pTpReleaseTimer(timer);
877}
878
881{
884 Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */
885 pTpReleaseWait(wait);
886}
887
888static void test_tp_group_wait(void)
889{
890 TP_CALLBACK_ENVIRON environment;
892 LARGE_INTEGER when;
895 TP_TIMER *timer;
896 TP_WAIT *wait;
897 TP_WORK *work;
898 TP_POOL *pool;
900
902 ok(semaphore != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
903
904 /* allocate new threadpool */
905 pool = NULL;
906 status = pTpAllocPool(&pool, NULL);
907 ok(!status, "TpAllocPool failed with status %lx\n", status);
908 ok(pool != NULL, "expected pool != NULL\n");
909
910 /* allocate a cleanup group */
911 group = NULL;
912 status = pTpAllocCleanupGroup(&group);
913 ok(!status, "TpAllocCleanupGroup failed with status %lx\n", status);
914 ok(group != NULL, "expected pool != NULL\n");
915
916 /* release work object during TpReleaseCleanupGroupMembers */
917 work = NULL;
918 memset(&environment, 0, sizeof(environment));
919 environment.Version = 1;
920 environment.Pool = pool;
921 environment.CleanupGroup = group;
922 status = pTpAllocWork(&work, work_release_cb, semaphore, &environment);
923 ok(!status, "TpAllocWork failed with status %lx\n", status);
924 ok(work != NULL, "expected work != NULL\n");
925 pTpPostWork(work);
927 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
928 pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
929
930 /* release timer object during TpReleaseCleanupGroupMembers */
931 timer = NULL;
932 memset(&environment, 0, sizeof(environment));
933 environment.Version = 1;
934 environment.Pool = pool;
935 environment.CleanupGroup = group;
936 status = pTpAllocTimer(&timer, timer_release_cb, semaphore, &environment);
937 ok(!status, "TpAllocTimer failed with status %lx\n", status);
938 ok(timer != NULL, "expected timer != NULL\n");
939 when.QuadPart = 0;
940 pTpSetTimer(timer, &when, 0, 0);
942 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
943 pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
944
945 /* release wait object during TpReleaseCleanupGroupMembers */
946 wait = NULL;
947 memset(&environment, 0, sizeof(environment));
948 environment.Version = 1;
949 environment.Pool = pool;
950 environment.CleanupGroup = group;
951 status = pTpAllocWait(&wait, wait_release_cb, semaphore, &environment);
952 ok(!status, "TpAllocWait failed with status %lx\n", status);
953 ok(wait != NULL, "expected wait != NULL\n");
954 when.QuadPart = 0;
955 pTpSetWait(wait, INVALID_HANDLE_VALUE, &when);
957 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
958 pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
959
960 /* cleanup */
961 pTpReleaseCleanupGroup(group);
962 pTpReleasePool(pool);
964}
965
967
969{
970 HANDLE *semaphores = userdata;
973 int i;
974
975 status = pTpCallbackMayRunLong(instance);
976 ok(status == STATUS_TOO_MANY_THREADS || broken(status == 1) /* Win Vista / 2008 */,
977 "expected STATUS_TOO_MANY_THREADS, got %08lx\n", status);
978
979 ReleaseSemaphore(semaphores[1], 1, NULL);
980 for (i = 0; i < 4; i++)
981 {
982 result = WaitForSingleObject(semaphores[0], 1000);
983 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
984 }
985 ReleaseSemaphore(semaphores[1], 1, NULL);
986}
987
989{
990 HANDLE *semaphores = userdata;
992
993 ReleaseSemaphore(semaphores[1], 1, NULL);
994 result = WaitForSingleObject(semaphores[0], 200);
995 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
996}
997
998static void CALLBACK group_cancel_cleanup_release_cb(void *object, void *userdata)
999{
1000 HANDLE *semaphores = userdata;
1002 ok(object == (void *)0xdeadbeef, "expected 0xdeadbeef, got %p\n", object);
1003 ReleaseSemaphore(semaphores[0], 1, NULL);
1004}
1005
1007{
1008 HANDLE *semaphores = userdata;
1010 ok(object == userdata, "expected %p, got %p\n", userdata, object);
1011 ReleaseSemaphore(semaphores[0], 1, NULL);
1012}
1013
1015{
1018}
1019
1021{
1022 ok(0, "Unexpected callback\n");
1023}
1024
1026{
1027 ok(0, "Unexpected callback\n");
1028}
1029
1031{
1032 ok(0, "Unexpected callback\n");
1033}
1034
1037{
1038 ok(0, "Unexpected callback\n");
1039}
1040
1042{
1043 ok(0, "Unexpected callback\n");
1044}
1045
1046static void test_tp_group_cancel(void)
1047{
1048 TP_CALLBACK_ENVIRON environment;
1050 LONG userdata, userdata2;
1051 HANDLE semaphores[2];
1053 TP_TIMER *timer;
1054 TP_WAIT *wait;
1055 TP_WORK *work;
1056 TP_POOL *pool;
1057 DWORD result;
1058 int i;
1059
1060 semaphores[0] = CreateSemaphoreA(NULL, 0, 4, NULL);
1061 ok(semaphores[0] != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
1062 semaphores[1] = CreateSemaphoreA(NULL, 0, 1, NULL);
1063 ok(semaphores[1] != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
1064
1065 /* allocate new threadpool with only one thread */
1066 pool = NULL;
1067 status = pTpAllocPool(&pool, NULL);
1068 ok(!status, "TpAllocPool failed with status %lx\n", status);
1069 ok(pool != NULL, "expected pool != NULL\n");
1070 pTpSetPoolMaxThreads(pool, 1);
1071
1072 /* allocate a cleanup group */
1073 group = NULL;
1074 status = pTpAllocCleanupGroup(&group);
1075 ok(!status, "TpAllocCleanupGroup failed with status %lx\n", status);
1076 ok(group != NULL, "expected pool != NULL\n");
1077
1078 /* test execution of cancellation callback */
1079 memset(&environment, 0, sizeof(environment));
1080 environment.Version = 1;
1081 environment.Pool = pool;
1082 status = pTpSimpleTryPost(simple_group_cancel_cb, semaphores, &environment);
1083 ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
1084 result = WaitForSingleObject(semaphores[1], 1000);
1085 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1086
1087 memset(&environment, 0, sizeof(environment));
1088 environment.Version = 1;
1089 environment.Pool = pool;
1090 environment.CleanupGroup = group;
1092 status = pTpSimpleTryPost(unexpected_simple_cb, (void *)0xdeadbeef, &environment);
1093 ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
1094
1095 work = NULL;
1096 status = pTpAllocWork(&work, unexpected_work_cb, (void *)0xdeadbeef, &environment);
1097 ok(!status, "TpAllocWork failed with status %lx\n", status);
1098 ok(work != NULL, "expected work != NULL\n");
1099
1100 timer = NULL;
1101 status = pTpAllocTimer(&timer, unexpected_timer_cb, (void *)0xdeadbeef, &environment);
1102 ok(!status, "TpAllocTimer failed with status %lx\n", status);
1103 ok(timer != NULL, "expected timer != NULL\n");
1104
1105 wait = NULL;
1106 status = pTpAllocWait(&wait, unexpected_wait_cb, (void *)0xdeadbeef, &environment);
1107 ok(!status, "TpAllocWait failed with status %lx\n", status);
1108 ok(wait != NULL, "expected wait != NULL\n");
1109
1110 group_cancel_tid = 0xdeadbeef;
1111 pTpReleaseCleanupGroupMembers(group, TRUE, semaphores);
1112 result = WaitForSingleObject(semaphores[1], 1000);
1113 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1114 ok(group_cancel_tid == GetCurrentThreadId(), "expected tid %lx, got %lx\n",
1116
1117 /* test if cancellation callbacks are executed before or after wait */
1118 work = NULL;
1119 memset(&environment, 0, sizeof(environment));
1120 environment.Version = 1;
1121 environment.Pool = pool;
1122 environment.CleanupGroup = group;
1124 status = pTpAllocWork(&work, work_group_cancel_cb, semaphores, &environment);
1125 ok(!status, "TpAllocWork failed with status %lx\n", status);
1126 ok(work != NULL, "expected work != NULL\n");
1127 pTpPostWork(work);
1128 pTpPostWork(work);
1129
1130 result = WaitForSingleObject(semaphores[1], 1000);
1131 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1132
1133 group_cancel_tid = 0xdeadbeef;
1134 pTpReleaseCleanupGroupMembers(group, TRUE, semaphores);
1135 result = WaitForSingleObject(semaphores[0], 1000);
1136 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1137 ok(group_cancel_tid == GetCurrentThreadId(), "expected tid %lx, got %lx\n",
1139
1140 /* group cancel callback is not executed if object is destroyed while waiting */
1141 work = NULL;
1142 memset(&environment, 0, sizeof(environment));
1143 environment.Version = 1;
1144 environment.Pool = pool;
1145 environment.CleanupGroup = group;
1147 status = pTpAllocWork(&work, work_release_cb, semaphores[1], &environment);
1148 ok(!status, "TpAllocWork failed with status %lx\n", status);
1149 ok(work != NULL, "expected work != NULL\n");
1150 pTpPostWork(work);
1151
1152 result = WaitForSingleObject(semaphores[1], 1000);
1153 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1154 pTpReleaseCleanupGroupMembers(group, TRUE, NULL);
1155
1156 /* terminated simple callbacks should not trigger the group cancel callback */
1157 memset(&environment, 0, sizeof(environment));
1158 environment.Version = 1;
1159 environment.Pool = pool;
1160 environment.CleanupGroup = group;
1162 status = pTpSimpleTryPost(simple_release_cb, semaphores[1], &environment);
1163 ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
1164 result = WaitForSingleObject(semaphores[1], 1000);
1165 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1166 pTpReleaseCleanupGroupMembers(group, TRUE, semaphores);
1167
1168 /* test cancellation callback for objects with multiple instances */
1169 work = NULL;
1170 memset(&environment, 0, sizeof(environment));
1171 environment.Version = 1;
1172 environment.Pool = pool;
1173 environment.CleanupGroup = group;
1175 status = pTpAllocWork(&work, work_cb, &userdata, &environment);
1176 ok(!status, "TpAllocWork failed with status %lx\n", status);
1177 ok(work != NULL, "expected work != NULL\n");
1178
1179 /* post 10 identical work items at once */
1180 userdata = userdata2 = 0;
1181 for (i = 0; i < 10; i++)
1182 pTpPostWork(work);
1183
1184 /* check if we get multiple cancellation callbacks */
1185 group_cancel_tid = 0xdeadbeef;
1186 pTpReleaseCleanupGroupMembers(group, TRUE, &userdata2);
1187 ok(userdata <= 5, "expected userdata <= 5, got %lu\n", userdata);
1188 ok(userdata2 == 1, "expected only one cancellation callback, got %lu\n", userdata2);
1189 ok(group_cancel_tid == GetCurrentThreadId(), "expected tid %lx, got %lx\n",
1191
1192 /* cleanup */
1193 pTpReleaseCleanupGroup(group);
1194 pTpReleasePool(pool);
1195 CloseHandle(semaphores[0]);
1196 CloseHandle(semaphores[1]);
1197}
1198
1200{
1201 HANDLE *semaphores = userdata;
1202 pTpCallbackReleaseSemaphoreOnCompletion(instance, semaphores[0], 1);
1203}
1204
1206{
1207 HANDLE *semaphores = userdata;
1208 ReleaseSemaphore(semaphores[1], 1, NULL);
1209}
1210
1211static void test_tp_instance(void)
1212{
1213 TP_CALLBACK_ENVIRON environment;
1214 HANDLE semaphores[2];
1216 TP_POOL *pool;
1217 DWORD result;
1218
1219 semaphores[0] = CreateSemaphoreW(NULL, 0, 1, NULL);
1220 ok(semaphores[0] != NULL, "failed to create semaphore\n");
1221 semaphores[1] = CreateSemaphoreW(NULL, 0, 1, NULL);
1222 ok(semaphores[1] != NULL, "failed to create semaphore\n");
1223
1224 /* allocate new threadpool */
1225 pool = NULL;
1226 status = pTpAllocPool(&pool, NULL);
1227 ok(!status, "TpAllocPool failed with status %lx\n", status);
1228 ok(pool != NULL, "expected pool != NULL\n");
1229
1230 /* test for TpCallbackReleaseSemaphoreOnCompletion */
1231 memset(&environment, 0, sizeof(environment));
1232 environment.Version = 1;
1233 environment.Pool = pool;
1234 status = pTpSimpleTryPost(instance_semaphore_completion_cb, semaphores, &environment);
1235 ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
1236 result = WaitForSingleObject(semaphores[0], 1000);
1237 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1238
1239 /* test for finalization callback */
1240 memset(&environment, 0, sizeof(environment));
1241 environment.Version = 1;
1242 environment.Pool = pool;
1244 status = pTpSimpleTryPost(instance_semaphore_completion_cb, semaphores, &environment);
1245 ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
1246 result = WaitForSingleObject(semaphores[0], 1000);
1247 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1248 result = WaitForSingleObject(semaphores[1], 1000);
1249 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1250
1251 /* cleanup */
1252 pTpReleasePool(pool);
1253 CloseHandle(semaphores[0]);
1254 CloseHandle(semaphores[1]);
1255}
1256
1258{
1259 HANDLE *semaphores = userdata;
1260 DWORD result;
1261
1262 pTpDisassociateCallback(instance);
1263 result = WaitForSingleObject(semaphores[0], 1000);
1264 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1265 ReleaseSemaphore(semaphores[1], 1, NULL);
1266}
1267
1269{
1270 HANDLE *semaphores = userdata;
1271 DWORD result;
1272
1273 pTpDisassociateCallback(instance);
1274 result = WaitForSingleObject(semaphores[0], 100);
1275 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1276 ReleaseSemaphore(semaphores[1], 1, NULL);
1277}
1278
1280{
1281 HANDLE *semaphores = userdata;
1282 DWORD result;
1283
1284 pTpDisassociateCallback(instance);
1285 result = WaitForSingleObject(semaphores[0], 100);
1286 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1287 ReleaseSemaphore(semaphores[1], 1, NULL);
1288}
1289
1290static void test_tp_disassociate(void)
1291{
1292 TP_CALLBACK_ENVIRON environment;
1294 HANDLE semaphores[2];
1296 TP_POOL *pool;
1297 TP_WORK *work;
1298 DWORD result;
1299
1300 semaphores[0] = CreateSemaphoreW(NULL, 0, 1, NULL);
1301 ok(semaphores[0] != NULL, "failed to create semaphore\n");
1302 semaphores[1] = CreateSemaphoreW(NULL, 0, 1, NULL);
1303 ok(semaphores[1] != NULL, "failed to create semaphore\n");
1304
1305 /* allocate new threadpool and cleanup group */
1306 pool = NULL;
1307 status = pTpAllocPool(&pool, NULL);
1308 ok(!status, "TpAllocPool failed with status %lx\n", status);
1309 ok(pool != NULL, "expected pool != NULL\n");
1310
1311 group = NULL;
1312 status = pTpAllocCleanupGroup(&group);
1313 ok(!status, "TpAllocCleanupGroup failed with status %lx\n", status);
1314 ok(group != NULL, "expected pool != NULL\n");
1315
1316 /* test TpDisassociateCallback on work objects without group */
1317 work = NULL;
1318 memset(&environment, 0, sizeof(environment));
1319 environment.Version = 1;
1320 environment.Pool = pool;
1321 status = pTpAllocWork(&work, disassociate_cb, semaphores, &environment);
1322 ok(!status, "TpAllocWork failed with status %lx\n", status);
1323 ok(work != NULL, "expected work != NULL\n");
1324
1325 pTpPostWork(work);
1326 pTpWaitForWork(work, FALSE);
1327
1328 result = WaitForSingleObject(semaphores[1], 100);
1329 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1330 ReleaseSemaphore(semaphores[0], 1, NULL);
1331 result = WaitForSingleObject(semaphores[1], 1000);
1332 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1333 pTpReleaseWork(work);
1334
1335 /* test TpDisassociateCallback on work objects with group (1) */
1336 work = NULL;
1337 memset(&environment, 0, sizeof(environment));
1338 environment.Version = 1;
1339 environment.Pool = pool;
1340 environment.CleanupGroup = group;
1341 status = pTpAllocWork(&work, disassociate_cb, semaphores, &environment);
1342 ok(!status, "TpAllocWork failed with status %lx\n", status);
1343 ok(work != NULL, "expected work != NULL\n");
1344
1345 pTpPostWork(work);
1346 pTpWaitForWork(work, FALSE);
1347
1348 result = WaitForSingleObject(semaphores[1], 100);
1349 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1350 ReleaseSemaphore(semaphores[0], 1, NULL);
1351 result = WaitForSingleObject(semaphores[1], 1000);
1352 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1353 pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
1354
1355 /* test TpDisassociateCallback on work objects with group (2) */
1356 work = NULL;
1357 memset(&environment, 0, sizeof(environment));
1358 environment.Version = 1;
1359 environment.Pool = pool;
1360 environment.CleanupGroup = group;
1361 status = pTpAllocWork(&work, disassociate2_cb, semaphores, &environment);
1362 ok(!status, "TpAllocWork failed with status %lx\n", status);
1363 ok(work != NULL, "expected work != NULL\n");
1364
1365 pTpPostWork(work);
1366 pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
1367
1368 ReleaseSemaphore(semaphores[0], 1, NULL);
1369 result = WaitForSingleObject(semaphores[1], 1000);
1370 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1371 result = WaitForSingleObject(semaphores[0], 1000);
1372 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1373
1374 /* test TpDisassociateCallback on simple callbacks */
1375 memset(&environment, 0, sizeof(environment));
1376 environment.Version = 1;
1377 environment.Pool = pool;
1378 environment.CleanupGroup = group;
1379 status = pTpSimpleTryPost(disassociate3_cb, semaphores, &environment);
1380 ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
1381
1382 pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
1383
1384 ReleaseSemaphore(semaphores[0], 1, NULL);
1385 result = WaitForSingleObject(semaphores[1], 1000);
1386 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1387 result = WaitForSingleObject(semaphores[0], 1000);
1388 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1389
1390 /* cleanup */
1391 pTpReleaseCleanupGroup(group);
1392 pTpReleasePool(pool);
1393 CloseHandle(semaphores[0]);
1394 CloseHandle(semaphores[1]);
1395}
1396
1398{
1401}
1402
1403static void test_tp_timer(void)
1404{
1405 TP_CALLBACK_ENVIRON environment;
1406 DWORD result, ticks;
1407 LARGE_INTEGER when;
1410 TP_TIMER *timer;
1411 TP_POOL *pool;
1412 BOOL success;
1413 int i;
1414
1416 ok(semaphore != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
1417
1418 /* allocate new threadpool */
1419 pool = NULL;
1420 status = pTpAllocPool(&pool, NULL);
1421 ok(!status, "TpAllocPool failed with status %lx\n", status);
1422 ok(pool != NULL, "expected pool != NULL\n");
1423
1424 /* allocate new timer */
1425 timer = NULL;
1426 memset(&environment, 0, sizeof(environment));
1427 environment.Version = 1;
1428 environment.Pool = pool;
1429 status = pTpAllocTimer(&timer, timer_cb, semaphore, &environment);
1430 ok(!status, "TpAllocTimer failed with status %lx\n", status);
1431 ok(timer != NULL, "expected timer != NULL\n");
1432
1433 success = pTpIsTimerSet(timer);
1434 ok(!success, "TpIsTimerSet returned TRUE\n");
1435
1436 /* test timer with a relative timeout */
1437 when.QuadPart = (ULONGLONG)200 * -10000;
1438 pTpSetTimer(timer, &when, 0, 0);
1439 success = pTpIsTimerSet(timer);
1440 ok(success, "TpIsTimerSet returned FALSE\n");
1441
1442 pTpWaitForTimer(timer, FALSE);
1443
1445 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1447 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1448 success = pTpIsTimerSet(timer);
1449 ok(success, "TpIsTimerSet returned FALSE\n");
1450
1451 /* test timer with an absolute timeout */
1452 NtQuerySystemTime( &when );
1453 when.QuadPart += (ULONGLONG)200 * 10000;
1454 pTpSetTimer(timer, &when, 0, 0);
1455 success = pTpIsTimerSet(timer);
1456 ok(success, "TpIsTimerSet returned FALSE\n");
1457
1458 pTpWaitForTimer(timer, FALSE);
1459
1461 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1463 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1464 success = pTpIsTimerSet(timer);
1465 ok(success, "TpIsTimerSet returned FALSE\n");
1466
1467 /* test timer with zero timeout */
1468 when.QuadPart = 0;
1469 pTpSetTimer(timer, &when, 0, 0);
1470 success = pTpIsTimerSet(timer);
1471 ok(success, "TpIsTimerSet returned FALSE\n");
1472
1473 pTpWaitForTimer(timer, FALSE);
1474
1476 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1477 success = pTpIsTimerSet(timer);
1478 ok(success, "TpIsTimerSet returned FALSE\n");
1479
1480 /* unset the timer */
1481 pTpSetTimer(timer, NULL, 0, 0);
1482 success = pTpIsTimerSet(timer);
1483 ok(!success, "TpIsTimerSet returned TRUE\n");
1484 pTpWaitForTimer(timer, TRUE);
1485
1486 pTpReleaseTimer(timer);
1488
1490 ok(semaphore != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
1491
1492 /* allocate a new timer */
1493 timer = NULL;
1494 memset(&environment, 0, sizeof(environment));
1495 environment.Version = 1;
1496 environment.Pool = pool;
1497 status = pTpAllocTimer(&timer, timer_cb, semaphore, &environment);
1498 ok(!status, "TpAllocTimer failed with status %lx\n", status);
1499 ok(timer != NULL, "expected timer != NULL\n");
1500
1501 /* test a relative timeout repeated periodically */
1502 when.QuadPart = (ULONGLONG)200 * -10000;
1503 pTpSetTimer(timer, &when, 200, 0);
1504 success = pTpIsTimerSet(timer);
1505 ok(success, "TpIsTimerSet returned FALSE\n");
1506
1507 /* wait until the timer was triggered three times */
1508 ticks = GetTickCount();
1509 for (i = 0; i < 3; i++)
1510 {
1512 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1513 }
1514 ticks = GetTickCount() - ticks;
1515 ok(ticks >= 500 && (ticks <= 700 || broken(ticks <= 750)) /* Win 7 */,
1516 "expected approximately 600 ticks, got %lu\n", ticks);
1517
1518 /* unset the timer */
1519 pTpSetTimer(timer, NULL, 0, 0);
1520 success = pTpIsTimerSet(timer);
1521 ok(!success, "TpIsTimerSet returned TRUE\n");
1522 pTpWaitForTimer(timer, TRUE);
1523
1524 /* cleanup */
1525 pTpReleaseTimer(timer);
1526 pTpReleasePool(pool);
1528}
1529
1531{
1534};
1535
1537{
1538 struct window_length_info *info = userdata;
1539 info->ticks = GetTickCount();
1540 ReleaseSemaphore(info->semaphore, 1, NULL);
1541}
1542
1543static void test_tp_window_length(void)
1544{
1545 struct window_length_info info1, info2;
1546 TP_CALLBACK_ENVIRON environment;
1547 TP_TIMER *timer1, *timer2;
1548 LARGE_INTEGER when;
1551 TP_POOL *pool;
1552 DWORD result;
1553 BOOL merged;
1554
1556 ok(semaphore != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
1557
1558 /* allocate new threadpool */
1559 pool = NULL;
1560 status = pTpAllocPool(&pool, NULL);
1561 ok(!status, "TpAllocPool failed with status %lx\n", status);
1562 ok(pool != NULL, "expected pool != NULL\n");
1563
1564 /* allocate two identical timers */
1565 memset(&environment, 0, sizeof(environment));
1566 environment.Version = 1;
1567 environment.Pool = pool;
1568
1569 timer1 = NULL;
1570 info1.semaphore = semaphore;
1571 status = pTpAllocTimer(&timer1, window_length_cb, &info1, &environment);
1572 ok(!status, "TpAllocTimer failed with status %lx\n", status);
1573 ok(timer1 != NULL, "expected timer1 != NULL\n");
1574
1575 timer2 = NULL;
1576 info2.semaphore = semaphore;
1577 status = pTpAllocTimer(&timer2, window_length_cb, &info2, &environment);
1578 ok(!status, "TpAllocTimer failed with status %lx\n", status);
1579 ok(timer2 != NULL, "expected timer2 != NULL\n");
1580
1581 /* choose parameters so that timers are not merged */
1582 info1.ticks = 0;
1583 info2.ticks = 0;
1584
1585 NtQuerySystemTime( &when );
1586 when.QuadPart += (ULONGLONG)250 * 10000;
1587 pTpSetTimer(timer2, &when, 0, 0);
1588 Sleep(50);
1589 when.QuadPart -= (ULONGLONG)150 * 10000;
1590 pTpSetTimer(timer1, &when, 0, 75);
1591
1593 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1595 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1596 ok(info1.ticks != 0 && info2.ticks != 0, "expected that ticks are nonzero\n");
1597 ok(info2.ticks >= info1.ticks + 75 || broken(info2.ticks < info1.ticks + 75) /* Win 2008 */,
1598 "expected that timers are not merged\n");
1599
1600 /* timers will be merged */
1601 info1.ticks = 0;
1602 info2.ticks = 0;
1603
1604 NtQuerySystemTime( &when );
1605 when.QuadPart += (ULONGLONG)250 * 10000;
1606 pTpSetTimer(timer2, &when, 0, 0);
1607 Sleep(50);
1608 when.QuadPart -= (ULONGLONG)150 * 10000;
1609 pTpSetTimer(timer1, &when, 0, 200);
1610
1612 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1614 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1615 ok(info1.ticks != 0 && info2.ticks != 0, "expected that ticks are nonzero\n");
1616 merged = info2.ticks >= info1.ticks - 50 && info2.ticks <= info1.ticks + 50;
1617 ok(merged || broken(!merged) /* Win 10 */, "expected that timers are merged\n");
1618
1619 /* on Windows the timers also get merged in this case */
1620 info1.ticks = 0;
1621 info2.ticks = 0;
1622
1623 NtQuerySystemTime( &when );
1624 when.QuadPart += (ULONGLONG)100 * 10000;
1625 pTpSetTimer(timer1, &when, 0, 200);
1626 Sleep(50);
1627 when.QuadPart += (ULONGLONG)150 * 10000;
1628 pTpSetTimer(timer2, &when, 0, 0);
1629
1631 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1633 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1634 ok(info1.ticks != 0 && info2.ticks != 0, "expected that ticks are nonzero\n");
1635 merged = info2.ticks >= info1.ticks - 50 && info2.ticks <= info1.ticks + 50;
1636 todo_wine
1637 ok(merged || broken(!merged) /* Win 10 */, "expected that timers are merged\n");
1638
1639 /* cleanup */
1640 pTpReleaseTimer(timer1);
1641 pTpReleaseTimer(timer2);
1642 pTpReleasePool(pool);
1644}
1645
1647{
1650};
1651
1652static void CALLBACK wait_cb(TP_CALLBACK_INSTANCE *instance, void *userdata,
1654{
1655 struct wait_info *info = userdata;
1656 if (result == WAIT_OBJECT_0)
1657 InterlockedIncrement(&info->userdata);
1658 else if (result == WAIT_TIMEOUT)
1659 InterlockedExchangeAdd(&info->userdata, 0x10000);
1660 else
1661 ok(0, "unexpected result %lu\n", result);
1662 ReleaseSemaphore(info->semaphore, 1, NULL);
1663}
1664
1665static void test_tp_wait(void)
1666{
1667 TP_CALLBACK_ENVIRON environment;
1668 TP_WAIT *wait1, *wait2;
1669 struct wait_info info;
1670 HANDLE semaphores[2];
1671 LARGE_INTEGER when;
1673 TP_POOL *pool;
1674 DWORD result;
1675
1676 semaphores[0] = CreateSemaphoreW(NULL, 0, 2, NULL);
1677 ok(semaphores[0] != NULL, "failed to create semaphore\n");
1678 semaphores[1] = CreateSemaphoreW(NULL, 0, 1, NULL);
1679 ok(semaphores[1] != NULL, "failed to create semaphore\n");
1680 info.semaphore = semaphores[0];
1681
1682 /* allocate new threadpool */
1683 pool = NULL;
1684 status = pTpAllocPool(&pool, NULL);
1685 ok(!status, "TpAllocPool failed with status %lx\n", status);
1686 ok(pool != NULL, "expected pool != NULL\n");
1687
1688 /* allocate new wait items */
1689 memset(&environment, 0, sizeof(environment));
1690 environment.Version = 1;
1691 environment.Pool = pool;
1692
1693 wait1 = NULL;
1694 status = pTpAllocWait(&wait1, wait_cb, &info, &environment);
1695 ok(!status, "TpAllocWait failed with status %lx\n", status);
1696 ok(wait1 != NULL, "expected wait1 != NULL\n");
1697
1698 wait2 = NULL;
1699 status = pTpAllocWait(&wait2, wait_cb, &info, &environment);
1700 ok(!status, "TpAllocWait failed with status %lx\n", status);
1701 ok(wait2 != NULL, "expected wait2 != NULL\n");
1702
1703 /* infinite timeout, signal the semaphore immediately */
1704 info.userdata = 0;
1705 pTpSetWait(wait1, semaphores[1], NULL);
1706 ReleaseSemaphore(semaphores[1], 1, NULL);
1707 result = WaitForSingleObject(semaphores[0], 100);
1708 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1709 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
1710 result = WaitForSingleObject(semaphores[1], 0);
1711 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1712
1713 /* relative timeout, no event */
1714 info.userdata = 0;
1715 when.QuadPart = (ULONGLONG)200 * -10000;
1716 pTpSetWait(wait1, semaphores[1], &when);
1717 result = WaitForSingleObject(semaphores[0], 100);
1718 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1719 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
1720 result = WaitForSingleObject(semaphores[0], 200);
1721 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1722 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
1723 result = WaitForSingleObject(semaphores[1], 0);
1724 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1725
1726 /* repeat test with call to TpWaitForWait(..., TRUE) */
1727 info.userdata = 0;
1728 when.QuadPart = (ULONGLONG)200 * -10000;
1729 pTpSetWait(wait1, semaphores[1], &when);
1730 result = WaitForSingleObject(semaphores[0], 100);
1731 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1732 pTpWaitForWait(wait1, TRUE);
1733 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
1734 result = WaitForSingleObject(semaphores[0], 200);
1735 ok(result == WAIT_OBJECT_0 || broken(result == WAIT_TIMEOUT) /* Win 8 */,
1736 "WaitForSingleObject returned %lu\n", result);
1737 if (result == WAIT_OBJECT_0)
1738 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
1739 else
1740 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
1741 result = WaitForSingleObject(semaphores[1], 0);
1742 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1743
1744 /* relative timeout, with event */
1745 info.userdata = 0;
1746 when.QuadPart = (ULONGLONG)200 * -10000;
1747 pTpSetWait(wait1, semaphores[1], &when);
1748 result = WaitForSingleObject(semaphores[0], 100);
1749 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1750 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
1751 ReleaseSemaphore(semaphores[1], 1, NULL);
1752 result = WaitForSingleObject(semaphores[0], 100);
1753 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1754 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
1755 result = WaitForSingleObject(semaphores[1], 0);
1756 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1757
1758 /* repeat test with call to TpWaitForWait(..., TRUE) */
1759 info.userdata = 0;
1760 when.QuadPart = (ULONGLONG)200 * -10000;
1761 pTpSetWait(wait1, semaphores[1], &when);
1762 result = WaitForSingleObject(semaphores[0], 100);
1763 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1764 pTpWaitForWait(wait1, TRUE);
1765 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
1766 ReleaseSemaphore(semaphores[1], 1, NULL);
1767 result = WaitForSingleObject(semaphores[0], 100);
1768 ok(result == WAIT_OBJECT_0 || broken(result == WAIT_TIMEOUT) /* Win 8 */,
1769 "WaitForSingleObject returned %lu\n", result);
1770 if (result == WAIT_OBJECT_0)
1771 {
1772 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
1773 result = WaitForSingleObject(semaphores[1], 0);
1774 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1775 }
1776 else
1777 {
1778 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
1779 result = WaitForSingleObject(semaphores[1], 0);
1780 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1781 }
1782
1783 /* absolute timeout, no event */
1784 info.userdata = 0;
1785 NtQuerySystemTime( &when );
1786 when.QuadPart += (ULONGLONG)200 * 10000;
1787 pTpSetWait(wait1, semaphores[1], &when);
1788 result = WaitForSingleObject(semaphores[0], 100);
1789 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1790 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
1791 result = WaitForSingleObject(semaphores[0], 200);
1792 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1793 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
1794 result = WaitForSingleObject(semaphores[1], 0);
1795 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1796
1797 /* absolute timeout, with event */
1798 info.userdata = 0;
1799 NtQuerySystemTime( &when );
1800 when.QuadPart += (ULONGLONG)200 * 10000;
1801 pTpSetWait(wait1, semaphores[1], &when);
1802 result = WaitForSingleObject(semaphores[0], 100);
1803 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1804 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
1805 ReleaseSemaphore(semaphores[1], 1, NULL);
1806 result = WaitForSingleObject(semaphores[0], 100);
1807 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1808 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
1809 result = WaitForSingleObject(semaphores[1], 0);
1810 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1811
1812 /* test timeout of zero */
1813 info.userdata = 0;
1814 when.QuadPart = 0;
1815 pTpSetWait(wait1, semaphores[1], &when);
1816 result = WaitForSingleObject(semaphores[0], 100);
1817 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1818 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
1819 result = WaitForSingleObject(semaphores[1], 0);
1820 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1821
1822 /* cancel a pending wait */
1823 info.userdata = 0;
1824 when.QuadPart = (ULONGLONG)250 * -10000;
1825 pTpSetWait(wait1, semaphores[1], &when);
1826 result = WaitForSingleObject(semaphores[0], 100);
1827 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1828 pTpSetWait(wait1, NULL, (void *)0xdeadbeef);
1829 Sleep(50);
1830 ReleaseSemaphore(semaphores[1], 1, NULL);
1831 result = WaitForSingleObject(semaphores[0], 100);
1832 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1833 ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
1834 result = WaitForSingleObject(semaphores[1], 0);
1835 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1836
1837 /* test with INVALID_HANDLE_VALUE */
1838 info.userdata = 0;
1839 when.QuadPart = 0;
1840 pTpSetWait(wait1, INVALID_HANDLE_VALUE, &when);
1841 result = WaitForSingleObject(semaphores[0], 100);
1842 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1843 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
1844
1845 /* cancel a pending wait with INVALID_HANDLE_VALUE */
1846 info.userdata = 0;
1847 when.QuadPart = (ULONGLONG)250 * -10000;
1848 pTpSetWait(wait1, semaphores[1], &when);
1849 result = WaitForSingleObject(semaphores[0], 100);
1850 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1851 when.QuadPart = 0;
1852 pTpSetWait(wait1, INVALID_HANDLE_VALUE, &when);
1853 Sleep(50);
1854 ReleaseSemaphore(semaphores[1], 1, NULL);
1855 result = WaitForSingleObject(semaphores[0], 100);
1856 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1857 ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
1858 result = WaitForSingleObject(semaphores[1], 0);
1859 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1860
1861 CloseHandle(semaphores[1]);
1862 semaphores[1] = CreateSemaphoreW(NULL, 0, 2, NULL);
1863 ok(semaphores[1] != NULL, "failed to create semaphore\n");
1864
1865 /* add two wait objects with the same semaphore */
1866 info.userdata = 0;
1867 pTpSetWait(wait1, semaphores[1], NULL);
1868 pTpSetWait(wait2, semaphores[1], NULL);
1869 Sleep(50);
1870 ReleaseSemaphore(semaphores[1], 1, NULL);
1871 result = WaitForSingleObject(semaphores[0], 100);
1872 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1873 result = WaitForSingleObject(semaphores[0], 100);
1874 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1875 ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
1876 result = WaitForSingleObject(semaphores[1], 0);
1877 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1878
1879 /* repeat test above with release count 2 */
1880 info.userdata = 0;
1881 pTpSetWait(wait1, semaphores[1], NULL);
1882 pTpSetWait(wait2, semaphores[1], NULL);
1883 Sleep(50);
1884 result = ReleaseSemaphore(semaphores[1], 2, NULL);
1885 result = WaitForSingleObject(semaphores[0], 100);
1886 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1887 result = WaitForSingleObject(semaphores[0], 100);
1888 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1889 ok(info.userdata == 2, "expected info.userdata = 2, got %lu\n", info.userdata);
1890 result = WaitForSingleObject(semaphores[1], 0);
1891 ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1892
1893 /* cleanup */
1894 pTpReleaseWait(wait1);
1895 pTpReleaseWait(wait2);
1896 pTpReleasePool(pool);
1897 CloseHandle(semaphores[0]);
1898 CloseHandle(semaphores[1]);
1899}
1900
1901static struct
1902{
1906
1908{
1910
1911 if (result == WAIT_OBJECT_0)
1912 multi_wait_info.result = index;
1913 else if (result == WAIT_TIMEOUT)
1914 multi_wait_info.result = 0x10000 | index;
1915 else
1916 ok(0, "unexpected result %lu\n", result);
1917 ReleaseSemaphore(multi_wait_info.semaphore, 1, NULL);
1918}
1919
1920static void test_tp_multi_wait(void)
1921{
1922 TP_POOL_STACK_INFORMATION stack_info;
1923 TP_CALLBACK_ENVIRON environment;
1924 HANDLE semaphores[512];
1925 TP_WAIT *waits[512];
1926 LARGE_INTEGER when;
1929 TP_POOL *pool;
1930 DWORD result;
1931 int i;
1932
1933#ifdef __REACTOS__
1934 if (pTpSetPoolStackInformation == NULL)
1935 {
1936 win_skip("TpSetPoolStackInformation not available\n");
1937 return;
1938 }
1939#endif
1940
1941 semaphore = CreateSemaphoreW(NULL, 0, 512, NULL);
1942 ok(semaphore != NULL, "failed to create semaphore\n");
1943 multi_wait_info.semaphore = semaphore;
1944
1945 /* allocate new threadpool */
1946 pool = NULL;
1947 status = pTpAllocPool(&pool, NULL);
1948 ok(!status, "TpAllocPool failed with status %lx\n", status);
1949 ok(pool != NULL, "expected pool != NULL\n");
1950 /* many threads -> use the smallest stack possible */
1951 stack_info.StackReserve = 256 * 1024;
1952 stack_info.StackCommit = 4 * 1024;
1953 status = pTpSetPoolStackInformation(pool, &stack_info);
1954 ok(!status, "TpQueryPoolStackInformation failed: %lx\n", status);
1955
1956 memset(&environment, 0, sizeof(environment));
1957 environment.Version = 1;
1958 environment.Pool = pool;
1959
1960 /* create semaphores and corresponding wait objects */
1961 for (i = 0; i < ARRAY_SIZE(semaphores); i++)
1962 {
1963 semaphores[i] = CreateSemaphoreW(NULL, 0, 1, NULL);
1964 ok(semaphores[i] != NULL, "failed to create semaphore %i\n", i);
1965
1966 waits[i] = NULL;
1967 status = pTpAllocWait(&waits[i], multi_wait_cb, (void *)(DWORD_PTR)i, &environment);
1968 ok(!status, "TpAllocWait failed with status %lx\n", status);
1969 ok(waits[i] != NULL, "expected waits[%d] != NULL\n", i);
1970
1971 pTpSetWait(waits[i], semaphores[i], NULL);
1972 }
1973
1974 /* release all semaphores and wait for callback */
1975 for (i = 0; i < ARRAY_SIZE(semaphores); i++)
1976 {
1977 multi_wait_info.result = 0;
1978 ReleaseSemaphore(semaphores[i], 1, NULL);
1979
1981 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1982 ok(multi_wait_info.result == i, "expected result %d, got %lu\n", i, multi_wait_info.result);
1983
1984 pTpSetWait(waits[i], semaphores[i], NULL);
1985 }
1986
1987 /* repeat the same test in reverse order */
1988 for (i = ARRAY_SIZE(semaphores) - 1; i >= 0; i--)
1989 {
1990 multi_wait_info.result = 0;
1991 ReleaseSemaphore(semaphores[i], 1, NULL);
1992
1994 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1995 ok(multi_wait_info.result == i, "expected result %d, got %lu\n", i, multi_wait_info.result);
1996
1997 pTpSetWait(waits[i], semaphores[i], NULL);
1998 }
1999
2000 /* test timeout of wait objects */
2001 multi_wait_info.result = 0;
2002 for (i = 0; i < ARRAY_SIZE(semaphores); i++)
2003 {
2004 when.QuadPart = (ULONGLONG)50 * -10000;
2005 pTpSetWait(waits[i], semaphores[i], &when);
2006 }
2007
2008 for (i = 0; i < ARRAY_SIZE(semaphores); i++)
2009 {
2011 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
2012 }
2013
2014 ok(multi_wait_info.result >> 16, "expected multi_wait_info.result >> 16 != 0\n");
2015
2016 /* destroy the wait objects and semaphores while waiting */
2017 for (i = 0; i < ARRAY_SIZE(semaphores); i++)
2018 {
2019 pTpSetWait(waits[i], semaphores[i], NULL);
2020 }
2021
2022 Sleep(50);
2023
2024 for (i = 0; i < ARRAY_SIZE(semaphores); i++)
2025 {
2026 pTpReleaseWait(waits[i]);
2027 NtClose(semaphores[i]);
2028 }
2029
2030 pTpReleasePool(pool);
2032}
2033
2035{
2036 unsigned int count;
2037 void *ovl;
2041};
2042
2043static void CALLBACK io_cb(TP_CALLBACK_INSTANCE *instance, void *userdata,
2044 void *cvalue, IO_STATUS_BLOCK *iosb, TP_IO *io)
2045{
2046 struct io_cb_ctx *ctx = userdata;
2047 ++ctx->count;
2048 ctx->ovl = cvalue;
2049 ctx->ret = iosb->Status;
2050 ctx->length = iosb->Information;
2051 ctx->io = io;
2052}
2053
2055{
2056 TP_IO *io = arg;
2057 pTpWaitForIoCompletion(io, FALSE);
2058 return 0;
2059}
2060
2061static void test_tp_io(void)
2062{
2063 TP_CALLBACK_ENVIRON environment = {.Version = 1};
2064 OVERLAPPED ovl = {0}, ovl2 = {0};
2066 struct io_cb_ctx userdata;
2067 char in[1], in2[1];
2068 const char out[1];
2071 TP_POOL *pool;
2072 TP_IO *io;
2073 BOOL ret;
2074
2075 ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
2076
2077 status = pTpAllocPool(&pool, NULL);
2078 ok(!status, "failed to allocate pool, status %#lx\n", status);
2079
2080 server = CreateNamedPipeA("\\\\.\\pipe\\wine_tp_test",
2081 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0, 1, 1024, 1024, 0, NULL);
2082 ok(server != INVALID_HANDLE_VALUE, "Failed to create server pipe, error %lu.\n", GetLastError());
2083 client = CreateFileA("\\\\.\\pipe\\wine_tp_test", GENERIC_READ | GENERIC_WRITE,
2084 0, NULL, OPEN_EXISTING, 0, 0);
2085 ok(client != INVALID_HANDLE_VALUE, "Failed to create client pipe, error %lu.\n", GetLastError());
2086
2087 environment.Pool = pool;
2088 io = NULL;
2089 status = pTpAllocIoCompletion(&io, server, io_cb, &userdata, &environment);
2090 ok(!status, "got %#lx\n", status);
2091 ok(!!io, "expected non-NULL TP_IO\n");
2092
2093 pTpWaitForIoCompletion(io, FALSE);
2094
2095 userdata.count = 0;
2096 pTpStartAsyncIoOperation(io);
2097
2099 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "TpWaitForIoCompletion() should not return\n");
2100
2101 ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
2102 ok(!ret, "wrong ret %d\n", ret);
2103 ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError());
2104
2105 ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
2106 ok(ret, "WriteFile() failed, error %lu\n", GetLastError());
2107
2108 pTpWaitForIoCompletion(io, FALSE);
2109 ok(userdata.count == 1, "callback ran %u times\n", userdata.count);
2110 ok(userdata.ovl == &ovl, "expected %p, got %p\n", &ovl, userdata.ovl);
2111 ok(userdata.ret == STATUS_SUCCESS, "got status %#lx\n", userdata.ret);
2112 ok(userdata.length == 1, "got length %Iu\n", userdata.length);
2113 ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io);
2114
2115 ok(!WaitForSingleObject(thread, 1000), "wait timed out\n");
2117
2118 userdata.count = 0;
2119 pTpStartAsyncIoOperation(io);
2120 pTpStartAsyncIoOperation(io);
2121
2122 ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
2123 ok(!ret, "wrong ret %d\n", ret);
2124 ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError());
2125 ret = ReadFile(server, in2, sizeof(in2), NULL, &ovl2);
2126 ok(!ret, "wrong ret %d\n", ret);
2127 ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError());
2128
2129 ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
2130 ok(ret, "WriteFile() failed, error %lu\n", GetLastError());
2131 ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
2132 ok(ret, "WriteFile() failed, error %lu\n", GetLastError());
2133
2134 pTpWaitForIoCompletion(io, FALSE);
2135 ok(userdata.count == 2, "callback ran %u times\n", userdata.count);
2136 ok(userdata.ret == STATUS_SUCCESS, "got status %#lx\n", userdata.ret);
2137 ok(userdata.length == 1, "got length %Iu\n", userdata.length);
2138 ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io);
2139
2140 /* The documentation is a bit unclear about passing TRUE to
2141 * WaitForThreadpoolIoCallbacks()—"pending I/O requests are not canceled"
2142 * [as with CancelIoEx()], but pending threadpool callbacks are, even those
2143 * which have not yet reached the completion port [as with
2144 * TpCancelAsyncIoOperation()]. */
2145 userdata.count = 0;
2146 pTpStartAsyncIoOperation(io);
2147
2148 pTpWaitForIoCompletion(io, TRUE);
2149 ok(!userdata.count, "callback ran %u times\n", userdata.count);
2150
2151 pTpStartAsyncIoOperation(io);
2152
2153 ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
2154 ok(ret, "WriteFile() failed, error %lu\n", GetLastError());
2155
2156 ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
2157 ok(ret, "wrong ret %d\n", ret);
2158
2159 pTpWaitForIoCompletion(io, FALSE);
2160 ok(userdata.count == 1, "callback ran %u times\n", userdata.count);
2161 ok(userdata.ovl == &ovl, "expected %p, got %p\n", &ovl, userdata.ovl);
2162 ok(userdata.ret == STATUS_SUCCESS, "got status %#lx\n", userdata.ret);
2163 ok(userdata.length == 1, "got length %Iu\n", userdata.length);
2164 ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io);
2165
2166 userdata.count = 0;
2167 pTpStartAsyncIoOperation(io);
2168
2169 ret = ReadFile(server, NULL, 1, NULL, &ovl);
2170 ok(!ret, "wrong ret %d\n", ret);
2171 ok(GetLastError() == ERROR_NOACCESS, "wrong error %lu\n", GetLastError());
2172
2173 pTpCancelAsyncIoOperation(io);
2174 pTpWaitForIoCompletion(io, FALSE);
2175 ok(!userdata.count, "callback ran %u times\n", userdata.count);
2176
2177 userdata.count = 0;
2178 pTpStartAsyncIoOperation(io);
2179
2180 ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
2181 ok(!ret, "wrong ret %d\n", ret);
2182 ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError());
2183 ret = CancelIo(server);
2184 ok(ret, "CancelIo() failed, error %lu\n", GetLastError());
2185
2186 pTpWaitForIoCompletion(io, FALSE);
2187 ok(userdata.count == 1, "callback ran %u times\n", userdata.count);
2188 ok(userdata.ovl == &ovl, "expected %p, got %p\n", &ovl, userdata.ovl);
2189 ok(userdata.ret == STATUS_CANCELLED, "got status %#lx\n", userdata.ret);
2190 ok(!userdata.length, "got length %Iu\n", userdata.length);
2191 ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io);
2192
2193 userdata.count = 0;
2194 pTpStartAsyncIoOperation(io);
2195 pTpCancelAsyncIoOperation(io);
2196 ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
2197 ok(!ret, "wrong ret %d\n", ret);
2198 ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
2199 ok(ret, "WriteFile() failed, error %lu\n", GetLastError());
2200 ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError());
2201
2202 pTpWaitForIoCompletion(io, FALSE);
2203 if (0)
2204 {
2205 /* Add a sleep to check that callback is not called later. Commented out to
2206 * save the test time. */
2207 Sleep(200);
2208 }
2209 ok(userdata.count == 0, "callback ran %u times\n", userdata.count);
2210
2211 pTpReleaseIoCompletion(io);
2213
2214 /* Test TPIO object destruction. */
2215 server = CreateNamedPipeA("\\\\.\\pipe\\wine_tp_test",
2216 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0, 1, 1024, 1024, 0, NULL);
2217 ok(server != INVALID_HANDLE_VALUE, "Failed to create server pipe, error %lu.\n", GetLastError());
2218 io = NULL;
2219 status = pTpAllocIoCompletion(&io, server, io_cb, &userdata, &environment);
2220 ok(!status, "got %#lx\n", status);
2221
2223 ok(ret, "Got unexpected ret %#x.\n", ret);
2224 pTpReleaseIoCompletion(io);
2226 ok(!ret, "Got unexpected ret %#x.\n", ret);
2229
2230 server = CreateNamedPipeA("\\\\.\\pipe\\wine_tp_test",
2231 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0, 1, 1024, 1024, 0, NULL);
2232 ok(server != INVALID_HANDLE_VALUE, "Failed to create server pipe, error %lu.\n", GetLastError());
2233 client = CreateFileA("\\\\.\\pipe\\wine_tp_test", GENERIC_READ | GENERIC_WRITE,
2234 0, NULL, OPEN_EXISTING, 0, 0);
2235 ok(client != INVALID_HANDLE_VALUE, "Failed to create client pipe, error %lu.\n", GetLastError());
2236
2237 io = NULL;
2238 status = pTpAllocIoCompletion(&io, server, io_cb, &userdata, &environment);
2239 ok(!status, "got %#lx\n", status);
2240 pTpStartAsyncIoOperation(io);
2241 pTpWaitForIoCompletion(io, TRUE);
2243 ok(ret, "Got unexpected ret %#x.\n", ret);
2244 pTpReleaseIoCompletion(io);
2246 ok(ret, "Got unexpected ret %#x.\n", ret);
2247
2248 if (0)
2249 {
2250 /* Object destruction will wait until one completion arrives (which was started but not cancelled).
2251 * Commented out to save test time. */
2252 Sleep(1000);
2254 ok(ret, "Got unexpected ret %#x.\n", ret);
2255 ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
2256 ok(!ret, "wrong ret %d\n", ret);
2257 ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
2258 ok(ret, "WriteFile() failed, error %lu\n", GetLastError());
2259 Sleep(2000);
2261 ok(!ret, "Got unexpected ret %#x.\n", ret);
2262 }
2263
2265 CloseHandle(ovl.hEvent);
2267 pTpReleasePool(pool);
2268}
2269
2271 void *ovl, ULONG ret, ULONG_PTR length, TP_IO *io)
2272{
2273 struct io_cb_ctx *ctx = userdata;
2274 ++ctx->count;
2275 ctx->ovl = ovl;
2276 ctx->ret = ret;
2277 ctx->length = length;
2278 ctx->io = io;
2279}
2280
2281static void test_kernel32_tp_io(void)
2282{
2283 TP_CALLBACK_ENVIRON environment = {.Version = 1};
2284 OVERLAPPED ovl = {0}, ovl2 = {0};
2286 struct io_cb_ctx userdata;
2287 char in[1], in2[1];
2288 const char out[1];
2291 TP_POOL *pool;
2292 TP_IO *io;
2293 BOOL ret;
2294
2295 ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
2296
2297 status = pTpAllocPool(&pool, NULL);
2298 ok(!status, "failed to allocate pool, status %#lx\n", status);
2299
2300 server = CreateNamedPipeA("\\\\.\\pipe\\wine_tp_test",
2301 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0, 1, 1024, 1024, 0, NULL);
2302 ok(server != INVALID_HANDLE_VALUE, "Failed to create server pipe, error %lu.\n", GetLastError());
2303 client = CreateFileA("\\\\.\\pipe\\wine_tp_test", GENERIC_READ | GENERIC_WRITE,
2304 0, NULL, OPEN_EXISTING, 0, 0);
2305 ok(client != INVALID_HANDLE_VALUE, "Failed to create client pipe, error %lu.\n", GetLastError());
2306
2307 environment.Pool = pool;
2308 io = NULL;
2309 io = pCreateThreadpoolIo(server, kernel32_io_cb, &userdata, &environment);
2310 ok(!!io, "expected non-NULL TP_IO\n");
2311
2312 pWaitForThreadpoolIoCallbacks(io, FALSE);
2313
2314 userdata.count = 0;
2315 pStartThreadpoolIo(io);
2316
2318 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "TpWaitForIoCompletion() should not return\n");
2319
2320 ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
2321 ok(!ret, "wrong ret %d\n", ret);
2322 ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError());
2323
2324 ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
2325 ok(ret, "WriteFile() failed, error %lu\n", GetLastError());
2326
2327 pWaitForThreadpoolIoCallbacks(io, FALSE);
2328 ok(userdata.count == 1, "callback ran %u times\n", userdata.count);
2329 ok(userdata.ovl == &ovl, "expected %p, got %p\n", &ovl, userdata.ovl);
2330 ok(userdata.ret == ERROR_SUCCESS, "got status %#lx\n", userdata.ret);
2331 ok(userdata.length == 1, "got length %Iu\n", userdata.length);
2332 ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io);
2333
2334 ok(!WaitForSingleObject(thread, 1000), "wait timed out\n");
2336
2337 userdata.count = 0;
2338 pStartThreadpoolIo(io);
2339 pStartThreadpoolIo(io);
2340
2341 ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
2342 ok(!ret, "wrong ret %d\n", ret);
2343 ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError());
2344 ret = ReadFile(server, in2, sizeof(in2), NULL, &ovl2);
2345 ok(!ret, "wrong ret %d\n", ret);
2346 ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError());
2347
2348 ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
2349 ok(ret, "WriteFile() failed, error %lu\n", GetLastError());
2350 ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
2351 ok(ret, "WriteFile() failed, error %lu\n", GetLastError());
2352
2353 pWaitForThreadpoolIoCallbacks(io, FALSE);
2354 ok(userdata.count == 2, "callback ran %u times\n", userdata.count);
2355 ok(userdata.ret == STATUS_SUCCESS, "got status %#lx\n", userdata.ret);
2356 ok(userdata.length == 1, "got length %Iu\n", userdata.length);
2357 ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io);
2358
2359 userdata.count = 0;
2360 pStartThreadpoolIo(io);
2361 pWaitForThreadpoolIoCallbacks(io, TRUE);
2362 ok(!userdata.count, "callback ran %u times\n", userdata.count);
2363
2364 pStartThreadpoolIo(io);
2365
2366 ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
2367 ok(ret, "WriteFile() failed, error %lu\n", GetLastError());
2368
2369 ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
2370 ok(ret, "wrong ret %d\n", ret);
2371
2372 pWaitForThreadpoolIoCallbacks(io, FALSE);
2373 ok(userdata.count == 1, "callback ran %u times\n", userdata.count);
2374 ok(userdata.ovl == &ovl, "expected %p, got %p\n", &ovl, userdata.ovl);
2375 ok(userdata.ret == ERROR_SUCCESS, "got status %#lx\n", userdata.ret);
2376 ok(userdata.length == 1, "got length %Iu\n", userdata.length);
2377 ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io);
2378
2379 userdata.count = 0;
2380 pStartThreadpoolIo(io);
2381
2382 ret = ReadFile(server, NULL, 1, NULL, &ovl);
2383 ok(!ret, "wrong ret %d\n", ret);
2384 ok(GetLastError() == ERROR_NOACCESS, "wrong error %lu\n", GetLastError());
2385
2386 pCancelThreadpoolIo(io);
2387 pWaitForThreadpoolIoCallbacks(io, FALSE);
2388 ok(!userdata.count, "callback ran %u times\n", userdata.count);
2389
2390 userdata.count = 0;
2391 pStartThreadpoolIo(io);
2392
2393 ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
2394 ok(!ret, "wrong ret %d\n", ret);
2395 ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError());
2396 ret = CancelIo(server);
2397 ok(ret, "CancelIo() failed, error %lu\n", GetLastError());
2398
2399 pWaitForThreadpoolIoCallbacks(io, FALSE);
2400 ok(userdata.count == 1, "callback ran %u times\n", userdata.count);
2401 ok(userdata.ovl == &ovl, "expected %p, got %p\n", &ovl, userdata.ovl);
2402 ok(userdata.ret == ERROR_OPERATION_ABORTED, "got status %#lx\n", userdata.ret);
2403 ok(!userdata.length, "got length %Iu\n", userdata.length);
2404 ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io);
2405
2406 CloseHandle(ovl.hEvent);
2409 pCloseThreadpoolIo(io);
2410 pTpReleasePool(pool);
2411}
2412
2414{
2417
2418 if (!init_threadpool())
2419 return;
2420
2422 test_tp_work();
2428 test_tp_timer();
2430 test_tp_wait();
2432 test_tp_io();
2434}
#define VOID
Definition: acefi.h:82
unsigned char BOOLEAN
Definition: actypes.h:127
#define InterlockedIncrement
Definition: armddk.h:53
#define ok(value,...)
Definition: atltest.h:57
#define skip(...)
Definition: atltest.h:64
#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
#define ARRAY_SIZE(A)
Definition: main.h:20
static HANDLE thread
Definition: service.c:33
#define WAIT_TIMEOUT
Definition: dderror.h:14
#define ERROR_IO_PENDING
Definition: dderror.h:15
PIMAGE_NT_HEADERS nt
Definition: delayimp.cpp:445
#define ERROR_SUCCESS
Definition: deptool.c:10
BOOL WINAPI CancelIo(IN HANDLE hFile)
Definition: deviceio.c:290
#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 GetProcessHeap()
Definition: compat.h:736
#define OPEN_EXISTING
Definition: compat.h:775
#define ReadFile(a, b, c, d, e)
Definition: compat.h:742
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
#define CreateFileA(a, b, c, d, e, f, g)
Definition: compat.h:740
#define GENERIC_READ
Definition: compat.h:135
#define RtlImageNtHeader
Definition: compat.h:806
#define CALLBACK
Definition: compat.h:35
PPEB Peb
Definition: dllmain.c:27
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
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
HANDLE WINAPI DECLSPEC_HOTPATCH CreateThread(IN LPSECURITY_ATTRIBUTES lpThreadAttributes, IN DWORD dwStackSize, IN LPTHREAD_START_ROUTINE lpStartAddress, IN LPVOID lpParameter, IN DWORD dwCreationFlags, OUT LPDWORD lpThreadId)
Definition: thread.c:137
BOOL WINAPI DECLSPEC_HOTPATCH TpSimpleTryPost(PTP_SIMPLE_CALLBACK callback, PVOID userdata, TP_CALLBACK_ENVIRON *environment)
Definition: threadpool.c:3243
ULONG WINAPI DECLSPEC_HOTPATCH GetTickCount(void)
Definition: sync.c:182
PTP_IO WINAPI DECLSPEC_HOTPATCH CreateThreadpoolIo(HANDLE handle, PTP_WIN32_IO_CALLBACK callback, PVOID userdata, TP_CALLBACK_ENVIRON *environment)
Definition: thread.c:1286
return ret
Definition: mutex.c:146
#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
GLuint in
Definition: glext.h:9616
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
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
BOOL WINAPI HeapValidate(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem)
Definition: heapmem.c:156
#define THREAD_SET_CONTEXT
#define InterlockedExchangeAdd
Definition: interlocked.h:196
#define NtCurrentTeb
#define win_skip
Definition: minitest.h:67
#define todo_wine
Definition: minitest.h:80
#define FILE_FLAG_OVERLAPPED
Definition: disk.h:46
static HANDLE PIO_APC_ROUTINE PVOID PIO_STATUS_BLOCK io
Definition: file.c:72
static PIO_STATUS_BLOCK iosb
Definition: file.c:70
static void test_tp_io(void)
Definition: threadpool.c:2061
static void CALLBACK unexpected_group_cancel_cleanup_cb(void *object, void *userdata)
Definition: threadpool.c:1041
static DWORD WINAPI io_wait_thread(void *arg)
Definition: threadpool.c:2054
static void CALLBACK wait_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WAIT *wait, TP_WAIT_RESULT result)
Definition: threadpool.c:1652
static void CALLBACK simple_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
Definition: threadpool.c:573
static void CALLBACK disassociate2_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
Definition: threadpool.c:1268
HANDLE semaphore
Definition: threadpool.c:1903
static void CALLBACK work_group_cancel_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
Definition: threadpool.c:988
static void test_tp_work_scheduler(void)
Definition: threadpool.c:785
static void CALLBACK wait_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WAIT *wait, TP_WAIT_RESULT result)
Definition: threadpool.c:879
static void CALLBACK rtl_wait_apc_cb(ULONG_PTR userdata)
Definition: threadpool.c:203
static void test_tp_work(void)
Definition: threadpool.c:741
static void CALLBACK work_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
Definition: threadpool.c:729
static BOOL
Definition: threadpool.c:44
static void CALLBACK group_cancel_cleanup_release2_cb(void *object, void *userdata)
Definition: threadpool.c:1006
static HANDLE
Definition: threadpool.c:31
static void test_tp_timer(void)
Definition: threadpool.c:1403
static void CALLBACK instance_semaphore_completion_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
Definition: threadpool.c:1199
static void CALLBACK io_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, void *cvalue, IO_STATUS_BLOCK *iosb, TP_IO *io)
Definition: threadpool.c:2043
static TP_CALLBACK_ENVIRON *static TP_CALLBACK_ENVIRON *static PTP_WORK_CALLBACK
Definition: threadpool.c:35
static void CALLBACK disassociate_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
Definition: threadpool.c:1257
static TP_POOL_STACK_INFORMATION *static LARGE_INTEGER LONG
Definition: threadpool.c:52
static void test_tp_group_cancel(void)
Definition: threadpool.c:1046
static void test_tp_window_length(void)
Definition: threadpool.c:1543
static DWORD CALLBACK rtl_work_cb(void *userdata)
Definition: threadpool.c:128
static PTP_TIMER_CALLBACK
Definition: threadpool.c:33
static void test_tp_wait(void)
Definition: threadpool.c:1665
DWORD result
Definition: threadpool.c:1904
static void CALLBACK timer_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer)
Definition: threadpool.c:1397
static void test_tp_disassociate(void)
Definition: threadpool.c:1290
static void CALLBACK work2_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
Definition: threadpool.c:735
static PTP_IO_CALLBACK
Definition: threadpool.c:31
static void CALLBACK simple_group_cancel_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
Definition: threadpool.c:968
static DWORD
Definition: threadpool.c:37
static void CALLBACK rtl_wait_cb(void *userdata, BOOLEAN timeout)
Definition: threadpool.c:181
static void test_kernel32_tp_io(void)
Definition: threadpool.c:2281
static DWORD group_cancel_tid
Definition: threadpool.c:966
static HANDLE rtl_wait_apc_semaphore
Definition: threadpool.c:201
static void CALLBACK unexpected_work_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
Definition: threadpool.c:1025
static void test_tp_group_wait(void)
Definition: threadpool.c:888
#define GET_PROC(func)
Definition: threadpool.c:67
static void test_tp_multi_wait(void)
Definition: threadpool.c:1920
static void CALLBACK work_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
Definition: threadpool.c:863
static void CALLBACK unexpected_timer_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer)
Definition: threadpool.c:1030
static void CALLBACK disassociate3_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
Definition: threadpool.c:1279
static void test_tp_instance(void)
Definition: threadpool.c:1211
static TP_CALLBACK_ENVIRON *static PTP_WAIT_CALLBACK
Definition: threadpool.c:34
static struct @1834 multi_wait_info
static void CALLBACK group_cancel_cleanup_increment_cb(void *object, void *userdata)
Definition: threadpool.c:1014
static void CALLBACK kernel32_io_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, void *ovl, ULONG ret, ULONG_PTR length, TP_IO *io)
Definition: threadpool.c:2270
static void CALLBACK instance_finalization_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
Definition: threadpool.c:1205
static void CALLBACK simple2_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
Definition: threadpool.c:579
static void CALLBACK group_cancel_cleanup_release_cb(void *object, void *userdata)
Definition: threadpool.c:998
static void test_RtlRegisterWait(void)
Definition: threadpool.c:209
static BOOL init_threadpool(void)
Definition: threadpool.c:75
static void CALLBACK multi_wait_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WAIT *wait, TP_WAIT_RESULT result)
Definition: threadpool.c:1907
static void CALLBACK window_length_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer)
Definition: threadpool.c:1536
static void test_RtlQueueWorkItem(void)
Definition: threadpool.c:135
static void CALLBACK unexpected_simple_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
Definition: threadpool.c:1020
static TP_IO *WINAPI * pCreateThreadpoolIo(HANDLE, PTP_WIN32_IO_CALLBACK, void *, TP_CALLBACK_ENVIRON *)
static void CALLBACK unexpected_wait_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WAIT *wait, TP_WAIT_RESULT result)
Definition: threadpool.c:1035
static void CALLBACK timer_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer)
Definition: threadpool.c:871
static void TP_CALLBACK_ENVIRON *static PVOID
Definition: threadpool.c:32
static void CALLBACK simple_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
Definition: threadpool.c:856
static void test_tp_simple(void)
Definition: threadpool.c:585
static void ULONG ULONG * ret_size
Definition: time.c:40
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)
HANDLE WINAPI CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances, DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
Definition: npipe.c:220
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3402
#define GENERIC_WRITE
Definition: nt_native.h:90
NTSTATUS NTAPI NtQuerySystemTime(OUT PLARGE_INTEGER SystemTime)
Definition: time.c:563
#define STATUS_TOO_MANY_THREADS
Definition: ntstatus.h:627
long LONG
Definition: pedump.c:60
#define memset(x, y, z)
Definition: compat.h:39
static FILE * client
Definition: client.c:37
#define STATUS_SUCCESS
Definition: shellext.h:65
IMAGE_OPTIONAL_HEADER32 OptionalHeader
Definition: ntddk_ex.h:184
PVOID ImageBaseAddress
Definition: ntddk_ex.h:245
PTP_CLEANUP_GROUP CleanupGroup
Definition: winnt_old.h:4803
PTP_SIMPLE_CALLBACK FinalizationCallback
Definition: winnt_old.h:4807
TP_CALLBACK_PRIORITY CallbackPriority
Definition: winnt_old.h:4816
PTP_CLEANUP_GROUP_CANCEL_CALLBACK CleanupGroupCancelCallback
Definition: winnt_old.h:4804
void * ovl
Definition: threadpool.c:2037
ULONG_PTR length
Definition: threadpool.c:2039
TP_IO * io
Definition: threadpool.c:2040
unsigned int count
Definition: threadpool.c:2036
NTSTATUS ret
Definition: threadpool.c:2038
HANDLE semaphore1
Definition: threadpool.c:174
DWORD wait_result
Definition: threadpool.c:176
DWORD threadid
Definition: threadpool.c:177
HANDLE semaphore2
Definition: threadpool.c:175
Definition: ps.c:97
Definition: dhcpd.h:248
HANDLE semaphore
Definition: threadpool.c:1648
LONG userdata
Definition: threadpool.c:1649
DWORD WINAPI WaitForSingleObject(IN HANDLE hHandle, IN DWORD dwMilliseconds)
Definition: synch.c:82
VOID WINAPI DECLSPEC_HOTPATCH Sleep(IN DWORD dwMilliseconds)
Definition: synch.c:726
HANDLE WINAPI DECLSPEC_HOTPATCH CreateEventW(IN LPSECURITY_ATTRIBUTES lpEventAttributes OPTIONAL, IN BOOL bManualReset, IN BOOL bInitialState, IN LPCWSTR lpName OPTIONAL)
Definition: synch.c:587
HANDLE WINAPI DECLSPEC_HOTPATCH CreateSemaphoreW(IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes OPTIONAL, IN LONG lInitialCount, IN LONG lMaximumCount, IN LPCWSTR lpName OPTIONAL)
Definition: synch.c:406
BOOL WINAPI DECLSPEC_HOTPATCH ReleaseSemaphore(IN HANDLE hSemaphore, IN LONG lReleaseCount, IN LPLONG lpPreviousCount)
Definition: synch.c:491
HANDLE WINAPI DECLSPEC_HOTPATCH CreateSemaphoreA(IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes OPTIONAL, IN LONG lInitialCount, IN LONG lMaximumCount, IN LPCSTR lpName OPTIONAL)
Definition: synchansi.c:44
#define STATUS_PENDING
Definition: telnetd.h:14
VOID(WINAPI * PTP_WIN32_IO_CALLBACK)(_Inout_ PTP_CALLBACK_INSTANCE Instance, _Inout_opt_ PVOID Context, _Inout_opt_ PVOID Overlapped, _In_ ULONG IoResult, _In_ ULONG_PTR NumberOfBytesTransferred, _Inout_ PTP_IO Io)
WINBASEAPI VOID WINAPI WaitForThreadpoolIoCallbacks(_Inout_ PTP_IO pio, _In_ BOOL fCancelPendingCallbacks)
WINBASEAPI VOID WINAPI StartThreadpoolIo(_Inout_ PTP_IO pio)
WINBASEAPI VOID WINAPI CancelThreadpoolIo(_Inout_ PTP_IO pio)
WINBASEAPI VOID WINAPI CloseThreadpoolIo(_Inout_ PTP_IO pio)
uint32_t DWORD_PTR
Definition: typedefs.h:65
uint64_t ULONGLONG
Definition: typedefs.h:67
uint32_t ULONG_PTR
Definition: typedefs.h:65
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_CANCELLED
Definition: udferr_usr.h:170
LONGLONG QuadPart
Definition: typedefs.h:114
static rfbScreenInfoPtr server
Definition: vnc.c:74
wchar_t tm const _CrtWcstime_Writes_and_advances_ptr_ count wchar_t ** out
Definition: wcsftime.cpp:383
#define success(from, fromstr, to, tostr)
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define PIPE_ACCESS_DUPLEX
Definition: winbase.h:166
DWORD WINAPI GetCurrentThreadId(void)
Definition: thread.c:459
#define WAIT_OBJECT_0
Definition: winbase.h:383
void * arg
Definition: msvc.h:10
#define WINAPI
Definition: msvc.h:6
NTSYSAPI void WINAPI TpWaitForWork(TP_WORK *, BOOL)
Definition: threadpool.c:3331
NTSYSAPI void WINAPI TpReleaseWork(TP_WORK *)
Definition: threadpool.c:3055
NTSYSAPI void WINAPI TpDisassociateCallback(TP_CALLBACK_INSTANCE *)
Definition: threadpool.c:2850
NTSYSAPI NTSTATUS WINAPI TpQueryPoolStackInformation(TP_POOL *, TP_POOL_STACK_INFORMATION *stack_info)
Definition: threadpool.c:3364
NTSYSAPI void WINAPI TpStartAsyncIoOperation(TP_IO *)
Definition: threadpool.c:3273
NTSYSAPI void WINAPI TpReleasePool(TP_POOL *)
Definition: threadpool.c:3014
NTSYSAPI NTSTATUS WINAPI TpAllocTimer(TP_TIMER **, PTP_TIMER_CALLBACK, PVOID, TP_CALLBACK_ENVIRON *)
Definition: threadpool.c:2601
NTSYSAPI NTSTATUS WINAPI TpAllocCleanupGroup(TP_CLEANUP_GROUP **)
Definition: threadpool.c:2534
NTSYSAPI void WINAPI TpWaitForTimer(TP_TIMER *, BOOL)
Definition: threadpool.c:3303
NTSYSAPI void WINAPI TpWaitForIoCompletion(TP_IO *, BOOL)
Definition: threadpool.c:3289
NTSYSAPI void WINAPI TpCancelAsyncIoOperation(TP_IO *)
Definition: threadpool.c:2718
NTSYSAPI BOOL WINAPI TpIsTimerSet(TP_TIMER *)
Definition: threadpool.c:2881
NTSYSAPI void WINAPI TpReleaseTimer(TP_TIMER *)
Definition: threadpool.c:3027
NTSYSAPI void WINAPI TpPostWork(TP_WORK *)
Definition: threadpool.c:2893
NTSYSAPI void WINAPI TpWaitForWait(TP_WAIT *, BOOL)
Definition: threadpool.c:3317
NTSYSAPI NTSTATUS WINAPI TpAllocIoCompletion(TP_IO **, HANDLE, PTP_IO_CALLBACK, void *, TP_CALLBACK_ENVIRON *)
Definition: threadpool.c:2544
NTSYSAPI void WINAPI TpSetWait(TP_WAIT *, HANDLE, LARGE_INTEGER *)
Definition: threadpool.c:3191
NTSYSAPI NTSTATUS WINAPI TpAllocPool(TP_POOL **, PVOID)
Definition: threadpool.c:2588
NTSYSAPI void WINAPI TpReleaseIoCompletion(TP_IO *)
Definition: threadpool.c:2991
NTSYSAPI NTSTATUS WINAPI TpAllocWait(TP_WAIT **, PTP_WAIT_CALLBACK, PVOID, TP_CALLBACK_ENVIRON *)
Definition: threadpool.c:2677
NTSYSAPI void WINAPI TpSetPoolMaxThreads(TP_POOL *, DWORD)
Definition: threadpool.c:3069
NTSYSAPI void WINAPI TpCallbackReleaseSemaphoreOnCompletion(TP_CALLBACK_INSTANCE *, HANDLE, DWORD)
Definition: threadpool.c:2808
NTSYSAPI NTSTATUS WINAPI TpAllocWork(TP_WORK **, PTP_WORK_CALLBACK, PVOID, TP_CALLBACK_ENVIRON *)
Definition: threadpool.c:2687
NTSYSAPI void WINAPI TpReleaseCleanupGroupMembers(TP_CLEANUP_GROUP *, BOOL, PVOID)
Definition: threadpool.c:2918
NTSYSAPI void WINAPI TpReleaseCleanupGroup(TP_CLEANUP_GROUP *)
Definition: threadpool.c:2905
NTSYSAPI void WINAPI TpSetTimer(TP_TIMER *, LARGE_INTEGER *, LONG, LONG)
Definition: threadpool.c:3113
NTSYSAPI NTSTATUS WINAPI TpCallbackMayRunLong(TP_CALLBACK_INSTANCE *)
Definition: threadpool.c:2753
NTSYSAPI NTSTATUS WINAPI TpSetPoolStackInformation(TP_POOL *, TP_POOL_STACK_INFORMATION *stack_info)
Definition: threadpool.c:3345
NTSYSAPI void WINAPI TpReleaseWait(TP_WAIT *)
Definition: threadpool.c:3041
#define ERROR_OPERATION_ABORTED
Definition: winerror.h:899
#define ERROR_NOACCESS
Definition: winerror.h:902
#define WT_TRANSFER_IMPERSONATION
Definition: winnt_old.h:1105
@ TP_CALLBACK_PRIORITY_HIGH
Definition: winnt_old.h:4765
struct _TP_CLEANUP_GROUP TP_CLEANUP_GROUP
Definition: winnt_old.h:4784
#define WT_EXECUTEINPERSISTENTTHREAD
Definition: winnt_old.h:1104
#define WT_EXECUTEONLYONCE
Definition: winnt_old.h:1100
struct _TP_POOL TP_POOL
Definition: winnt_old.h:4754
#define WT_EXECUTEINIOTHREAD
Definition: winnt_old.h:1097
DWORD TP_WAIT_RESULT
Definition: winnt_old.h:4761
#define WT_EXECUTELONGFUNCTION
Definition: winnt_old.h:1101
#define WT_EXECUTEINWAITTHREAD
Definition: winnt_old.h:1099
struct _TP_WAIT TP_WAIT
Definition: winnt_old.h:4758
struct _TP_WORK TP_WORK
Definition: winnt_old.h:4755
struct _TP_IO TP_IO
Definition: winnt_old.h:4759
struct _TP_TIMER TP_TIMER
Definition: winnt_old.h:4757
VOID(NTAPI * PTP_SIMPLE_CALLBACK)(_Inout_ PTP_CALLBACK_INSTANCE Instance, _Inout_opt_ PVOID Context)
Definition: winnt_old.h:4787
struct _TP_CALLBACK_INSTANCE TP_CALLBACK_INSTANCE
Definition: winnt_old.h:4756
#define WT_EXECUTEDEFAULT
Definition: winnt_old.h:1096