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