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