1f7932ba2SAmine Khaldi /*
2f7932ba2SAmine Khaldi  * Unit test suite for thread pool functions
3f7932ba2SAmine Khaldi  *
4f7932ba2SAmine Khaldi  * Copyright 2015-2016 Sebastian Lackner
5f7932ba2SAmine Khaldi  *
6f7932ba2SAmine Khaldi  * This library is free software; you can redistribute it and/or
7f7932ba2SAmine Khaldi  * modify it under the terms of the GNU Lesser General Public
8f7932ba2SAmine Khaldi  * License as published by the Free Software Foundation; either
9f7932ba2SAmine Khaldi  * version 2.1 of the License, or (at your option) any later version.
10f7932ba2SAmine Khaldi  *
11f7932ba2SAmine Khaldi  * This library is distributed in the hope that it will be useful,
12f7932ba2SAmine Khaldi  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13f7932ba2SAmine Khaldi  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14f7932ba2SAmine Khaldi  * Lesser General Public License for more details.
15f7932ba2SAmine Khaldi  *
16f7932ba2SAmine Khaldi  * You should have received a copy of the GNU Lesser General Public
17f7932ba2SAmine Khaldi  * License along with this library; if not, write to the Free Software
18f7932ba2SAmine Khaldi  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19f7932ba2SAmine Khaldi  */
20f7932ba2SAmine Khaldi 
21f7932ba2SAmine Khaldi #include "ntdll_test.h"
22f7932ba2SAmine Khaldi 
23*0bf42067SJustin Miller #ifdef __REACTOS__
24*0bf42067SJustin Miller typedef void (CALLBACK *PTP_IO_CALLBACK)(PTP_CALLBACK_INSTANCE,void*,void*,IO_STATUS_BLOCK*,PTP_IO);
25*0bf42067SJustin Miller #endif
26*0bf42067SJustin Miller 
27f7932ba2SAmine Khaldi static NTSTATUS (WINAPI *pTpAllocCleanupGroup)(TP_CLEANUP_GROUP **);
2888a63011SJustin Miller static NTSTATUS (WINAPI *pTpAllocIoCompletion)(TP_IO **,HANDLE,PTP_IO_CALLBACK,void *,TP_CALLBACK_ENVIRON *);
29f7932ba2SAmine Khaldi static NTSTATUS (WINAPI *pTpAllocPool)(TP_POOL **,PVOID);
30f7932ba2SAmine Khaldi static NTSTATUS (WINAPI *pTpAllocTimer)(TP_TIMER **,PTP_TIMER_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *);
31f7932ba2SAmine Khaldi static NTSTATUS (WINAPI *pTpAllocWait)(TP_WAIT **,PTP_WAIT_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *);
32f7932ba2SAmine Khaldi static NTSTATUS (WINAPI *pTpAllocWork)(TP_WORK **,PTP_WORK_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *);
33f7932ba2SAmine Khaldi static NTSTATUS (WINAPI *pTpCallbackMayRunLong)(TP_CALLBACK_INSTANCE *);
34f7932ba2SAmine Khaldi static VOID     (WINAPI *pTpCallbackReleaseSemaphoreOnCompletion)(TP_CALLBACK_INSTANCE *,HANDLE,DWORD);
3588a63011SJustin Miller static void     (WINAPI *pTpCancelAsyncIoOperation)(TP_IO *);
36f7932ba2SAmine Khaldi static VOID     (WINAPI *pTpDisassociateCallback)(TP_CALLBACK_INSTANCE *);
37f7932ba2SAmine Khaldi static BOOL     (WINAPI *pTpIsTimerSet)(TP_TIMER *);
38f7932ba2SAmine Khaldi static VOID     (WINAPI *pTpPostWork)(TP_WORK *);
3988a63011SJustin Miller static NTSTATUS (WINAPI *pTpQueryPoolStackInformation)(TP_POOL *,TP_POOL_STACK_INFORMATION *);
40f7932ba2SAmine Khaldi static VOID     (WINAPI *pTpReleaseCleanupGroup)(TP_CLEANUP_GROUP *);
41f7932ba2SAmine Khaldi static VOID     (WINAPI *pTpReleaseCleanupGroupMembers)(TP_CLEANUP_GROUP *,BOOL,PVOID);
4288a63011SJustin Miller static void     (WINAPI *pTpReleaseIoCompletion)(TP_IO *);
43f7932ba2SAmine Khaldi static VOID     (WINAPI *pTpReleasePool)(TP_POOL *);
44f7932ba2SAmine Khaldi static VOID     (WINAPI *pTpReleaseTimer)(TP_TIMER *);
4588a63011SJustin Miller static VOID     (WINAPI *pTpReleaseWait)(TP_WAIT *);
46f7932ba2SAmine Khaldi static VOID     (WINAPI *pTpReleaseWork)(TP_WORK *);
47f7932ba2SAmine Khaldi static VOID     (WINAPI *pTpSetPoolMaxThreads)(TP_POOL *,DWORD);
4888a63011SJustin Miller static NTSTATUS (WINAPI *pTpSetPoolStackInformation)(TP_POOL *,TP_POOL_STACK_INFORMATION *);
49f7932ba2SAmine Khaldi static VOID     (WINAPI *pTpSetTimer)(TP_TIMER *,LARGE_INTEGER *,LONG,LONG);
50f7932ba2SAmine Khaldi static VOID     (WINAPI *pTpSetWait)(TP_WAIT *,HANDLE,LARGE_INTEGER *);
51f7932ba2SAmine Khaldi static NTSTATUS (WINAPI *pTpSimpleTryPost)(PTP_SIMPLE_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *);
5288a63011SJustin Miller static void     (WINAPI *pTpStartAsyncIoOperation)(TP_IO *);
5388a63011SJustin Miller static void     (WINAPI *pTpWaitForIoCompletion)(TP_IO *,BOOL);
54f7932ba2SAmine Khaldi static VOID     (WINAPI *pTpWaitForTimer)(TP_TIMER *,BOOL);
55f7932ba2SAmine Khaldi static VOID     (WINAPI *pTpWaitForWait)(TP_WAIT *,BOOL);
56f7932ba2SAmine Khaldi static VOID     (WINAPI *pTpWaitForWork)(TP_WORK *,BOOL);
57f7932ba2SAmine Khaldi 
5888a63011SJustin Miller static void (WINAPI *pCancelThreadpoolIo)(TP_IO *);
5988a63011SJustin Miller static void (WINAPI *pCloseThreadpoolIo)(TP_IO *);
6088a63011SJustin Miller static TP_IO *(WINAPI *pCreateThreadpoolIo)(HANDLE, PTP_WIN32_IO_CALLBACK, void *, TP_CALLBACK_ENVIRON *);
6188a63011SJustin Miller static void (WINAPI *pStartThreadpoolIo)(TP_IO *);
6288a63011SJustin Miller static void (WINAPI *pWaitForThreadpoolIoCallbacks)(TP_IO *, BOOL);
6388a63011SJustin Miller 
6488a63011SJustin Miller #define GET_PROC(func) \
65f7932ba2SAmine Khaldi     do \
66f7932ba2SAmine Khaldi     { \
6788a63011SJustin Miller         p ## func = (void *)GetProcAddress(module, #func); \
68f7932ba2SAmine Khaldi         if (!p ## func) trace("Failed to get address for %s\n", #func); \
69f7932ba2SAmine Khaldi     } \
70f7932ba2SAmine Khaldi     while (0)
71f7932ba2SAmine Khaldi 
init_threadpool(void)72f7932ba2SAmine Khaldi static BOOL init_threadpool(void)
73f7932ba2SAmine Khaldi {
7488a63011SJustin Miller     HMODULE module = GetModuleHandleA("ntdll");
7588a63011SJustin Miller     GET_PROC(TpAllocCleanupGroup);
7688a63011SJustin Miller     GET_PROC(TpAllocIoCompletion);
7788a63011SJustin Miller     GET_PROC(TpAllocPool);
7888a63011SJustin Miller     GET_PROC(TpAllocTimer);
7988a63011SJustin Miller     GET_PROC(TpAllocWait);
8088a63011SJustin Miller     GET_PROC(TpAllocWork);
8188a63011SJustin Miller     GET_PROC(TpCallbackMayRunLong);
8288a63011SJustin Miller     GET_PROC(TpCallbackReleaseSemaphoreOnCompletion);
8388a63011SJustin Miller     GET_PROC(TpCancelAsyncIoOperation);
8488a63011SJustin Miller     GET_PROC(TpDisassociateCallback);
8588a63011SJustin Miller     GET_PROC(TpIsTimerSet);
8688a63011SJustin Miller     GET_PROC(TpPostWork);
8788a63011SJustin Miller     GET_PROC(TpQueryPoolStackInformation);
8888a63011SJustin Miller     GET_PROC(TpReleaseCleanupGroup);
8988a63011SJustin Miller     GET_PROC(TpReleaseCleanupGroupMembers);
9088a63011SJustin Miller     GET_PROC(TpReleaseIoCompletion);
9188a63011SJustin Miller     GET_PROC(TpReleasePool);
9288a63011SJustin Miller     GET_PROC(TpReleaseTimer);
9388a63011SJustin Miller     GET_PROC(TpReleaseWait);
9488a63011SJustin Miller     GET_PROC(TpReleaseWork);
9588a63011SJustin Miller     GET_PROC(TpSetPoolMaxThreads);
9688a63011SJustin Miller     GET_PROC(TpSetPoolStackInformation);
9788a63011SJustin Miller     GET_PROC(TpSetTimer);
9888a63011SJustin Miller     GET_PROC(TpSetWait);
9988a63011SJustin Miller     GET_PROC(TpSimpleTryPost);
10088a63011SJustin Miller     GET_PROC(TpStartAsyncIoOperation);
10188a63011SJustin Miller     GET_PROC(TpWaitForIoCompletion);
10288a63011SJustin Miller     GET_PROC(TpWaitForTimer);
10388a63011SJustin Miller     GET_PROC(TpWaitForWait);
10488a63011SJustin Miller     GET_PROC(TpWaitForWork);
105f7932ba2SAmine Khaldi 
10688a63011SJustin Miller     module = GetModuleHandleA("kernel32");
10788a63011SJustin Miller     GET_PROC(CancelThreadpoolIo);
10888a63011SJustin Miller     GET_PROC(CloseThreadpoolIo);
10988a63011SJustin Miller     GET_PROC(CreateThreadpoolIo);
11088a63011SJustin Miller     GET_PROC(StartThreadpoolIo);
11188a63011SJustin Miller     GET_PROC(WaitForThreadpoolIoCallbacks);
112f7932ba2SAmine Khaldi 
113f7932ba2SAmine Khaldi     if (!pTpAllocPool)
114f7932ba2SAmine Khaldi     {
115f7932ba2SAmine Khaldi         win_skip("Threadpool functions not supported, skipping tests\n");
116f7932ba2SAmine Khaldi         return FALSE;
117f7932ba2SAmine Khaldi     }
118f7932ba2SAmine Khaldi 
119f7932ba2SAmine Khaldi     return TRUE;
120f7932ba2SAmine Khaldi }
121f7932ba2SAmine Khaldi 
122f7932ba2SAmine Khaldi #undef NTDLL_GET_PROC
123f7932ba2SAmine Khaldi 
124f7932ba2SAmine Khaldi 
rtl_work_cb(void * userdata)125f7932ba2SAmine Khaldi static DWORD CALLBACK rtl_work_cb(void *userdata)
126f7932ba2SAmine Khaldi {
127f7932ba2SAmine Khaldi     HANDLE semaphore = userdata;
128f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphore, 1, NULL);
129f7932ba2SAmine Khaldi     return 0;
130f7932ba2SAmine Khaldi }
131f7932ba2SAmine Khaldi 
test_RtlQueueWorkItem(void)132f7932ba2SAmine Khaldi static void test_RtlQueueWorkItem(void)
133f7932ba2SAmine Khaldi {
134f7932ba2SAmine Khaldi     HANDLE semaphore;
135f7932ba2SAmine Khaldi     NTSTATUS status;
136f7932ba2SAmine Khaldi     DWORD result;
137f7932ba2SAmine Khaldi 
138f7932ba2SAmine Khaldi     semaphore = CreateSemaphoreA(NULL, 0, 1, NULL);
13988a63011SJustin Miller     ok(semaphore != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
140f7932ba2SAmine Khaldi 
141f7932ba2SAmine Khaldi     status = RtlQueueWorkItem(rtl_work_cb, semaphore, WT_EXECUTEDEFAULT);
14288a63011SJustin Miller     ok(!status, "RtlQueueWorkItem failed with status %lx\n", status);
143f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphore, 1000);
14488a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
145f7932ba2SAmine Khaldi 
146f7932ba2SAmine Khaldi     status = RtlQueueWorkItem(rtl_work_cb, semaphore, WT_EXECUTEINIOTHREAD);
14788a63011SJustin Miller     ok(!status, "RtlQueueWorkItem failed with status %lx\n", status);
148f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphore, 1000);
14988a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
150f7932ba2SAmine Khaldi 
151f7932ba2SAmine Khaldi     status = RtlQueueWorkItem(rtl_work_cb, semaphore, WT_EXECUTEINPERSISTENTTHREAD);
15288a63011SJustin Miller     ok(!status, "RtlQueueWorkItem failed with status %lx\n", status);
153f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphore, 1000);
15488a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
155f7932ba2SAmine Khaldi 
156f7932ba2SAmine Khaldi     status = RtlQueueWorkItem(rtl_work_cb, semaphore, WT_EXECUTELONGFUNCTION);
15788a63011SJustin Miller     ok(!status, "RtlQueueWorkItem failed with status %lx\n", status);
158f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphore, 1000);
15988a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
160f7932ba2SAmine Khaldi 
161f7932ba2SAmine Khaldi     status = RtlQueueWorkItem(rtl_work_cb, semaphore, WT_TRANSFER_IMPERSONATION);
16288a63011SJustin Miller     ok(!status, "RtlQueueWorkItem failed with status %lx\n", status);
163f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphore, 1000);
16488a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
165f7932ba2SAmine Khaldi 
166f7932ba2SAmine Khaldi     CloseHandle(semaphore);
167f7932ba2SAmine Khaldi }
168f7932ba2SAmine Khaldi 
169f7932ba2SAmine Khaldi struct rtl_wait_info
170f7932ba2SAmine Khaldi {
171f7932ba2SAmine Khaldi     HANDLE semaphore1;
172f7932ba2SAmine Khaldi     HANDLE semaphore2;
173f7932ba2SAmine Khaldi     DWORD wait_result;
174f7932ba2SAmine Khaldi     DWORD threadid;
175f7932ba2SAmine Khaldi     LONG userdata;
176f7932ba2SAmine Khaldi };
177f7932ba2SAmine Khaldi 
rtl_wait_cb(void * userdata,BOOLEAN timeout)178f7932ba2SAmine Khaldi static void CALLBACK rtl_wait_cb(void *userdata, BOOLEAN timeout)
179f7932ba2SAmine Khaldi {
180f7932ba2SAmine Khaldi     struct rtl_wait_info *info = userdata;
181f7932ba2SAmine Khaldi     DWORD result;
182f7932ba2SAmine Khaldi 
183f7932ba2SAmine Khaldi     if (!timeout)
184f7932ba2SAmine Khaldi         InterlockedIncrement(&info->userdata);
185f7932ba2SAmine Khaldi     else
186f7932ba2SAmine Khaldi         InterlockedExchangeAdd(&info->userdata, 0x10000);
187f7932ba2SAmine Khaldi     info->threadid = GetCurrentThreadId();
188f7932ba2SAmine Khaldi     ReleaseSemaphore(info->semaphore1, 1, NULL);
189f7932ba2SAmine Khaldi 
190f7932ba2SAmine Khaldi     if (info->semaphore2)
191f7932ba2SAmine Khaldi     {
192f7932ba2SAmine Khaldi         result = WaitForSingleObject(info->semaphore2, 200);
19388a63011SJustin Miller         ok(result == info->wait_result, "expected %lu, got %lu\n", info->wait_result, result);
194f7932ba2SAmine Khaldi         ReleaseSemaphore(info->semaphore1, 1, NULL);
195f7932ba2SAmine Khaldi     }
196f7932ba2SAmine Khaldi }
197f7932ba2SAmine Khaldi 
198f7932ba2SAmine Khaldi static HANDLE rtl_wait_apc_semaphore;
199f7932ba2SAmine Khaldi 
rtl_wait_apc_cb(ULONG_PTR userdata)200f7932ba2SAmine Khaldi static void CALLBACK rtl_wait_apc_cb(ULONG_PTR userdata)
201f7932ba2SAmine Khaldi {
202f7932ba2SAmine Khaldi     if (rtl_wait_apc_semaphore)
203f7932ba2SAmine Khaldi         ReleaseSemaphore(rtl_wait_apc_semaphore, 1, NULL);
204f7932ba2SAmine Khaldi }
205f7932ba2SAmine Khaldi 
test_RtlRegisterWait(void)206f7932ba2SAmine Khaldi static void test_RtlRegisterWait(void)
207f7932ba2SAmine Khaldi {
208f7932ba2SAmine Khaldi     HANDLE wait1, event, thread;
209f7932ba2SAmine Khaldi     struct rtl_wait_info info;
210f7932ba2SAmine Khaldi     HANDLE semaphores[2];
211f7932ba2SAmine Khaldi     NTSTATUS status;
21288a63011SJustin Miller     DWORD result, threadid;
213f7932ba2SAmine Khaldi 
214f7932ba2SAmine Khaldi     semaphores[0] = CreateSemaphoreW(NULL, 0, 2, NULL);
215f7932ba2SAmine Khaldi     ok(semaphores[0] != NULL, "failed to create semaphore\n");
216f7932ba2SAmine Khaldi     semaphores[1] = CreateSemaphoreW(NULL, 0, 1, NULL);
217f7932ba2SAmine Khaldi     ok(semaphores[1] != NULL, "failed to create semaphore\n");
218f7932ba2SAmine Khaldi     info.semaphore1 = semaphores[0];
219f7932ba2SAmine Khaldi     info.semaphore2 = NULL;
220f7932ba2SAmine Khaldi 
221f7932ba2SAmine Khaldi     event = CreateEventW(NULL, FALSE, FALSE, NULL);
222f7932ba2SAmine Khaldi     ok(event != NULL, "failed to create event\n");
223f7932ba2SAmine Khaldi 
224f7932ba2SAmine Khaldi     /* basic test for RtlRegisterWait and RtlDeregisterWait */
225f7932ba2SAmine Khaldi     wait1 = NULL;
226f7932ba2SAmine Khaldi     info.userdata = 0;
227f7932ba2SAmine Khaldi     status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT);
22888a63011SJustin Miller     ok(!status, "RtlRegisterWait failed with status %lx\n", status);
229f7932ba2SAmine Khaldi     ok(wait1 != NULL, "expected wait1 != NULL\n");
230f7932ba2SAmine Khaldi     status = RtlDeregisterWait(wait1);
23188a63011SJustin Miller     ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
23288a63011SJustin Miller     ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
233f7932ba2SAmine Khaldi 
234f7932ba2SAmine Khaldi     /* infinite timeout, signal the semaphore two times */
235f7932ba2SAmine Khaldi     info.userdata = 0;
236f7932ba2SAmine Khaldi     status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT);
23788a63011SJustin Miller     ok(!status, "RtlRegisterWait failed with status %lx\n", status);
238f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[1], 1, NULL);
239f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
24088a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
24188a63011SJustin Miller     ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
242f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[1], 1, NULL);
243f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
24488a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
24588a63011SJustin Miller     ok(info.userdata == 2, "expected info.userdata = 2, got %lu\n", info.userdata);
246f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[1], 0);
24788a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
248f7932ba2SAmine Khaldi     Sleep(50);
249f7932ba2SAmine Khaldi     status = RtlDeregisterWait(wait1);
25088a63011SJustin Miller     ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
251f7932ba2SAmine Khaldi 
252f7932ba2SAmine Khaldi     /* repeat test with WT_EXECUTEONLYONCE */
253f7932ba2SAmine Khaldi     info.userdata = 0;
254f7932ba2SAmine Khaldi     status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEONLYONCE);
25588a63011SJustin Miller     ok(!status, "RtlRegisterWait failed with status %lx\n", status);
256f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[1], 1, NULL);
257f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
25888a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
25988a63011SJustin Miller     ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
260f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[1], 1, NULL);
261f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
26288a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
26388a63011SJustin Miller     ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
264f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[1], 0);
26588a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
266f7932ba2SAmine Khaldi     Sleep(50);
267f7932ba2SAmine Khaldi     status = RtlDeregisterWait(wait1);
26888a63011SJustin Miller     ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
269f7932ba2SAmine Khaldi 
270f7932ba2SAmine Khaldi     /* finite timeout, no event */
271f7932ba2SAmine Khaldi     info.userdata = 0;
272f7932ba2SAmine Khaldi     status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 200, WT_EXECUTEDEFAULT);
27388a63011SJustin Miller     ok(!status, "RtlRegisterWait failed with status %lx\n", status);
274f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
27588a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
27688a63011SJustin Miller     ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
277f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 200);
27888a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
27988a63011SJustin Miller     ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
280f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[1], 0);
28188a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
282f7932ba2SAmine Khaldi     Sleep(50);
283f7932ba2SAmine Khaldi     status = RtlDeregisterWait(wait1);
28488a63011SJustin Miller     ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
285f7932ba2SAmine Khaldi 
286f7932ba2SAmine Khaldi     /* finite timeout, with event */
287f7932ba2SAmine Khaldi     info.userdata = 0;
288f7932ba2SAmine Khaldi     status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 200, WT_EXECUTEDEFAULT);
28988a63011SJustin Miller     ok(!status, "RtlRegisterWait failed with status %lx\n", status);
290f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
29188a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
29288a63011SJustin Miller     ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
293f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[1], 1, NULL);
294f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
29588a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
29688a63011SJustin Miller     ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
297f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[1], 0);
29888a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
299f7932ba2SAmine Khaldi     Sleep(50);
300f7932ba2SAmine Khaldi     status = RtlDeregisterWait(wait1);
30188a63011SJustin Miller     ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
30288a63011SJustin Miller 
30388a63011SJustin Miller     /* test RtlRegisterWait WT_EXECUTEINWAITTHREAD flag */
30488a63011SJustin Miller     info.userdata = 0;
30588a63011SJustin Miller     info.threadid = 0;
30688a63011SJustin Miller     status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 200, WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE);
30788a63011SJustin Miller     ok(!status, "RtlRegisterWait failed with status %lx\n", status);
30888a63011SJustin Miller     ReleaseSemaphore(semaphores[1], 1, NULL);
30988a63011SJustin Miller     result = WaitForSingleObject(semaphores[0], 200);
31088a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
31188a63011SJustin Miller     ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
31288a63011SJustin Miller     ok(info.threadid && info.threadid != GetCurrentThreadId(), "unexpected wait thread id %lx\n", info.threadid);
31388a63011SJustin Miller     threadid = info.threadid;
31488a63011SJustin Miller     result = WaitForSingleObject(semaphores[1], 0);
31588a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
31688a63011SJustin Miller     Sleep(50);
31788a63011SJustin Miller     status = RtlDeregisterWait(wait1);
31888a63011SJustin Miller     ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
31988a63011SJustin Miller 
32088a63011SJustin Miller     info.userdata = 0;
32188a63011SJustin Miller     info.threadid = 0;
32288a63011SJustin Miller     status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 200, WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE);
32388a63011SJustin Miller     ok(!status, "RtlRegisterWait failed with status %lx\n", status);
32488a63011SJustin Miller     ReleaseSemaphore(semaphores[1], 1, NULL);
32588a63011SJustin Miller     result = WaitForSingleObject(semaphores[0], 200);
32688a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
32788a63011SJustin Miller     ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
32888a63011SJustin Miller     ok(info.threadid == threadid, "unexpected different wait thread id %lx\n", info.threadid);
32988a63011SJustin Miller     result = WaitForSingleObject(semaphores[1], 0);
33088a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
33188a63011SJustin Miller     Sleep(50);
33288a63011SJustin Miller     status = RtlDeregisterWait(wait1);
33388a63011SJustin Miller     ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
33488a63011SJustin Miller 
33588a63011SJustin Miller     /* test RtlRegisterWait WT_EXECUTEINWAITTHREAD flag with 0 timeout */
33688a63011SJustin Miller     info.userdata = 0;
33788a63011SJustin Miller     info.threadid = 0;
33888a63011SJustin Miller     status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 0, WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE);
33988a63011SJustin Miller     ok(!status, "RtlRegisterWait failed with status %lx\n", status);
34088a63011SJustin Miller     result = WaitForSingleObject(semaphores[0], 100);
34188a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
34288a63011SJustin Miller     ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
34388a63011SJustin Miller     ok(info.threadid == threadid, "unexpected different wait thread id %lx\n", info.threadid);
34488a63011SJustin Miller     result = WaitForSingleObject(semaphores[1], 0);
34588a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
34688a63011SJustin Miller     Sleep(50);
34788a63011SJustin Miller     status = RtlDeregisterWait(wait1);
34888a63011SJustin Miller     ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
34988a63011SJustin Miller 
35088a63011SJustin Miller     /* test RtlRegisterWait WT_EXECUTEINWAITTHREAD flag with already signaled event */
35188a63011SJustin Miller     info.userdata = 0;
35288a63011SJustin Miller     info.threadid = 0;
35388a63011SJustin Miller     ReleaseSemaphore(semaphores[1], 1, NULL);
35488a63011SJustin Miller     status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 200, WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE);
35588a63011SJustin Miller     ok(!status, "RtlRegisterWait failed with status %lx\n", status);
35688a63011SJustin Miller     result = WaitForSingleObject(semaphores[0], 200);
35788a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
35888a63011SJustin Miller     ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
35988a63011SJustin Miller     ok(info.threadid == threadid, "unexpected different wait thread id %lx\n", info.threadid);
36088a63011SJustin Miller     result = WaitForSingleObject(semaphores[1], 0);
36188a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
36288a63011SJustin Miller     Sleep(50);
36388a63011SJustin Miller     status = RtlDeregisterWait(wait1);
36488a63011SJustin Miller     ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
365f7932ba2SAmine Khaldi 
366f7932ba2SAmine Khaldi     /* test for IO threads */
367f7932ba2SAmine Khaldi     info.userdata = 0;
368f7932ba2SAmine Khaldi     info.threadid = 0;
369f7932ba2SAmine Khaldi     status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEINIOTHREAD);
37088a63011SJustin Miller     ok(!status, "RtlRegisterWait failed with status %lx\n", status);
371f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[1], 1, NULL);
372f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
37388a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
37488a63011SJustin Miller     ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
37588a63011SJustin Miller     ok(info.threadid != 0, "expected info.threadid != 0, got %lu\n", info.threadid);
376f7932ba2SAmine Khaldi     thread = OpenThread(THREAD_SET_CONTEXT, FALSE, info.threadid);
37788a63011SJustin Miller     ok(thread != NULL, "OpenThread failed with %lu\n", GetLastError());
378f7932ba2SAmine Khaldi     rtl_wait_apc_semaphore = semaphores[0];
379f7932ba2SAmine Khaldi     result = QueueUserAPC(rtl_wait_apc_cb, thread, 0);
38088a63011SJustin Miller     ok(result != 0, "QueueUserAPC failed with %lu\n", GetLastError());
381f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 200);
38288a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
383f7932ba2SAmine Khaldi     rtl_wait_apc_semaphore = 0;
384f7932ba2SAmine Khaldi     CloseHandle(thread);
385f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[1], 1, NULL);
386f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
38788a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
38888a63011SJustin Miller     ok(info.userdata == 2, "expected info.userdata = 2, got %lu\n", info.userdata);
389f7932ba2SAmine Khaldi     Sleep(50);
390f7932ba2SAmine Khaldi     status = RtlDeregisterWait(wait1);
39188a63011SJustin Miller     ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
392f7932ba2SAmine Khaldi 
393f7932ba2SAmine Khaldi     info.userdata = 0;
394f7932ba2SAmine Khaldi     info.threadid = 0;
395f7932ba2SAmine Khaldi     status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT);
39688a63011SJustin Miller     ok(!status, "RtlRegisterWait failed with status %lx\n", status);
397f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[1], 1, NULL);
398f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
39988a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
40088a63011SJustin Miller     ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
40188a63011SJustin Miller     ok(info.threadid != 0, "expected info.threadid != 0, got %lu\n", info.threadid);
402f7932ba2SAmine Khaldi     thread = OpenThread(THREAD_SET_CONTEXT, FALSE, info.threadid);
40388a63011SJustin Miller     ok(thread != NULL, "OpenThread failed with %lu\n", GetLastError());
404f7932ba2SAmine Khaldi     rtl_wait_apc_semaphore = semaphores[0];
405f7932ba2SAmine Khaldi     result = QueueUserAPC(rtl_wait_apc_cb, thread, 0);
40688a63011SJustin Miller     ok(result != 0, "QueueUserAPC failed with %lu\n", GetLastError());
407f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 200);
408f7932ba2SAmine Khaldi     ok(result == WAIT_TIMEOUT || broken(result == WAIT_OBJECT_0) /* >= Win Vista */,
40988a63011SJustin Miller        "WaitForSingleObject returned %lu\n", result);
410f7932ba2SAmine Khaldi     rtl_wait_apc_semaphore = 0;
411f7932ba2SAmine Khaldi     CloseHandle(thread);
412f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[1], 1, NULL);
413f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
41488a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
41588a63011SJustin Miller     ok(info.userdata == 2, "expected info.userdata = 2, got %lu\n", info.userdata);
416f7932ba2SAmine Khaldi     Sleep(50);
417f7932ba2SAmine Khaldi     status = RtlDeregisterWait(wait1);
41888a63011SJustin Miller     ok(!status, "RtlDeregisterWait failed with status %lx\n", status);
419f7932ba2SAmine Khaldi 
420f7932ba2SAmine Khaldi     /* test RtlDeregisterWaitEx before wait expired */
421f7932ba2SAmine Khaldi     info.userdata = 0;
422f7932ba2SAmine Khaldi     status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT);
42388a63011SJustin Miller     ok(!status, "RtlRegisterWait failed with status %lx\n", status);
424f7932ba2SAmine Khaldi     status = RtlDeregisterWaitEx(wait1, NULL);
42588a63011SJustin Miller     ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status);
42688a63011SJustin Miller     ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
427f7932ba2SAmine Khaldi 
428f7932ba2SAmine Khaldi     info.userdata = 0;
429f7932ba2SAmine Khaldi     status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT);
43088a63011SJustin Miller     ok(!status, "RtlRegisterWait failed with status %lx\n", status);
431f7932ba2SAmine Khaldi     status = RtlDeregisterWaitEx(wait1, INVALID_HANDLE_VALUE);
43288a63011SJustin Miller     ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status);
43388a63011SJustin Miller     ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
434f7932ba2SAmine Khaldi 
435f7932ba2SAmine Khaldi     info.userdata = 0;
436f7932ba2SAmine Khaldi     status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT);
43788a63011SJustin Miller     ok(!status, "RtlRegisterWait failed with status %lx\n", status);
438f7932ba2SAmine Khaldi     status = RtlDeregisterWaitEx(wait1, event);
43988a63011SJustin Miller     ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status);
44088a63011SJustin Miller     ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
441f7932ba2SAmine Khaldi     result = WaitForSingleObject(event, 200);
44288a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
443f7932ba2SAmine Khaldi 
444f7932ba2SAmine Khaldi     /* test RtlDeregisterWaitEx after wait expired */
445f7932ba2SAmine Khaldi     info.userdata = 0;
446f7932ba2SAmine Khaldi     status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 0, WT_EXECUTEONLYONCE);
44788a63011SJustin Miller     ok(!status, "RtlRegisterWait failed with status %lx\n", status);
448f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
44988a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
45088a63011SJustin Miller     ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
451f7932ba2SAmine Khaldi     Sleep(50);
452f7932ba2SAmine Khaldi     status = RtlDeregisterWaitEx(wait1, NULL);
45388a63011SJustin Miller     ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status);
45488a63011SJustin Miller     ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
455f7932ba2SAmine Khaldi 
456f7932ba2SAmine Khaldi     info.userdata = 0;
457f7932ba2SAmine Khaldi     status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 0, WT_EXECUTEONLYONCE);
45888a63011SJustin Miller     ok(!status, "RtlRegisterWait failed with status %lx\n", status);
459f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
46088a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
46188a63011SJustin Miller     ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
462f7932ba2SAmine Khaldi     Sleep(50);
463f7932ba2SAmine Khaldi     status = RtlDeregisterWaitEx(wait1, INVALID_HANDLE_VALUE);
46488a63011SJustin Miller     ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status);
46588a63011SJustin Miller     ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
466f7932ba2SAmine Khaldi 
467f7932ba2SAmine Khaldi     info.userdata = 0;
468f7932ba2SAmine Khaldi     status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, 0, WT_EXECUTEONLYONCE);
46988a63011SJustin Miller     ok(!status, "RtlRegisterWait failed with status %lx\n", status);
470f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
47188a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
47288a63011SJustin Miller     ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
473f7932ba2SAmine Khaldi     Sleep(50);
474f7932ba2SAmine Khaldi     status = RtlDeregisterWaitEx(wait1, event);
47588a63011SJustin Miller     ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status);
47688a63011SJustin Miller     ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
477f7932ba2SAmine Khaldi     result = WaitForSingleObject(event, 200);
47888a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
479f7932ba2SAmine Khaldi 
480f7932ba2SAmine Khaldi     /* test RtlDeregisterWaitEx while callback is running */
481f7932ba2SAmine Khaldi     info.semaphore2 = semaphores[1];
482f7932ba2SAmine Khaldi     info.wait_result = WAIT_OBJECT_0;
483f7932ba2SAmine Khaldi 
484f7932ba2SAmine Khaldi     info.userdata = 0;
485f7932ba2SAmine Khaldi     status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEONLYONCE);
48688a63011SJustin Miller     ok(!status, "RtlRegisterWait failed with status %lx\n", status);
487f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[1], 1, NULL);
488f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 1000);
48988a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
49088a63011SJustin Miller     ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
491f7932ba2SAmine Khaldi     status = RtlDeregisterWait(wait1);
49288a63011SJustin Miller     ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %lx\n", status);
493f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[1], 1, NULL);
494f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 1000);
49588a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
49688a63011SJustin Miller 
49788a63011SJustin Miller     info.userdata = 0;
49888a63011SJustin Miller     status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE);
49988a63011SJustin Miller     ok(!status, "RtlRegisterWait failed with status %lx\n", status);
50088a63011SJustin Miller     ReleaseSemaphore(semaphores[1], 1, NULL);
50188a63011SJustin Miller     result = WaitForSingleObject(semaphores[0], 1000);
50288a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
50388a63011SJustin Miller     ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
50488a63011SJustin Miller     status = RtlDeregisterWait(wait1);
50588a63011SJustin Miller     ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %lx\n", status);
50688a63011SJustin Miller     ReleaseSemaphore(semaphores[1], 1, NULL);
50788a63011SJustin Miller     result = WaitForSingleObject(semaphores[0], 1000);
50888a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
509f7932ba2SAmine Khaldi 
510f7932ba2SAmine Khaldi     info.userdata = 0;
511f7932ba2SAmine Khaldi     status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEONLYONCE);
51288a63011SJustin Miller     ok(!status, "RtlRegisterWait failed with status %lx\n", status);
513f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[1], 1, NULL);
514f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 1000);
51588a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
51688a63011SJustin Miller     ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
517f7932ba2SAmine Khaldi     status = RtlDeregisterWaitEx(wait1, NULL);
51888a63011SJustin Miller     ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %lx\n", status);
519f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[1], 1, NULL);
520f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 1000);
52188a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
522f7932ba2SAmine Khaldi 
523f7932ba2SAmine Khaldi     info.wait_result = WAIT_TIMEOUT;
524f7932ba2SAmine Khaldi     info.userdata = 0;
525f7932ba2SAmine Khaldi     status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEONLYONCE);
52688a63011SJustin Miller     ok(!status, "RtlRegisterWait failed with status %lx\n", status);
527f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[1], 1, NULL);
528f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 1000);
52988a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
53088a63011SJustin Miller     ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
531f7932ba2SAmine Khaldi     status = RtlDeregisterWaitEx(wait1, INVALID_HANDLE_VALUE);
53288a63011SJustin Miller     ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status);
533f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 0);
53488a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
53588a63011SJustin Miller 
53688a63011SJustin Miller     info.wait_result = WAIT_TIMEOUT;
53788a63011SJustin Miller     info.userdata = 0;
53888a63011SJustin Miller     status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE);
53988a63011SJustin Miller     ok(!status, "RtlRegisterWait failed with status %lx\n", status);
54088a63011SJustin Miller     ReleaseSemaphore(semaphores[1], 1, NULL);
54188a63011SJustin Miller     result = WaitForSingleObject(semaphores[0], 1000);
54288a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
54388a63011SJustin Miller     ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
54488a63011SJustin Miller     status = RtlDeregisterWaitEx(wait1, INVALID_HANDLE_VALUE);
54588a63011SJustin Miller     ok(!status, "RtlDeregisterWaitEx failed with status %lx\n", status);
54688a63011SJustin Miller     result = WaitForSingleObject(semaphores[0], 0);
54788a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
548f7932ba2SAmine Khaldi 
549f7932ba2SAmine Khaldi     info.wait_result = WAIT_OBJECT_0;
550f7932ba2SAmine Khaldi     info.userdata = 0;
551f7932ba2SAmine Khaldi     status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEONLYONCE);
55288a63011SJustin Miller     ok(!status, "RtlRegisterWait failed with status %lx\n", status);
553f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[1], 1, NULL);
554f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 1000);
55588a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
55688a63011SJustin Miller     ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
557f7932ba2SAmine Khaldi     status = RtlDeregisterWaitEx(wait1, event);
55888a63011SJustin Miller     ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %lx\n", status);
559f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[1], 1, NULL);
560f7932ba2SAmine Khaldi     result = WaitForSingleObject(event, 1000);
56188a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
562f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 0);
56388a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
564f7932ba2SAmine Khaldi 
565f7932ba2SAmine Khaldi     CloseHandle(semaphores[0]);
566f7932ba2SAmine Khaldi     CloseHandle(semaphores[1]);
567f7932ba2SAmine Khaldi     CloseHandle(event);
568f7932ba2SAmine Khaldi }
569f7932ba2SAmine Khaldi 
simple_cb(TP_CALLBACK_INSTANCE * instance,void * userdata)570f7932ba2SAmine Khaldi static void CALLBACK simple_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
571f7932ba2SAmine Khaldi {
572f7932ba2SAmine Khaldi     HANDLE semaphore = userdata;
573f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphore, 1, NULL);
574f7932ba2SAmine Khaldi }
575f7932ba2SAmine Khaldi 
simple2_cb(TP_CALLBACK_INSTANCE * instance,void * userdata)576f7932ba2SAmine Khaldi static void CALLBACK simple2_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
577f7932ba2SAmine Khaldi {
578f7932ba2SAmine Khaldi     Sleep(50);
579f7932ba2SAmine Khaldi     InterlockedIncrement((LONG *)userdata);
580f7932ba2SAmine Khaldi }
581f7932ba2SAmine Khaldi 
test_tp_simple(void)582f7932ba2SAmine Khaldi static void test_tp_simple(void)
583f7932ba2SAmine Khaldi {
58488a63011SJustin Miller     IMAGE_NT_HEADERS *nt = RtlImageNtHeader( NtCurrentTeb()->Peb->ImageBaseAddress );
58588a63011SJustin Miller     TP_POOL_STACK_INFORMATION stack_info;
586f7932ba2SAmine Khaldi     TP_CALLBACK_ENVIRON environment;
587*0bf42067SJustin Miller #ifndef __REACTOS__
588f7932ba2SAmine Khaldi     TP_CALLBACK_ENVIRON_V3 environment3;
589*0bf42067SJustin Miller #endif
590f7932ba2SAmine Khaldi     TP_CLEANUP_GROUP *group;
591f7932ba2SAmine Khaldi     HANDLE semaphore;
592f7932ba2SAmine Khaldi     NTSTATUS status;
593f7932ba2SAmine Khaldi     TP_POOL *pool;
594f7932ba2SAmine Khaldi     LONG userdata;
595f7932ba2SAmine Khaldi     DWORD result;
596f7932ba2SAmine Khaldi     int i;
597f7932ba2SAmine Khaldi 
598f7932ba2SAmine Khaldi     semaphore = CreateSemaphoreA(NULL, 0, 1, NULL);
59988a63011SJustin Miller     ok(semaphore != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
600f7932ba2SAmine Khaldi 
601f7932ba2SAmine Khaldi     /* post the callback using the default threadpool */
602f7932ba2SAmine Khaldi     memset(&environment, 0, sizeof(environment));
603f7932ba2SAmine Khaldi     environment.Version = 1;
604f7932ba2SAmine Khaldi     environment.Pool = NULL;
605f7932ba2SAmine Khaldi     status = pTpSimpleTryPost(simple_cb, semaphore, &environment);
60688a63011SJustin Miller     ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
607f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphore, 1000);
60888a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
609f7932ba2SAmine Khaldi 
610f7932ba2SAmine Khaldi     /* allocate new threadpool */
611f7932ba2SAmine Khaldi     pool = NULL;
612f7932ba2SAmine Khaldi     status = pTpAllocPool(&pool, NULL);
61388a63011SJustin Miller     ok(!status, "TpAllocPool failed with status %lx\n", status);
614f7932ba2SAmine Khaldi     ok(pool != NULL, "expected pool != NULL\n");
615f7932ba2SAmine Khaldi 
616f7932ba2SAmine Khaldi     /* post the callback using the new threadpool */
617f7932ba2SAmine Khaldi     memset(&environment, 0, sizeof(environment));
618f7932ba2SAmine Khaldi     environment.Version = 1;
619f7932ba2SAmine Khaldi     environment.Pool = pool;
620f7932ba2SAmine Khaldi     status = pTpSimpleTryPost(simple_cb, semaphore, &environment);
62188a63011SJustin Miller     ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
622f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphore, 1000);
62388a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
624f7932ba2SAmine Khaldi 
625*0bf42067SJustin Miller #ifndef __REACTOS__ // Windows 7
626f7932ba2SAmine Khaldi     /* test with environment version 3 */
627f7932ba2SAmine Khaldi     memset(&environment3, 0, sizeof(environment3));
628f7932ba2SAmine Khaldi     environment3.Version = 3;
629f7932ba2SAmine Khaldi     environment3.Pool = pool;
630f7932ba2SAmine Khaldi     environment3.Size = sizeof(environment3);
63188a63011SJustin Miller 
63288a63011SJustin Miller     for (i = 0; i < 3; ++i)
63388a63011SJustin Miller     {
63488a63011SJustin Miller         environment3.CallbackPriority = TP_CALLBACK_PRIORITY_HIGH + i;
635f7932ba2SAmine Khaldi         status = pTpSimpleTryPost(simple_cb, semaphore, (TP_CALLBACK_ENVIRON *)&environment3);
63688a63011SJustin Miller         ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
637f7932ba2SAmine Khaldi         result = WaitForSingleObject(semaphore, 1000);
63888a63011SJustin Miller         ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
63988a63011SJustin Miller     }
64088a63011SJustin Miller 
64188a63011SJustin Miller     environment3.CallbackPriority = 10;
64288a63011SJustin Miller     status = pTpSimpleTryPost(simple_cb, semaphore, (TP_CALLBACK_ENVIRON *)&environment3);
64388a63011SJustin Miller     ok(status == STATUS_INVALID_PARAMETER || broken(!status) /* Vista does not support priorities */,
64488a63011SJustin Miller             "TpSimpleTryPost failed with status %lx\n", status);
645*0bf42067SJustin Miller #endif
646f7932ba2SAmine Khaldi 
647f7932ba2SAmine Khaldi     /* test with invalid version number */
648f7932ba2SAmine Khaldi     memset(&environment, 0, sizeof(environment));
649f7932ba2SAmine Khaldi     environment.Version = 9999;
650f7932ba2SAmine Khaldi     environment.Pool = pool;
651f7932ba2SAmine Khaldi     status = pTpSimpleTryPost(simple_cb, semaphore, &environment);
652f7932ba2SAmine Khaldi     todo_wine
653f7932ba2SAmine Khaldi     ok(status == STATUS_INVALID_PARAMETER || broken(!status) /* Vista/2008 */,
65488a63011SJustin Miller        "TpSimpleTryPost unexpectedly returned status %lx\n", status);
655f7932ba2SAmine Khaldi     if (!status)
656f7932ba2SAmine Khaldi     {
657f7932ba2SAmine Khaldi         result = WaitForSingleObject(semaphore, 1000);
65888a63011SJustin Miller         ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
659f7932ba2SAmine Khaldi     }
660f7932ba2SAmine Khaldi 
661f7932ba2SAmine Khaldi     /* allocate a cleanup group for synchronization */
662f7932ba2SAmine Khaldi     group = NULL;
663f7932ba2SAmine Khaldi     status = pTpAllocCleanupGroup(&group);
66488a63011SJustin Miller     ok(!status, "TpAllocCleanupGroup failed with status %lx\n", status);
665f7932ba2SAmine Khaldi     ok(group != NULL, "expected pool != NULL\n");
666f7932ba2SAmine Khaldi 
667f7932ba2SAmine Khaldi     /* use cleanup group to wait for a simple callback */
668f7932ba2SAmine Khaldi     userdata = 0;
669f7932ba2SAmine Khaldi     memset(&environment, 0, sizeof(environment));
670f7932ba2SAmine Khaldi     environment.Version = 1;
671f7932ba2SAmine Khaldi     environment.Pool = pool;
672f7932ba2SAmine Khaldi     environment.CleanupGroup = group;
673f7932ba2SAmine Khaldi     status = pTpSimpleTryPost(simple2_cb, &userdata, &environment);
67488a63011SJustin Miller     ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
675f7932ba2SAmine Khaldi     pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
67688a63011SJustin Miller     ok(userdata == 1, "expected userdata = 1, got %lu\n", userdata);
677f7932ba2SAmine Khaldi 
678f7932ba2SAmine Khaldi     /* test cancellation of pending simple callbacks */
679f7932ba2SAmine Khaldi     userdata = 0;
680f7932ba2SAmine Khaldi     pTpSetPoolMaxThreads(pool, 10);
681f7932ba2SAmine Khaldi     memset(&environment, 0, sizeof(environment));
682f7932ba2SAmine Khaldi     environment.Version = 1;
683f7932ba2SAmine Khaldi     environment.Pool = pool;
684f7932ba2SAmine Khaldi     environment.CleanupGroup = group;
685f7932ba2SAmine Khaldi     for (i = 0; i < 100; i++)
686f7932ba2SAmine Khaldi     {
687f7932ba2SAmine Khaldi         status = pTpSimpleTryPost(simple2_cb, &userdata, &environment);
68888a63011SJustin Miller         ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
689f7932ba2SAmine Khaldi     }
690f7932ba2SAmine Khaldi     pTpReleaseCleanupGroupMembers(group, TRUE, NULL);
69188a63011SJustin Miller     ok(userdata < 100, "expected userdata < 100, got %lu\n", userdata);
69288a63011SJustin Miller 
69388a63011SJustin Miller     /* test querying and setting the stack size */
69488a63011SJustin Miller     status = pTpQueryPoolStackInformation(pool, &stack_info);
69588a63011SJustin Miller     ok(!status, "TpQueryPoolStackInformation failed: %lx\n", status);
69688a63011SJustin Miller     ok(stack_info.StackReserve == nt->OptionalHeader.SizeOfStackReserve, "expected default StackReserve, got %Ix\n", stack_info.StackReserve);
69788a63011SJustin Miller     ok(stack_info.StackCommit == nt->OptionalHeader.SizeOfStackCommit, "expected default StackCommit, got %Ix\n", stack_info.StackCommit);
69888a63011SJustin Miller 
69988a63011SJustin Miller     /* threadpool does not validate the stack size values */
70088a63011SJustin Miller     stack_info.StackReserve = stack_info.StackCommit = 1;
70188a63011SJustin Miller     status = pTpSetPoolStackInformation(pool, &stack_info);
70288a63011SJustin Miller     ok(!status, "TpSetPoolStackInformation failed: %lx\n", status);
70388a63011SJustin Miller 
70488a63011SJustin Miller     status = pTpQueryPoolStackInformation(pool, &stack_info);
70588a63011SJustin Miller     ok(!status, "TpQueryPoolStackInformation failed: %lx\n", status);
70688a63011SJustin Miller     ok(stack_info.StackReserve == 1, "expected 1 byte StackReserve, got %ld\n", (ULONG)stack_info.StackReserve);
70788a63011SJustin Miller     ok(stack_info.StackCommit == 1, "expected 1 byte StackCommit, got %ld\n", (ULONG)stack_info.StackCommit);
708f7932ba2SAmine Khaldi 
709f7932ba2SAmine Khaldi     /* cleanup */
710f7932ba2SAmine Khaldi     pTpReleaseCleanupGroup(group);
711f7932ba2SAmine Khaldi     pTpReleasePool(pool);
712f7932ba2SAmine Khaldi     CloseHandle(semaphore);
713f7932ba2SAmine Khaldi }
714f7932ba2SAmine Khaldi 
work_cb(TP_CALLBACK_INSTANCE * instance,void * userdata,TP_WORK * work)715f7932ba2SAmine Khaldi static void CALLBACK work_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
716f7932ba2SAmine Khaldi {
717f7932ba2SAmine Khaldi     Sleep(100);
718f7932ba2SAmine Khaldi     InterlockedIncrement((LONG *)userdata);
719f7932ba2SAmine Khaldi }
720f7932ba2SAmine Khaldi 
work2_cb(TP_CALLBACK_INSTANCE * instance,void * userdata,TP_WORK * work)721f7932ba2SAmine Khaldi static void CALLBACK work2_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
722f7932ba2SAmine Khaldi {
723f7932ba2SAmine Khaldi     Sleep(100);
724f7932ba2SAmine Khaldi     InterlockedExchangeAdd((LONG *)userdata, 0x10000);
725f7932ba2SAmine Khaldi }
726f7932ba2SAmine Khaldi 
test_tp_work(void)727f7932ba2SAmine Khaldi static void test_tp_work(void)
728f7932ba2SAmine Khaldi {
729f7932ba2SAmine Khaldi     TP_CALLBACK_ENVIRON environment;
730f7932ba2SAmine Khaldi     TP_WORK *work;
731f7932ba2SAmine Khaldi     TP_POOL *pool;
732f7932ba2SAmine Khaldi     NTSTATUS status;
733f7932ba2SAmine Khaldi     LONG userdata;
734f7932ba2SAmine Khaldi     int i;
735f7932ba2SAmine Khaldi 
736f7932ba2SAmine Khaldi     /* allocate new threadpool with only one thread */
737f7932ba2SAmine Khaldi     pool = NULL;
738f7932ba2SAmine Khaldi     status = pTpAllocPool(&pool, NULL);
73988a63011SJustin Miller     ok(!status, "TpAllocPool failed with status %lx\n", status);
740f7932ba2SAmine Khaldi     ok(pool != NULL, "expected pool != NULL\n");
741f7932ba2SAmine Khaldi     pTpSetPoolMaxThreads(pool, 1);
742f7932ba2SAmine Khaldi 
743f7932ba2SAmine Khaldi     /* allocate new work item */
744f7932ba2SAmine Khaldi     work = NULL;
745f7932ba2SAmine Khaldi     memset(&environment, 0, sizeof(environment));
746f7932ba2SAmine Khaldi     environment.Version = 1;
747f7932ba2SAmine Khaldi     environment.Pool = pool;
748f7932ba2SAmine Khaldi     status = pTpAllocWork(&work, work_cb, &userdata, &environment);
74988a63011SJustin Miller     ok(!status, "TpAllocWork failed with status %lx\n", status);
750f7932ba2SAmine Khaldi     ok(work != NULL, "expected work != NULL\n");
751f7932ba2SAmine Khaldi 
752f7932ba2SAmine Khaldi     /* post 5 identical work items at once */
753f7932ba2SAmine Khaldi     userdata = 0;
754f7932ba2SAmine Khaldi     for (i = 0; i < 5; i++)
755f7932ba2SAmine Khaldi         pTpPostWork(work);
756f7932ba2SAmine Khaldi     pTpWaitForWork(work, FALSE);
75788a63011SJustin Miller     ok(userdata == 5, "expected userdata = 5, got %lu\n", userdata);
758f7932ba2SAmine Khaldi 
759f7932ba2SAmine Khaldi     /* add more tasks and cancel them immediately */
760f7932ba2SAmine Khaldi     userdata = 0;
761f7932ba2SAmine Khaldi     for (i = 0; i < 10; i++)
762f7932ba2SAmine Khaldi         pTpPostWork(work);
763f7932ba2SAmine Khaldi     pTpWaitForWork(work, TRUE);
76488a63011SJustin Miller     ok(userdata < 10, "expected userdata < 10, got %lu\n", userdata);
765f7932ba2SAmine Khaldi 
766f7932ba2SAmine Khaldi     /* cleanup */
767f7932ba2SAmine Khaldi     pTpReleaseWork(work);
768f7932ba2SAmine Khaldi     pTpReleasePool(pool);
769f7932ba2SAmine Khaldi }
770f7932ba2SAmine Khaldi 
test_tp_work_scheduler(void)771f7932ba2SAmine Khaldi static void test_tp_work_scheduler(void)
772f7932ba2SAmine Khaldi {
773f7932ba2SAmine Khaldi     TP_CALLBACK_ENVIRON environment;
774f7932ba2SAmine Khaldi     TP_CLEANUP_GROUP *group;
775f7932ba2SAmine Khaldi     TP_WORK *work, *work2;
776f7932ba2SAmine Khaldi     TP_POOL *pool;
777f7932ba2SAmine Khaldi     NTSTATUS status;
778f7932ba2SAmine Khaldi     LONG userdata;
779f7932ba2SAmine Khaldi     int i;
780f7932ba2SAmine Khaldi 
781f7932ba2SAmine Khaldi     /* allocate new threadpool with only one thread */
782f7932ba2SAmine Khaldi     pool = NULL;
783f7932ba2SAmine Khaldi     status = pTpAllocPool(&pool, NULL);
78488a63011SJustin Miller     ok(!status, "TpAllocPool failed with status %lx\n", status);
785f7932ba2SAmine Khaldi     ok(pool != NULL, "expected pool != NULL\n");
786f7932ba2SAmine Khaldi     pTpSetPoolMaxThreads(pool, 1);
787f7932ba2SAmine Khaldi 
788f7932ba2SAmine Khaldi     /* create a cleanup group */
789f7932ba2SAmine Khaldi     group = NULL;
790f7932ba2SAmine Khaldi     status = pTpAllocCleanupGroup(&group);
79188a63011SJustin Miller     ok(!status, "TpAllocCleanupGroup failed with status %lx\n", status);
792f7932ba2SAmine Khaldi     ok(group != NULL, "expected pool != NULL\n");
793f7932ba2SAmine Khaldi 
794f7932ba2SAmine Khaldi     /* the first work item has no cleanup group associated */
795f7932ba2SAmine Khaldi     work = NULL;
796f7932ba2SAmine Khaldi     memset(&environment, 0, sizeof(environment));
797f7932ba2SAmine Khaldi     environment.Version = 1;
798f7932ba2SAmine Khaldi     environment.Pool = pool;
799f7932ba2SAmine Khaldi     status = pTpAllocWork(&work, work_cb, &userdata, &environment);
80088a63011SJustin Miller     ok(!status, "TpAllocWork failed with status %lx\n", status);
801f7932ba2SAmine Khaldi     ok(work != NULL, "expected work != NULL\n");
802f7932ba2SAmine Khaldi 
803f7932ba2SAmine Khaldi     /* allocate a second work item with a cleanup group */
804f7932ba2SAmine Khaldi     work2 = NULL;
805f7932ba2SAmine Khaldi     memset(&environment, 0, sizeof(environment));
806f7932ba2SAmine Khaldi     environment.Version = 1;
807f7932ba2SAmine Khaldi     environment.Pool = pool;
808f7932ba2SAmine Khaldi     environment.CleanupGroup = group;
809f7932ba2SAmine Khaldi     status = pTpAllocWork(&work2, work2_cb, &userdata, &environment);
81088a63011SJustin Miller     ok(!status, "TpAllocWork failed with status %lx\n", status);
811f7932ba2SAmine Khaldi     ok(work2 != NULL, "expected work2 != NULL\n");
812f7932ba2SAmine Khaldi 
813f7932ba2SAmine Khaldi     /* the 'work' callbacks are not blocking execution of 'work2' callbacks */
814f7932ba2SAmine Khaldi     userdata = 0;
815f7932ba2SAmine Khaldi     for (i = 0; i < 10; i++)
816f7932ba2SAmine Khaldi         pTpPostWork(work);
817f7932ba2SAmine Khaldi     for (i = 0; i < 10; i++)
818f7932ba2SAmine Khaldi         pTpPostWork(work2);
819f7932ba2SAmine Khaldi     Sleep(500);
820f7932ba2SAmine Khaldi     pTpWaitForWork(work, TRUE);
821f7932ba2SAmine Khaldi     pTpWaitForWork(work2, TRUE);
82288a63011SJustin Miller     ok(userdata & 0xffff, "expected userdata & 0xffff != 0, got %lu\n", userdata & 0xffff);
82388a63011SJustin Miller     ok(userdata >> 16, "expected userdata >> 16 != 0, got %lu\n", userdata >> 16);
824f7932ba2SAmine Khaldi 
825f7932ba2SAmine Khaldi     /* test TpReleaseCleanupGroupMembers on a work item */
826f7932ba2SAmine Khaldi     userdata = 0;
827f7932ba2SAmine Khaldi     for (i = 0; i < 10; i++)
828f7932ba2SAmine Khaldi         pTpPostWork(work);
829f7932ba2SAmine Khaldi     for (i = 0; i < 3; i++)
830f7932ba2SAmine Khaldi         pTpPostWork(work2);
831f7932ba2SAmine Khaldi     pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
832f7932ba2SAmine Khaldi     pTpWaitForWork(work, TRUE);
83388a63011SJustin Miller     ok((userdata & 0xffff) < 10, "expected userdata & 0xffff < 10, got %lu\n", userdata & 0xffff);
83488a63011SJustin Miller     ok((userdata >> 16) == 3, "expected userdata >> 16 == 3, got %lu\n", userdata >> 16);
835f7932ba2SAmine Khaldi 
836f7932ba2SAmine Khaldi     /* cleanup */
837f7932ba2SAmine Khaldi     pTpReleaseWork(work);
838f7932ba2SAmine Khaldi     pTpReleaseCleanupGroup(group);
839f7932ba2SAmine Khaldi     pTpReleasePool(pool);
840f7932ba2SAmine Khaldi }
841f7932ba2SAmine Khaldi 
simple_release_cb(TP_CALLBACK_INSTANCE * instance,void * userdata)842f7932ba2SAmine Khaldi static void CALLBACK simple_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
843f7932ba2SAmine Khaldi {
844f7932ba2SAmine Khaldi     HANDLE *semaphores = userdata;
845f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores, 1, NULL);
846f7932ba2SAmine Khaldi     Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */
847f7932ba2SAmine Khaldi }
848f7932ba2SAmine Khaldi 
work_release_cb(TP_CALLBACK_INSTANCE * instance,void * userdata,TP_WORK * work)849f7932ba2SAmine Khaldi static void CALLBACK work_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
850f7932ba2SAmine Khaldi {
851f7932ba2SAmine Khaldi     HANDLE semaphore = userdata;
852f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphore, 1, NULL);
853f7932ba2SAmine Khaldi     Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */
854f7932ba2SAmine Khaldi     pTpReleaseWork(work);
855f7932ba2SAmine Khaldi }
856f7932ba2SAmine Khaldi 
timer_release_cb(TP_CALLBACK_INSTANCE * instance,void * userdata,TP_TIMER * timer)857f7932ba2SAmine Khaldi static void CALLBACK timer_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer)
858f7932ba2SAmine Khaldi {
859f7932ba2SAmine Khaldi     HANDLE semaphore = userdata;
860f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphore, 1, NULL);
861f7932ba2SAmine Khaldi     Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */
862f7932ba2SAmine Khaldi     pTpReleaseTimer(timer);
863f7932ba2SAmine Khaldi }
864f7932ba2SAmine Khaldi 
wait_release_cb(TP_CALLBACK_INSTANCE * instance,void * userdata,TP_WAIT * wait,TP_WAIT_RESULT result)865f7932ba2SAmine Khaldi static void CALLBACK wait_release_cb(TP_CALLBACK_INSTANCE *instance, void *userdata,
866f7932ba2SAmine Khaldi                                      TP_WAIT *wait, TP_WAIT_RESULT result)
867f7932ba2SAmine Khaldi {
868f7932ba2SAmine Khaldi     HANDLE semaphore = userdata;
869f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphore, 1, NULL);
870f7932ba2SAmine Khaldi     Sleep(200); /* wait until main thread is in TpReleaseCleanupGroupMembers */
871f7932ba2SAmine Khaldi     pTpReleaseWait(wait);
872f7932ba2SAmine Khaldi }
873f7932ba2SAmine Khaldi 
test_tp_group_wait(void)874f7932ba2SAmine Khaldi static void test_tp_group_wait(void)
875f7932ba2SAmine Khaldi {
876f7932ba2SAmine Khaldi     TP_CALLBACK_ENVIRON environment;
877f7932ba2SAmine Khaldi     TP_CLEANUP_GROUP *group;
878f7932ba2SAmine Khaldi     LARGE_INTEGER when;
879f7932ba2SAmine Khaldi     HANDLE semaphore;
880f7932ba2SAmine Khaldi     NTSTATUS status;
881f7932ba2SAmine Khaldi     TP_TIMER *timer;
882f7932ba2SAmine Khaldi     TP_WAIT *wait;
883f7932ba2SAmine Khaldi     TP_WORK *work;
884f7932ba2SAmine Khaldi     TP_POOL *pool;
885f7932ba2SAmine Khaldi     DWORD result;
886f7932ba2SAmine Khaldi 
887f7932ba2SAmine Khaldi     semaphore = CreateSemaphoreA(NULL, 0, 1, NULL);
88888a63011SJustin Miller     ok(semaphore != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
889f7932ba2SAmine Khaldi 
890f7932ba2SAmine Khaldi     /* allocate new threadpool */
891f7932ba2SAmine Khaldi     pool = NULL;
892f7932ba2SAmine Khaldi     status = pTpAllocPool(&pool, NULL);
89388a63011SJustin Miller     ok(!status, "TpAllocPool failed with status %lx\n", status);
894f7932ba2SAmine Khaldi     ok(pool != NULL, "expected pool != NULL\n");
895f7932ba2SAmine Khaldi 
896f7932ba2SAmine Khaldi     /* allocate a cleanup group */
897f7932ba2SAmine Khaldi     group = NULL;
898f7932ba2SAmine Khaldi     status = pTpAllocCleanupGroup(&group);
89988a63011SJustin Miller     ok(!status, "TpAllocCleanupGroup failed with status %lx\n", status);
900f7932ba2SAmine Khaldi     ok(group != NULL, "expected pool != NULL\n");
901f7932ba2SAmine Khaldi 
902f7932ba2SAmine Khaldi     /* release work object during TpReleaseCleanupGroupMembers */
903f7932ba2SAmine Khaldi     work = NULL;
904f7932ba2SAmine Khaldi     memset(&environment, 0, sizeof(environment));
905f7932ba2SAmine Khaldi     environment.Version = 1;
906f7932ba2SAmine Khaldi     environment.Pool = pool;
907f7932ba2SAmine Khaldi     environment.CleanupGroup = group;
908f7932ba2SAmine Khaldi     status = pTpAllocWork(&work, work_release_cb, semaphore, &environment);
90988a63011SJustin Miller     ok(!status, "TpAllocWork failed with status %lx\n", status);
910f7932ba2SAmine Khaldi     ok(work != NULL, "expected work != NULL\n");
911f7932ba2SAmine Khaldi     pTpPostWork(work);
912f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphore, 1000);
91388a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
914f7932ba2SAmine Khaldi     pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
915f7932ba2SAmine Khaldi 
916f7932ba2SAmine Khaldi     /* release timer object during TpReleaseCleanupGroupMembers */
917f7932ba2SAmine Khaldi     timer = NULL;
918f7932ba2SAmine Khaldi     memset(&environment, 0, sizeof(environment));
919f7932ba2SAmine Khaldi     environment.Version = 1;
920f7932ba2SAmine Khaldi     environment.Pool = pool;
921f7932ba2SAmine Khaldi     environment.CleanupGroup = group;
922f7932ba2SAmine Khaldi     status = pTpAllocTimer(&timer, timer_release_cb, semaphore, &environment);
92388a63011SJustin Miller     ok(!status, "TpAllocTimer failed with status %lx\n", status);
924f7932ba2SAmine Khaldi     ok(timer != NULL, "expected timer != NULL\n");
925f7932ba2SAmine Khaldi     when.QuadPart = 0;
926f7932ba2SAmine Khaldi     pTpSetTimer(timer, &when, 0, 0);
927f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphore, 1000);
92888a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
929f7932ba2SAmine Khaldi     pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
930f7932ba2SAmine Khaldi 
931f7932ba2SAmine Khaldi     /* release wait object during TpReleaseCleanupGroupMembers */
932f7932ba2SAmine Khaldi     wait = NULL;
933f7932ba2SAmine Khaldi     memset(&environment, 0, sizeof(environment));
934f7932ba2SAmine Khaldi     environment.Version = 1;
935f7932ba2SAmine Khaldi     environment.Pool = pool;
936f7932ba2SAmine Khaldi     environment.CleanupGroup = group;
937f7932ba2SAmine Khaldi     status = pTpAllocWait(&wait, wait_release_cb, semaphore, &environment);
93888a63011SJustin Miller     ok(!status, "TpAllocWait failed with status %lx\n", status);
939f7932ba2SAmine Khaldi     ok(wait != NULL, "expected wait != NULL\n");
940f7932ba2SAmine Khaldi     when.QuadPart = 0;
941f7932ba2SAmine Khaldi     pTpSetWait(wait, INVALID_HANDLE_VALUE, &when);
942f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphore, 1000);
94388a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
944f7932ba2SAmine Khaldi     pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
945f7932ba2SAmine Khaldi 
946f7932ba2SAmine Khaldi     /* cleanup */
947f7932ba2SAmine Khaldi     pTpReleaseCleanupGroup(group);
948f7932ba2SAmine Khaldi     pTpReleasePool(pool);
949f7932ba2SAmine Khaldi     CloseHandle(semaphore);
950f7932ba2SAmine Khaldi }
951f7932ba2SAmine Khaldi 
952f7932ba2SAmine Khaldi static DWORD group_cancel_tid;
953f7932ba2SAmine Khaldi 
simple_group_cancel_cb(TP_CALLBACK_INSTANCE * instance,void * userdata)954f7932ba2SAmine Khaldi static void CALLBACK simple_group_cancel_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
955f7932ba2SAmine Khaldi {
956f7932ba2SAmine Khaldi     HANDLE *semaphores = userdata;
957f7932ba2SAmine Khaldi     NTSTATUS status;
958f7932ba2SAmine Khaldi     DWORD result;
959f7932ba2SAmine Khaldi     int i;
960f7932ba2SAmine Khaldi 
961f7932ba2SAmine Khaldi     status = pTpCallbackMayRunLong(instance);
962f7932ba2SAmine Khaldi     ok(status == STATUS_TOO_MANY_THREADS || broken(status == 1) /* Win Vista / 2008 */,
96388a63011SJustin Miller        "expected STATUS_TOO_MANY_THREADS, got %08lx\n", status);
964f7932ba2SAmine Khaldi 
965f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[1], 1, NULL);
966f7932ba2SAmine Khaldi     for (i = 0; i < 4; i++)
967f7932ba2SAmine Khaldi     {
968f7932ba2SAmine Khaldi         result = WaitForSingleObject(semaphores[0], 1000);
96988a63011SJustin Miller         ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
970f7932ba2SAmine Khaldi     }
971f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[1], 1, NULL);
972f7932ba2SAmine Khaldi }
973f7932ba2SAmine Khaldi 
work_group_cancel_cb(TP_CALLBACK_INSTANCE * instance,void * userdata,TP_WORK * work)974f7932ba2SAmine Khaldi static void CALLBACK work_group_cancel_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
975f7932ba2SAmine Khaldi {
976f7932ba2SAmine Khaldi     HANDLE *semaphores = userdata;
977f7932ba2SAmine Khaldi     DWORD result;
978f7932ba2SAmine Khaldi 
979f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[1], 1, NULL);
980f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 200);
98188a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
982f7932ba2SAmine Khaldi }
983f7932ba2SAmine Khaldi 
group_cancel_cleanup_release_cb(void * object,void * userdata)984f7932ba2SAmine Khaldi static void CALLBACK group_cancel_cleanup_release_cb(void *object, void *userdata)
985f7932ba2SAmine Khaldi {
986f7932ba2SAmine Khaldi     HANDLE *semaphores = userdata;
987f7932ba2SAmine Khaldi     group_cancel_tid = GetCurrentThreadId();
988f7932ba2SAmine Khaldi     ok(object == (void *)0xdeadbeef, "expected 0xdeadbeef, got %p\n", object);
989f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[0], 1, NULL);
990f7932ba2SAmine Khaldi }
991f7932ba2SAmine Khaldi 
group_cancel_cleanup_release2_cb(void * object,void * userdata)992f7932ba2SAmine Khaldi static void CALLBACK group_cancel_cleanup_release2_cb(void *object, void *userdata)
993f7932ba2SAmine Khaldi {
994f7932ba2SAmine Khaldi     HANDLE *semaphores = userdata;
995f7932ba2SAmine Khaldi     group_cancel_tid = GetCurrentThreadId();
996f7932ba2SAmine Khaldi     ok(object == userdata, "expected %p, got %p\n", userdata, object);
997f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[0], 1, NULL);
998f7932ba2SAmine Khaldi }
999f7932ba2SAmine Khaldi 
group_cancel_cleanup_increment_cb(void * object,void * userdata)1000f7932ba2SAmine Khaldi static void CALLBACK group_cancel_cleanup_increment_cb(void *object, void *userdata)
1001f7932ba2SAmine Khaldi {
1002f7932ba2SAmine Khaldi     group_cancel_tid = GetCurrentThreadId();
1003f7932ba2SAmine Khaldi     InterlockedIncrement((LONG *)userdata);
1004f7932ba2SAmine Khaldi }
1005f7932ba2SAmine Khaldi 
unexpected_simple_cb(TP_CALLBACK_INSTANCE * instance,void * userdata)1006f7932ba2SAmine Khaldi static void CALLBACK unexpected_simple_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
1007f7932ba2SAmine Khaldi {
1008f7932ba2SAmine Khaldi     ok(0, "Unexpected callback\n");
1009f7932ba2SAmine Khaldi }
1010f7932ba2SAmine Khaldi 
unexpected_work_cb(TP_CALLBACK_INSTANCE * instance,void * userdata,TP_WORK * work)1011f7932ba2SAmine Khaldi static void CALLBACK unexpected_work_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
1012f7932ba2SAmine Khaldi {
1013f7932ba2SAmine Khaldi     ok(0, "Unexpected callback\n");
1014f7932ba2SAmine Khaldi }
1015f7932ba2SAmine Khaldi 
unexpected_timer_cb(TP_CALLBACK_INSTANCE * instance,void * userdata,TP_TIMER * timer)1016f7932ba2SAmine Khaldi static void CALLBACK unexpected_timer_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer)
1017f7932ba2SAmine Khaldi {
1018f7932ba2SAmine Khaldi     ok(0, "Unexpected callback\n");
1019f7932ba2SAmine Khaldi }
1020f7932ba2SAmine Khaldi 
unexpected_wait_cb(TP_CALLBACK_INSTANCE * instance,void * userdata,TP_WAIT * wait,TP_WAIT_RESULT result)1021f7932ba2SAmine Khaldi static void CALLBACK unexpected_wait_cb(TP_CALLBACK_INSTANCE *instance, void *userdata,
1022f7932ba2SAmine Khaldi                                         TP_WAIT *wait, TP_WAIT_RESULT result)
1023f7932ba2SAmine Khaldi {
1024f7932ba2SAmine Khaldi     ok(0, "Unexpected callback\n");
1025f7932ba2SAmine Khaldi }
1026f7932ba2SAmine Khaldi 
unexpected_group_cancel_cleanup_cb(void * object,void * userdata)1027f7932ba2SAmine Khaldi static void CALLBACK unexpected_group_cancel_cleanup_cb(void *object, void *userdata)
1028f7932ba2SAmine Khaldi {
1029f7932ba2SAmine Khaldi     ok(0, "Unexpected callback\n");
1030f7932ba2SAmine Khaldi }
1031f7932ba2SAmine Khaldi 
test_tp_group_cancel(void)1032f7932ba2SAmine Khaldi static void test_tp_group_cancel(void)
1033f7932ba2SAmine Khaldi {
1034f7932ba2SAmine Khaldi     TP_CALLBACK_ENVIRON environment;
1035f7932ba2SAmine Khaldi     TP_CLEANUP_GROUP *group;
1036f7932ba2SAmine Khaldi     LONG userdata, userdata2;
1037f7932ba2SAmine Khaldi     HANDLE semaphores[2];
1038f7932ba2SAmine Khaldi     NTSTATUS status;
1039f7932ba2SAmine Khaldi     TP_TIMER *timer;
1040f7932ba2SAmine Khaldi     TP_WAIT *wait;
1041f7932ba2SAmine Khaldi     TP_WORK *work;
1042f7932ba2SAmine Khaldi     TP_POOL *pool;
1043f7932ba2SAmine Khaldi     DWORD result;
1044f7932ba2SAmine Khaldi     int i;
1045f7932ba2SAmine Khaldi 
1046f7932ba2SAmine Khaldi     semaphores[0] = CreateSemaphoreA(NULL, 0, 4, NULL);
104788a63011SJustin Miller     ok(semaphores[0] != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
1048f7932ba2SAmine Khaldi     semaphores[1] = CreateSemaphoreA(NULL, 0, 1, NULL);
104988a63011SJustin Miller     ok(semaphores[1] != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
1050f7932ba2SAmine Khaldi 
1051f7932ba2SAmine Khaldi     /* allocate new threadpool with only one thread */
1052f7932ba2SAmine Khaldi     pool = NULL;
1053f7932ba2SAmine Khaldi     status = pTpAllocPool(&pool, NULL);
105488a63011SJustin Miller     ok(!status, "TpAllocPool failed with status %lx\n", status);
1055f7932ba2SAmine Khaldi     ok(pool != NULL, "expected pool != NULL\n");
1056f7932ba2SAmine Khaldi     pTpSetPoolMaxThreads(pool, 1);
1057f7932ba2SAmine Khaldi 
1058f7932ba2SAmine Khaldi     /* allocate a cleanup group */
1059f7932ba2SAmine Khaldi     group = NULL;
1060f7932ba2SAmine Khaldi     status = pTpAllocCleanupGroup(&group);
106188a63011SJustin Miller     ok(!status, "TpAllocCleanupGroup failed with status %lx\n", status);
1062f7932ba2SAmine Khaldi     ok(group != NULL, "expected pool != NULL\n");
1063f7932ba2SAmine Khaldi 
1064f7932ba2SAmine Khaldi     /* test execution of cancellation callback */
1065f7932ba2SAmine Khaldi     memset(&environment, 0, sizeof(environment));
1066f7932ba2SAmine Khaldi     environment.Version = 1;
1067f7932ba2SAmine Khaldi     environment.Pool = pool;
1068f7932ba2SAmine Khaldi     status = pTpSimpleTryPost(simple_group_cancel_cb, semaphores, &environment);
106988a63011SJustin Miller     ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
1070f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[1], 1000);
107188a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1072f7932ba2SAmine Khaldi 
1073f7932ba2SAmine Khaldi     memset(&environment, 0, sizeof(environment));
1074f7932ba2SAmine Khaldi     environment.Version = 1;
1075f7932ba2SAmine Khaldi     environment.Pool = pool;
1076f7932ba2SAmine Khaldi     environment.CleanupGroup = group;
1077f7932ba2SAmine Khaldi     environment.CleanupGroupCancelCallback = group_cancel_cleanup_release_cb;
1078f7932ba2SAmine Khaldi     status = pTpSimpleTryPost(unexpected_simple_cb, (void *)0xdeadbeef, &environment);
107988a63011SJustin Miller     ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
1080f7932ba2SAmine Khaldi 
1081f7932ba2SAmine Khaldi     work = NULL;
1082f7932ba2SAmine Khaldi     status = pTpAllocWork(&work, unexpected_work_cb, (void *)0xdeadbeef, &environment);
108388a63011SJustin Miller     ok(!status, "TpAllocWork failed with status %lx\n", status);
1084f7932ba2SAmine Khaldi     ok(work != NULL, "expected work != NULL\n");
1085f7932ba2SAmine Khaldi 
1086f7932ba2SAmine Khaldi     timer = NULL;
1087f7932ba2SAmine Khaldi     status = pTpAllocTimer(&timer, unexpected_timer_cb, (void *)0xdeadbeef, &environment);
108888a63011SJustin Miller     ok(!status, "TpAllocTimer failed with status %lx\n", status);
1089f7932ba2SAmine Khaldi     ok(timer != NULL, "expected timer != NULL\n");
1090f7932ba2SAmine Khaldi 
1091f7932ba2SAmine Khaldi     wait = NULL;
1092f7932ba2SAmine Khaldi     status = pTpAllocWait(&wait, unexpected_wait_cb, (void *)0xdeadbeef, &environment);
109388a63011SJustin Miller     ok(!status, "TpAllocWait failed with status %lx\n", status);
1094f7932ba2SAmine Khaldi     ok(wait != NULL, "expected wait != NULL\n");
1095f7932ba2SAmine Khaldi 
1096f7932ba2SAmine Khaldi     group_cancel_tid = 0xdeadbeef;
1097f7932ba2SAmine Khaldi     pTpReleaseCleanupGroupMembers(group, TRUE, semaphores);
1098f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[1], 1000);
109988a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
110088a63011SJustin Miller     ok(group_cancel_tid == GetCurrentThreadId(), "expected tid %lx, got %lx\n",
1101f7932ba2SAmine Khaldi        GetCurrentThreadId(), group_cancel_tid);
1102f7932ba2SAmine Khaldi 
1103f7932ba2SAmine Khaldi     /* test if cancellation callbacks are executed before or after wait */
1104f7932ba2SAmine Khaldi     work = NULL;
1105f7932ba2SAmine Khaldi     memset(&environment, 0, sizeof(environment));
1106f7932ba2SAmine Khaldi     environment.Version = 1;
1107f7932ba2SAmine Khaldi     environment.Pool = pool;
1108f7932ba2SAmine Khaldi     environment.CleanupGroup = group;
1109f7932ba2SAmine Khaldi     environment.CleanupGroupCancelCallback = group_cancel_cleanup_release2_cb;
1110f7932ba2SAmine Khaldi     status = pTpAllocWork(&work, work_group_cancel_cb, semaphores, &environment);
111188a63011SJustin Miller     ok(!status, "TpAllocWork failed with status %lx\n", status);
1112f7932ba2SAmine Khaldi     ok(work != NULL, "expected work != NULL\n");
1113f7932ba2SAmine Khaldi     pTpPostWork(work);
1114f7932ba2SAmine Khaldi     pTpPostWork(work);
1115f7932ba2SAmine Khaldi 
1116f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[1], 1000);
111788a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1118f7932ba2SAmine Khaldi 
1119f7932ba2SAmine Khaldi     group_cancel_tid = 0xdeadbeef;
1120f7932ba2SAmine Khaldi     pTpReleaseCleanupGroupMembers(group, TRUE, semaphores);
1121f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 1000);
112288a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
112388a63011SJustin Miller     ok(group_cancel_tid == GetCurrentThreadId(), "expected tid %lx, got %lx\n",
1124f7932ba2SAmine Khaldi        GetCurrentThreadId(), group_cancel_tid);
1125f7932ba2SAmine Khaldi 
1126f7932ba2SAmine Khaldi     /* group cancel callback is not executed if object is destroyed while waiting */
1127f7932ba2SAmine Khaldi     work = NULL;
1128f7932ba2SAmine Khaldi     memset(&environment, 0, sizeof(environment));
1129f7932ba2SAmine Khaldi     environment.Version = 1;
1130f7932ba2SAmine Khaldi     environment.Pool = pool;
1131f7932ba2SAmine Khaldi     environment.CleanupGroup = group;
1132f7932ba2SAmine Khaldi     environment.CleanupGroupCancelCallback = unexpected_group_cancel_cleanup_cb;
1133f7932ba2SAmine Khaldi     status = pTpAllocWork(&work, work_release_cb, semaphores[1], &environment);
113488a63011SJustin Miller     ok(!status, "TpAllocWork failed with status %lx\n", status);
1135f7932ba2SAmine Khaldi     ok(work != NULL, "expected work != NULL\n");
1136f7932ba2SAmine Khaldi     pTpPostWork(work);
1137f7932ba2SAmine Khaldi 
1138f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[1], 1000);
113988a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1140f7932ba2SAmine Khaldi     pTpReleaseCleanupGroupMembers(group, TRUE, NULL);
1141f7932ba2SAmine Khaldi 
1142f7932ba2SAmine Khaldi     /* terminated simple callbacks should not trigger the group cancel callback */
1143f7932ba2SAmine Khaldi     memset(&environment, 0, sizeof(environment));
1144f7932ba2SAmine Khaldi     environment.Version = 1;
1145f7932ba2SAmine Khaldi     environment.Pool = pool;
1146f7932ba2SAmine Khaldi     environment.CleanupGroup = group;
1147f7932ba2SAmine Khaldi     environment.CleanupGroupCancelCallback = unexpected_group_cancel_cleanup_cb;
1148f7932ba2SAmine Khaldi     status = pTpSimpleTryPost(simple_release_cb, semaphores[1], &environment);
114988a63011SJustin Miller     ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
1150f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[1], 1000);
115188a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1152f7932ba2SAmine Khaldi     pTpReleaseCleanupGroupMembers(group, TRUE, semaphores);
1153f7932ba2SAmine Khaldi 
1154f7932ba2SAmine Khaldi     /* test cancellation callback for objects with multiple instances */
1155f7932ba2SAmine Khaldi     work = NULL;
1156f7932ba2SAmine Khaldi     memset(&environment, 0, sizeof(environment));
1157f7932ba2SAmine Khaldi     environment.Version = 1;
1158f7932ba2SAmine Khaldi     environment.Pool = pool;
1159f7932ba2SAmine Khaldi     environment.CleanupGroup = group;
1160f7932ba2SAmine Khaldi     environment.CleanupGroupCancelCallback = group_cancel_cleanup_increment_cb;
1161f7932ba2SAmine Khaldi     status = pTpAllocWork(&work, work_cb, &userdata, &environment);
116288a63011SJustin Miller     ok(!status, "TpAllocWork failed with status %lx\n", status);
1163f7932ba2SAmine Khaldi     ok(work != NULL, "expected work != NULL\n");
1164f7932ba2SAmine Khaldi 
1165f7932ba2SAmine Khaldi     /* post 10 identical work items at once */
1166f7932ba2SAmine Khaldi     userdata = userdata2 = 0;
1167f7932ba2SAmine Khaldi     for (i = 0; i < 10; i++)
1168f7932ba2SAmine Khaldi         pTpPostWork(work);
1169f7932ba2SAmine Khaldi 
1170f7932ba2SAmine Khaldi     /* check if we get multiple cancellation callbacks */
1171f7932ba2SAmine Khaldi     group_cancel_tid = 0xdeadbeef;
1172f7932ba2SAmine Khaldi     pTpReleaseCleanupGroupMembers(group, TRUE, &userdata2);
117388a63011SJustin Miller     ok(userdata <= 5, "expected userdata <= 5, got %lu\n", userdata);
117488a63011SJustin Miller     ok(userdata2 == 1, "expected only one cancellation callback, got %lu\n", userdata2);
117588a63011SJustin Miller     ok(group_cancel_tid == GetCurrentThreadId(), "expected tid %lx, got %lx\n",
1176f7932ba2SAmine Khaldi        GetCurrentThreadId(), group_cancel_tid);
1177f7932ba2SAmine Khaldi 
1178f7932ba2SAmine Khaldi     /* cleanup */
1179f7932ba2SAmine Khaldi     pTpReleaseCleanupGroup(group);
1180f7932ba2SAmine Khaldi     pTpReleasePool(pool);
1181f7932ba2SAmine Khaldi     CloseHandle(semaphores[0]);
1182f7932ba2SAmine Khaldi     CloseHandle(semaphores[1]);
1183f7932ba2SAmine Khaldi }
1184f7932ba2SAmine Khaldi 
instance_semaphore_completion_cb(TP_CALLBACK_INSTANCE * instance,void * userdata)1185f7932ba2SAmine Khaldi static void CALLBACK instance_semaphore_completion_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
1186f7932ba2SAmine Khaldi {
1187f7932ba2SAmine Khaldi     HANDLE *semaphores = userdata;
1188f7932ba2SAmine Khaldi     pTpCallbackReleaseSemaphoreOnCompletion(instance, semaphores[0], 1);
1189f7932ba2SAmine Khaldi }
1190f7932ba2SAmine Khaldi 
instance_finalization_cb(TP_CALLBACK_INSTANCE * instance,void * userdata)1191f7932ba2SAmine Khaldi static void CALLBACK instance_finalization_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
1192f7932ba2SAmine Khaldi {
1193f7932ba2SAmine Khaldi     HANDLE *semaphores = userdata;
1194f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[1], 1, NULL);
1195f7932ba2SAmine Khaldi }
1196f7932ba2SAmine Khaldi 
test_tp_instance(void)1197f7932ba2SAmine Khaldi static void test_tp_instance(void)
1198f7932ba2SAmine Khaldi {
1199f7932ba2SAmine Khaldi     TP_CALLBACK_ENVIRON environment;
1200f7932ba2SAmine Khaldi     HANDLE semaphores[2];
1201f7932ba2SAmine Khaldi     NTSTATUS status;
1202f7932ba2SAmine Khaldi     TP_POOL *pool;
1203f7932ba2SAmine Khaldi     DWORD result;
1204f7932ba2SAmine Khaldi 
1205f7932ba2SAmine Khaldi     semaphores[0] = CreateSemaphoreW(NULL, 0, 1, NULL);
1206f7932ba2SAmine Khaldi     ok(semaphores[0] != NULL, "failed to create semaphore\n");
1207f7932ba2SAmine Khaldi     semaphores[1] = CreateSemaphoreW(NULL, 0, 1, NULL);
1208f7932ba2SAmine Khaldi     ok(semaphores[1] != NULL, "failed to create semaphore\n");
1209f7932ba2SAmine Khaldi 
1210f7932ba2SAmine Khaldi     /* allocate new threadpool */
1211f7932ba2SAmine Khaldi     pool = NULL;
1212f7932ba2SAmine Khaldi     status = pTpAllocPool(&pool, NULL);
121388a63011SJustin Miller     ok(!status, "TpAllocPool failed with status %lx\n", status);
1214f7932ba2SAmine Khaldi     ok(pool != NULL, "expected pool != NULL\n");
1215f7932ba2SAmine Khaldi 
1216f7932ba2SAmine Khaldi     /* test for TpCallbackReleaseSemaphoreOnCompletion */
1217f7932ba2SAmine Khaldi     memset(&environment, 0, sizeof(environment));
1218f7932ba2SAmine Khaldi     environment.Version = 1;
1219f7932ba2SAmine Khaldi     environment.Pool = pool;
1220f7932ba2SAmine Khaldi     status = pTpSimpleTryPost(instance_semaphore_completion_cb, semaphores, &environment);
122188a63011SJustin Miller     ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
1222f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 1000);
122388a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1224f7932ba2SAmine Khaldi 
1225f7932ba2SAmine Khaldi     /* test for finalization callback */
1226f7932ba2SAmine Khaldi     memset(&environment, 0, sizeof(environment));
1227f7932ba2SAmine Khaldi     environment.Version = 1;
1228f7932ba2SAmine Khaldi     environment.Pool = pool;
1229f7932ba2SAmine Khaldi     environment.FinalizationCallback = instance_finalization_cb;
1230f7932ba2SAmine Khaldi     status = pTpSimpleTryPost(instance_semaphore_completion_cb, semaphores, &environment);
123188a63011SJustin Miller     ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
1232f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 1000);
123388a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1234f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[1], 1000);
123588a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1236f7932ba2SAmine Khaldi 
1237f7932ba2SAmine Khaldi     /* cleanup */
1238f7932ba2SAmine Khaldi     pTpReleasePool(pool);
1239f7932ba2SAmine Khaldi     CloseHandle(semaphores[0]);
1240f7932ba2SAmine Khaldi     CloseHandle(semaphores[1]);
1241f7932ba2SAmine Khaldi }
1242f7932ba2SAmine Khaldi 
disassociate_cb(TP_CALLBACK_INSTANCE * instance,void * userdata,TP_WORK * work)1243f7932ba2SAmine Khaldi static void CALLBACK disassociate_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
1244f7932ba2SAmine Khaldi {
1245f7932ba2SAmine Khaldi     HANDLE *semaphores = userdata;
1246f7932ba2SAmine Khaldi     DWORD result;
1247f7932ba2SAmine Khaldi 
1248f7932ba2SAmine Khaldi     pTpDisassociateCallback(instance);
1249f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 1000);
125088a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1251f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[1], 1, NULL);
1252f7932ba2SAmine Khaldi }
1253f7932ba2SAmine Khaldi 
disassociate2_cb(TP_CALLBACK_INSTANCE * instance,void * userdata,TP_WORK * work)1254f7932ba2SAmine Khaldi static void CALLBACK disassociate2_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WORK *work)
1255f7932ba2SAmine Khaldi {
1256f7932ba2SAmine Khaldi     HANDLE *semaphores = userdata;
1257f7932ba2SAmine Khaldi     DWORD result;
1258f7932ba2SAmine Khaldi 
1259f7932ba2SAmine Khaldi     pTpDisassociateCallback(instance);
1260f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
126188a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1262f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[1], 1, NULL);
1263f7932ba2SAmine Khaldi }
1264f7932ba2SAmine Khaldi 
disassociate3_cb(TP_CALLBACK_INSTANCE * instance,void * userdata)1265f7932ba2SAmine Khaldi static void CALLBACK disassociate3_cb(TP_CALLBACK_INSTANCE *instance, void *userdata)
1266f7932ba2SAmine Khaldi {
1267f7932ba2SAmine Khaldi     HANDLE *semaphores = userdata;
1268f7932ba2SAmine Khaldi     DWORD result;
1269f7932ba2SAmine Khaldi 
1270f7932ba2SAmine Khaldi     pTpDisassociateCallback(instance);
1271f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
127288a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1273f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[1], 1, NULL);
1274f7932ba2SAmine Khaldi }
1275f7932ba2SAmine Khaldi 
test_tp_disassociate(void)1276f7932ba2SAmine Khaldi static void test_tp_disassociate(void)
1277f7932ba2SAmine Khaldi {
1278f7932ba2SAmine Khaldi     TP_CALLBACK_ENVIRON environment;
1279f7932ba2SAmine Khaldi     TP_CLEANUP_GROUP *group;
1280f7932ba2SAmine Khaldi     HANDLE semaphores[2];
1281f7932ba2SAmine Khaldi     NTSTATUS status;
1282f7932ba2SAmine Khaldi     TP_POOL *pool;
1283f7932ba2SAmine Khaldi     TP_WORK *work;
1284f7932ba2SAmine Khaldi     DWORD result;
1285f7932ba2SAmine Khaldi 
1286f7932ba2SAmine Khaldi     semaphores[0] = CreateSemaphoreW(NULL, 0, 1, NULL);
1287f7932ba2SAmine Khaldi     ok(semaphores[0] != NULL, "failed to create semaphore\n");
1288f7932ba2SAmine Khaldi     semaphores[1] = CreateSemaphoreW(NULL, 0, 1, NULL);
1289f7932ba2SAmine Khaldi     ok(semaphores[1] != NULL, "failed to create semaphore\n");
1290f7932ba2SAmine Khaldi 
1291f7932ba2SAmine Khaldi     /* allocate new threadpool and cleanup group */
1292f7932ba2SAmine Khaldi     pool = NULL;
1293f7932ba2SAmine Khaldi     status = pTpAllocPool(&pool, NULL);
129488a63011SJustin Miller     ok(!status, "TpAllocPool failed with status %lx\n", status);
1295f7932ba2SAmine Khaldi     ok(pool != NULL, "expected pool != NULL\n");
1296f7932ba2SAmine Khaldi 
1297f7932ba2SAmine Khaldi     group = NULL;
1298f7932ba2SAmine Khaldi     status = pTpAllocCleanupGroup(&group);
129988a63011SJustin Miller     ok(!status, "TpAllocCleanupGroup failed with status %lx\n", status);
1300f7932ba2SAmine Khaldi     ok(group != NULL, "expected pool != NULL\n");
1301f7932ba2SAmine Khaldi 
1302f7932ba2SAmine Khaldi     /* test TpDisassociateCallback on work objects without group */
1303f7932ba2SAmine Khaldi     work = NULL;
1304f7932ba2SAmine Khaldi     memset(&environment, 0, sizeof(environment));
1305f7932ba2SAmine Khaldi     environment.Version = 1;
1306f7932ba2SAmine Khaldi     environment.Pool = pool;
1307f7932ba2SAmine Khaldi     status = pTpAllocWork(&work, disassociate_cb, semaphores, &environment);
130888a63011SJustin Miller     ok(!status, "TpAllocWork failed with status %lx\n", status);
1309f7932ba2SAmine Khaldi     ok(work != NULL, "expected work != NULL\n");
1310f7932ba2SAmine Khaldi 
1311f7932ba2SAmine Khaldi     pTpPostWork(work);
1312f7932ba2SAmine Khaldi     pTpWaitForWork(work, FALSE);
1313f7932ba2SAmine Khaldi 
1314f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[1], 100);
131588a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1316f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[0], 1, NULL);
1317f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[1], 1000);
131888a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1319f7932ba2SAmine Khaldi     pTpReleaseWork(work);
1320f7932ba2SAmine Khaldi 
1321f7932ba2SAmine Khaldi     /* test TpDisassociateCallback on work objects with group (1) */
1322f7932ba2SAmine Khaldi     work = NULL;
1323f7932ba2SAmine Khaldi     memset(&environment, 0, sizeof(environment));
1324f7932ba2SAmine Khaldi     environment.Version = 1;
1325f7932ba2SAmine Khaldi     environment.Pool = pool;
1326f7932ba2SAmine Khaldi     environment.CleanupGroup = group;
1327f7932ba2SAmine Khaldi     status = pTpAllocWork(&work, disassociate_cb, semaphores, &environment);
132888a63011SJustin Miller     ok(!status, "TpAllocWork failed with status %lx\n", status);
1329f7932ba2SAmine Khaldi     ok(work != NULL, "expected work != NULL\n");
1330f7932ba2SAmine Khaldi 
1331f7932ba2SAmine Khaldi     pTpPostWork(work);
1332f7932ba2SAmine Khaldi     pTpWaitForWork(work, FALSE);
1333f7932ba2SAmine Khaldi 
1334f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[1], 100);
133588a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1336f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[0], 1, NULL);
1337f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[1], 1000);
133888a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1339f7932ba2SAmine Khaldi     pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
1340f7932ba2SAmine Khaldi 
1341f7932ba2SAmine Khaldi     /* test TpDisassociateCallback on work objects with group (2) */
1342f7932ba2SAmine Khaldi     work = NULL;
1343f7932ba2SAmine Khaldi     memset(&environment, 0, sizeof(environment));
1344f7932ba2SAmine Khaldi     environment.Version = 1;
1345f7932ba2SAmine Khaldi     environment.Pool = pool;
1346f7932ba2SAmine Khaldi     environment.CleanupGroup = group;
1347f7932ba2SAmine Khaldi     status = pTpAllocWork(&work, disassociate2_cb, semaphores, &environment);
134888a63011SJustin Miller     ok(!status, "TpAllocWork failed with status %lx\n", status);
1349f7932ba2SAmine Khaldi     ok(work != NULL, "expected work != NULL\n");
1350f7932ba2SAmine Khaldi 
1351f7932ba2SAmine Khaldi     pTpPostWork(work);
1352f7932ba2SAmine Khaldi     pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
1353f7932ba2SAmine Khaldi 
1354f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[0], 1, NULL);
1355f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[1], 1000);
135688a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1357f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 1000);
135888a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1359f7932ba2SAmine Khaldi 
1360f7932ba2SAmine Khaldi     /* test TpDisassociateCallback on simple callbacks */
1361f7932ba2SAmine Khaldi     memset(&environment, 0, sizeof(environment));
1362f7932ba2SAmine Khaldi     environment.Version = 1;
1363f7932ba2SAmine Khaldi     environment.Pool = pool;
1364f7932ba2SAmine Khaldi     environment.CleanupGroup = group;
1365f7932ba2SAmine Khaldi     status = pTpSimpleTryPost(disassociate3_cb, semaphores, &environment);
136688a63011SJustin Miller     ok(!status, "TpSimpleTryPost failed with status %lx\n", status);
1367f7932ba2SAmine Khaldi 
1368f7932ba2SAmine Khaldi     pTpReleaseCleanupGroupMembers(group, FALSE, NULL);
1369f7932ba2SAmine Khaldi 
1370f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[0], 1, NULL);
1371f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[1], 1000);
137288a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1373f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 1000);
137488a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1375f7932ba2SAmine Khaldi 
1376f7932ba2SAmine Khaldi     /* cleanup */
1377f7932ba2SAmine Khaldi     pTpReleaseCleanupGroup(group);
1378f7932ba2SAmine Khaldi     pTpReleasePool(pool);
1379f7932ba2SAmine Khaldi     CloseHandle(semaphores[0]);
1380f7932ba2SAmine Khaldi     CloseHandle(semaphores[1]);
1381f7932ba2SAmine Khaldi }
1382f7932ba2SAmine Khaldi 
timer_cb(TP_CALLBACK_INSTANCE * instance,void * userdata,TP_TIMER * timer)1383f7932ba2SAmine Khaldi static void CALLBACK timer_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer)
1384f7932ba2SAmine Khaldi {
1385f7932ba2SAmine Khaldi     HANDLE semaphore = userdata;
1386f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphore, 1, NULL);
1387f7932ba2SAmine Khaldi }
1388f7932ba2SAmine Khaldi 
test_tp_timer(void)1389f7932ba2SAmine Khaldi static void test_tp_timer(void)
1390f7932ba2SAmine Khaldi {
1391f7932ba2SAmine Khaldi     TP_CALLBACK_ENVIRON environment;
1392f7932ba2SAmine Khaldi     DWORD result, ticks;
1393f7932ba2SAmine Khaldi     LARGE_INTEGER when;
1394f7932ba2SAmine Khaldi     HANDLE semaphore;
1395f7932ba2SAmine Khaldi     NTSTATUS status;
1396f7932ba2SAmine Khaldi     TP_TIMER *timer;
1397f7932ba2SAmine Khaldi     TP_POOL *pool;
1398f7932ba2SAmine Khaldi     BOOL success;
1399f7932ba2SAmine Khaldi     int i;
1400f7932ba2SAmine Khaldi 
1401f7932ba2SAmine Khaldi     semaphore = CreateSemaphoreA(NULL, 0, 1, NULL);
140288a63011SJustin Miller     ok(semaphore != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
1403f7932ba2SAmine Khaldi 
1404f7932ba2SAmine Khaldi     /* allocate new threadpool */
1405f7932ba2SAmine Khaldi     pool = NULL;
1406f7932ba2SAmine Khaldi     status = pTpAllocPool(&pool, NULL);
140788a63011SJustin Miller     ok(!status, "TpAllocPool failed with status %lx\n", status);
1408f7932ba2SAmine Khaldi     ok(pool != NULL, "expected pool != NULL\n");
1409f7932ba2SAmine Khaldi 
1410f7932ba2SAmine Khaldi     /* allocate new timer */
1411f7932ba2SAmine Khaldi     timer = NULL;
1412f7932ba2SAmine Khaldi     memset(&environment, 0, sizeof(environment));
1413f7932ba2SAmine Khaldi     environment.Version = 1;
1414f7932ba2SAmine Khaldi     environment.Pool = pool;
1415f7932ba2SAmine Khaldi     status = pTpAllocTimer(&timer, timer_cb, semaphore, &environment);
141688a63011SJustin Miller     ok(!status, "TpAllocTimer failed with status %lx\n", status);
1417f7932ba2SAmine Khaldi     ok(timer != NULL, "expected timer != NULL\n");
1418f7932ba2SAmine Khaldi 
1419f7932ba2SAmine Khaldi     success = pTpIsTimerSet(timer);
1420f7932ba2SAmine Khaldi     ok(!success, "TpIsTimerSet returned TRUE\n");
1421f7932ba2SAmine Khaldi 
1422f7932ba2SAmine Khaldi     /* test timer with a relative timeout */
1423f7932ba2SAmine Khaldi     when.QuadPart = (ULONGLONG)200 * -10000;
1424f7932ba2SAmine Khaldi     pTpSetTimer(timer, &when, 0, 0);
1425f7932ba2SAmine Khaldi     success = pTpIsTimerSet(timer);
1426f7932ba2SAmine Khaldi     ok(success, "TpIsTimerSet returned FALSE\n");
1427f7932ba2SAmine Khaldi 
1428f7932ba2SAmine Khaldi     pTpWaitForTimer(timer, FALSE);
1429f7932ba2SAmine Khaldi 
1430f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphore, 100);
143188a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1432f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphore, 200);
143388a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1434f7932ba2SAmine Khaldi     success = pTpIsTimerSet(timer);
1435f7932ba2SAmine Khaldi     ok(success, "TpIsTimerSet returned FALSE\n");
1436f7932ba2SAmine Khaldi 
1437f7932ba2SAmine Khaldi     /* test timer with an absolute timeout */
1438f7932ba2SAmine Khaldi     NtQuerySystemTime( &when );
1439f7932ba2SAmine Khaldi     when.QuadPart += (ULONGLONG)200 * 10000;
1440f7932ba2SAmine Khaldi     pTpSetTimer(timer, &when, 0, 0);
1441f7932ba2SAmine Khaldi     success = pTpIsTimerSet(timer);
1442f7932ba2SAmine Khaldi     ok(success, "TpIsTimerSet returned FALSE\n");
1443f7932ba2SAmine Khaldi 
1444f7932ba2SAmine Khaldi     pTpWaitForTimer(timer, FALSE);
1445f7932ba2SAmine Khaldi 
1446f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphore, 100);
144788a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1448f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphore, 200);
144988a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1450f7932ba2SAmine Khaldi     success = pTpIsTimerSet(timer);
1451f7932ba2SAmine Khaldi     ok(success, "TpIsTimerSet returned FALSE\n");
1452f7932ba2SAmine Khaldi 
1453f7932ba2SAmine Khaldi     /* test timer with zero timeout */
1454f7932ba2SAmine Khaldi     when.QuadPart = 0;
1455f7932ba2SAmine Khaldi     pTpSetTimer(timer, &when, 0, 0);
1456f7932ba2SAmine Khaldi     success = pTpIsTimerSet(timer);
1457f7932ba2SAmine Khaldi     ok(success, "TpIsTimerSet returned FALSE\n");
1458f7932ba2SAmine Khaldi 
1459f7932ba2SAmine Khaldi     pTpWaitForTimer(timer, FALSE);
1460f7932ba2SAmine Khaldi 
1461f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphore, 50);
146288a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1463f7932ba2SAmine Khaldi     success = pTpIsTimerSet(timer);
1464f7932ba2SAmine Khaldi     ok(success, "TpIsTimerSet returned FALSE\n");
1465f7932ba2SAmine Khaldi 
1466f7932ba2SAmine Khaldi     /* unset the timer */
1467f7932ba2SAmine Khaldi     pTpSetTimer(timer, NULL, 0, 0);
1468f7932ba2SAmine Khaldi     success = pTpIsTimerSet(timer);
1469f7932ba2SAmine Khaldi     ok(!success, "TpIsTimerSet returned TRUE\n");
1470f7932ba2SAmine Khaldi     pTpWaitForTimer(timer, TRUE);
1471f7932ba2SAmine Khaldi 
1472f7932ba2SAmine Khaldi     pTpReleaseTimer(timer);
1473f7932ba2SAmine Khaldi     CloseHandle(semaphore);
1474f7932ba2SAmine Khaldi 
1475f7932ba2SAmine Khaldi     semaphore = CreateSemaphoreA(NULL, 0, 3, NULL);
147688a63011SJustin Miller     ok(semaphore != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
1477f7932ba2SAmine Khaldi 
1478f7932ba2SAmine Khaldi     /* allocate a new timer */
1479f7932ba2SAmine Khaldi     timer = NULL;
1480f7932ba2SAmine Khaldi     memset(&environment, 0, sizeof(environment));
1481f7932ba2SAmine Khaldi     environment.Version = 1;
1482f7932ba2SAmine Khaldi     environment.Pool = pool;
1483f7932ba2SAmine Khaldi     status = pTpAllocTimer(&timer, timer_cb, semaphore, &environment);
148488a63011SJustin Miller     ok(!status, "TpAllocTimer failed with status %lx\n", status);
1485f7932ba2SAmine Khaldi     ok(timer != NULL, "expected timer != NULL\n");
1486f7932ba2SAmine Khaldi 
1487f7932ba2SAmine Khaldi     /* test a relative timeout repeated periodically */
1488f7932ba2SAmine Khaldi     when.QuadPart = (ULONGLONG)200 * -10000;
1489f7932ba2SAmine Khaldi     pTpSetTimer(timer, &when, 200, 0);
1490f7932ba2SAmine Khaldi     success = pTpIsTimerSet(timer);
1491f7932ba2SAmine Khaldi     ok(success, "TpIsTimerSet returned FALSE\n");
1492f7932ba2SAmine Khaldi 
1493f7932ba2SAmine Khaldi     /* wait until the timer was triggered three times */
1494f7932ba2SAmine Khaldi     ticks = GetTickCount();
1495f7932ba2SAmine Khaldi     for (i = 0; i < 3; i++)
1496f7932ba2SAmine Khaldi     {
1497f7932ba2SAmine Khaldi         result = WaitForSingleObject(semaphore, 1000);
149888a63011SJustin Miller         ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1499f7932ba2SAmine Khaldi     }
1500f7932ba2SAmine Khaldi     ticks = GetTickCount() - ticks;
1501f7932ba2SAmine Khaldi     ok(ticks >= 500 && (ticks <= 700 || broken(ticks <= 750)) /* Win 7 */,
150288a63011SJustin Miller        "expected approximately 600 ticks, got %lu\n", ticks);
1503f7932ba2SAmine Khaldi 
1504f7932ba2SAmine Khaldi     /* unset the timer */
1505f7932ba2SAmine Khaldi     pTpSetTimer(timer, NULL, 0, 0);
1506f7932ba2SAmine Khaldi     success = pTpIsTimerSet(timer);
1507f7932ba2SAmine Khaldi     ok(!success, "TpIsTimerSet returned TRUE\n");
1508f7932ba2SAmine Khaldi     pTpWaitForTimer(timer, TRUE);
1509f7932ba2SAmine Khaldi 
1510f7932ba2SAmine Khaldi     /* cleanup */
1511f7932ba2SAmine Khaldi     pTpReleaseTimer(timer);
1512f7932ba2SAmine Khaldi     pTpReleasePool(pool);
1513f7932ba2SAmine Khaldi     CloseHandle(semaphore);
1514f7932ba2SAmine Khaldi }
1515f7932ba2SAmine Khaldi 
1516f7932ba2SAmine Khaldi struct window_length_info
1517f7932ba2SAmine Khaldi {
1518f7932ba2SAmine Khaldi     HANDLE semaphore;
1519f7932ba2SAmine Khaldi     DWORD ticks;
1520f7932ba2SAmine Khaldi };
1521f7932ba2SAmine Khaldi 
window_length_cb(TP_CALLBACK_INSTANCE * instance,void * userdata,TP_TIMER * timer)1522f7932ba2SAmine Khaldi static void CALLBACK window_length_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_TIMER *timer)
1523f7932ba2SAmine Khaldi {
1524f7932ba2SAmine Khaldi     struct window_length_info *info = userdata;
1525f7932ba2SAmine Khaldi     info->ticks = GetTickCount();
1526f7932ba2SAmine Khaldi     ReleaseSemaphore(info->semaphore, 1, NULL);
1527f7932ba2SAmine Khaldi }
1528f7932ba2SAmine Khaldi 
test_tp_window_length(void)1529f7932ba2SAmine Khaldi static void test_tp_window_length(void)
1530f7932ba2SAmine Khaldi {
1531f7932ba2SAmine Khaldi     struct window_length_info info1, info2;
1532f7932ba2SAmine Khaldi     TP_CALLBACK_ENVIRON environment;
1533f7932ba2SAmine Khaldi     TP_TIMER *timer1, *timer2;
1534f7932ba2SAmine Khaldi     LARGE_INTEGER when;
1535f7932ba2SAmine Khaldi     HANDLE semaphore;
1536f7932ba2SAmine Khaldi     NTSTATUS status;
1537f7932ba2SAmine Khaldi     TP_POOL *pool;
1538f7932ba2SAmine Khaldi     DWORD result;
1539f7932ba2SAmine Khaldi     BOOL merged;
1540f7932ba2SAmine Khaldi 
1541f7932ba2SAmine Khaldi     semaphore = CreateSemaphoreA(NULL, 0, 2, NULL);
154288a63011SJustin Miller     ok(semaphore != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
1543f7932ba2SAmine Khaldi 
1544f7932ba2SAmine Khaldi     /* allocate new threadpool */
1545f7932ba2SAmine Khaldi     pool = NULL;
1546f7932ba2SAmine Khaldi     status = pTpAllocPool(&pool, NULL);
154788a63011SJustin Miller     ok(!status, "TpAllocPool failed with status %lx\n", status);
1548f7932ba2SAmine Khaldi     ok(pool != NULL, "expected pool != NULL\n");
1549f7932ba2SAmine Khaldi 
1550f7932ba2SAmine Khaldi     /* allocate two identical timers */
1551f7932ba2SAmine Khaldi     memset(&environment, 0, sizeof(environment));
1552f7932ba2SAmine Khaldi     environment.Version = 1;
1553f7932ba2SAmine Khaldi     environment.Pool = pool;
1554f7932ba2SAmine Khaldi 
1555f7932ba2SAmine Khaldi     timer1 = NULL;
1556f7932ba2SAmine Khaldi     info1.semaphore = semaphore;
1557f7932ba2SAmine Khaldi     status = pTpAllocTimer(&timer1, window_length_cb, &info1, &environment);
155888a63011SJustin Miller     ok(!status, "TpAllocTimer failed with status %lx\n", status);
1559f7932ba2SAmine Khaldi     ok(timer1 != NULL, "expected timer1 != NULL\n");
1560f7932ba2SAmine Khaldi 
1561f7932ba2SAmine Khaldi     timer2 = NULL;
1562f7932ba2SAmine Khaldi     info2.semaphore = semaphore;
1563f7932ba2SAmine Khaldi     status = pTpAllocTimer(&timer2, window_length_cb, &info2, &environment);
156488a63011SJustin Miller     ok(!status, "TpAllocTimer failed with status %lx\n", status);
1565f7932ba2SAmine Khaldi     ok(timer2 != NULL, "expected timer2 != NULL\n");
1566f7932ba2SAmine Khaldi 
1567f7932ba2SAmine Khaldi     /* choose parameters so that timers are not merged */
1568f7932ba2SAmine Khaldi     info1.ticks = 0;
1569f7932ba2SAmine Khaldi     info2.ticks = 0;
1570f7932ba2SAmine Khaldi 
1571f7932ba2SAmine Khaldi     NtQuerySystemTime( &when );
1572f7932ba2SAmine Khaldi     when.QuadPart += (ULONGLONG)250 * 10000;
1573f7932ba2SAmine Khaldi     pTpSetTimer(timer2, &when, 0, 0);
1574f7932ba2SAmine Khaldi     Sleep(50);
1575f7932ba2SAmine Khaldi     when.QuadPart -= (ULONGLONG)150 * 10000;
1576f7932ba2SAmine Khaldi     pTpSetTimer(timer1, &when, 0, 75);
1577f7932ba2SAmine Khaldi 
1578f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphore, 1000);
157988a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1580f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphore, 1000);
158188a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1582f7932ba2SAmine Khaldi     ok(info1.ticks != 0 && info2.ticks != 0, "expected that ticks are nonzero\n");
1583f7932ba2SAmine Khaldi     ok(info2.ticks >= info1.ticks + 75 || broken(info2.ticks < info1.ticks + 75) /* Win 2008 */,
1584f7932ba2SAmine Khaldi        "expected that timers are not merged\n");
1585f7932ba2SAmine Khaldi 
1586f7932ba2SAmine Khaldi     /* timers will be merged */
1587f7932ba2SAmine Khaldi     info1.ticks = 0;
1588f7932ba2SAmine Khaldi     info2.ticks = 0;
1589f7932ba2SAmine Khaldi 
1590f7932ba2SAmine Khaldi     NtQuerySystemTime( &when );
1591f7932ba2SAmine Khaldi     when.QuadPart += (ULONGLONG)250 * 10000;
1592f7932ba2SAmine Khaldi     pTpSetTimer(timer2, &when, 0, 0);
1593f7932ba2SAmine Khaldi     Sleep(50);
1594f7932ba2SAmine Khaldi     when.QuadPart -= (ULONGLONG)150 * 10000;
1595f7932ba2SAmine Khaldi     pTpSetTimer(timer1, &when, 0, 200);
1596f7932ba2SAmine Khaldi 
1597f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphore, 1000);
159888a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1599f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphore, 1000);
160088a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1601f7932ba2SAmine Khaldi     ok(info1.ticks != 0 && info2.ticks != 0, "expected that ticks are nonzero\n");
1602f7932ba2SAmine Khaldi     merged = info2.ticks >= info1.ticks - 50 && info2.ticks <= info1.ticks + 50;
1603f7932ba2SAmine Khaldi     ok(merged || broken(!merged) /* Win 10 */, "expected that timers are merged\n");
1604f7932ba2SAmine Khaldi 
1605f7932ba2SAmine Khaldi     /* on Windows the timers also get merged in this case */
1606f7932ba2SAmine Khaldi     info1.ticks = 0;
1607f7932ba2SAmine Khaldi     info2.ticks = 0;
1608f7932ba2SAmine Khaldi 
1609f7932ba2SAmine Khaldi     NtQuerySystemTime( &when );
1610f7932ba2SAmine Khaldi     when.QuadPart += (ULONGLONG)100 * 10000;
1611f7932ba2SAmine Khaldi     pTpSetTimer(timer1, &when, 0, 200);
1612f7932ba2SAmine Khaldi     Sleep(50);
1613f7932ba2SAmine Khaldi     when.QuadPart += (ULONGLONG)150 * 10000;
1614f7932ba2SAmine Khaldi     pTpSetTimer(timer2, &when, 0, 0);
1615f7932ba2SAmine Khaldi 
1616f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphore, 1000);
161788a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1618f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphore, 1000);
161988a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1620f7932ba2SAmine Khaldi     ok(info1.ticks != 0 && info2.ticks != 0, "expected that ticks are nonzero\n");
1621f7932ba2SAmine Khaldi     merged = info2.ticks >= info1.ticks - 50 && info2.ticks <= info1.ticks + 50;
1622f7932ba2SAmine Khaldi     todo_wine
1623f7932ba2SAmine Khaldi     ok(merged || broken(!merged) /* Win 10 */, "expected that timers are merged\n");
1624f7932ba2SAmine Khaldi 
1625f7932ba2SAmine Khaldi     /* cleanup */
1626f7932ba2SAmine Khaldi     pTpReleaseTimer(timer1);
1627f7932ba2SAmine Khaldi     pTpReleaseTimer(timer2);
1628f7932ba2SAmine Khaldi     pTpReleasePool(pool);
1629f7932ba2SAmine Khaldi     CloseHandle(semaphore);
1630f7932ba2SAmine Khaldi }
1631f7932ba2SAmine Khaldi 
1632f7932ba2SAmine Khaldi struct wait_info
1633f7932ba2SAmine Khaldi {
1634f7932ba2SAmine Khaldi     HANDLE semaphore;
1635f7932ba2SAmine Khaldi     LONG userdata;
1636f7932ba2SAmine Khaldi };
1637f7932ba2SAmine Khaldi 
wait_cb(TP_CALLBACK_INSTANCE * instance,void * userdata,TP_WAIT * wait,TP_WAIT_RESULT result)1638f7932ba2SAmine Khaldi static void CALLBACK wait_cb(TP_CALLBACK_INSTANCE *instance, void *userdata,
1639f7932ba2SAmine Khaldi                              TP_WAIT *wait, TP_WAIT_RESULT result)
1640f7932ba2SAmine Khaldi {
1641f7932ba2SAmine Khaldi     struct wait_info *info = userdata;
1642f7932ba2SAmine Khaldi     if (result == WAIT_OBJECT_0)
1643f7932ba2SAmine Khaldi         InterlockedIncrement(&info->userdata);
1644f7932ba2SAmine Khaldi     else if (result == WAIT_TIMEOUT)
1645f7932ba2SAmine Khaldi         InterlockedExchangeAdd(&info->userdata, 0x10000);
1646f7932ba2SAmine Khaldi     else
164788a63011SJustin Miller         ok(0, "unexpected result %lu\n", result);
1648f7932ba2SAmine Khaldi     ReleaseSemaphore(info->semaphore, 1, NULL);
1649f7932ba2SAmine Khaldi }
1650f7932ba2SAmine Khaldi 
test_tp_wait(void)1651f7932ba2SAmine Khaldi static void test_tp_wait(void)
1652f7932ba2SAmine Khaldi {
1653f7932ba2SAmine Khaldi     TP_CALLBACK_ENVIRON environment;
1654f7932ba2SAmine Khaldi     TP_WAIT *wait1, *wait2;
1655f7932ba2SAmine Khaldi     struct wait_info info;
1656f7932ba2SAmine Khaldi     HANDLE semaphores[2];
1657f7932ba2SAmine Khaldi     LARGE_INTEGER when;
1658f7932ba2SAmine Khaldi     NTSTATUS status;
1659f7932ba2SAmine Khaldi     TP_POOL *pool;
1660f7932ba2SAmine Khaldi     DWORD result;
1661f7932ba2SAmine Khaldi 
1662f7932ba2SAmine Khaldi     semaphores[0] = CreateSemaphoreW(NULL, 0, 2, NULL);
1663f7932ba2SAmine Khaldi     ok(semaphores[0] != NULL, "failed to create semaphore\n");
1664f7932ba2SAmine Khaldi     semaphores[1] = CreateSemaphoreW(NULL, 0, 1, NULL);
1665f7932ba2SAmine Khaldi     ok(semaphores[1] != NULL, "failed to create semaphore\n");
1666f7932ba2SAmine Khaldi     info.semaphore = semaphores[0];
1667f7932ba2SAmine Khaldi 
1668f7932ba2SAmine Khaldi     /* allocate new threadpool */
1669f7932ba2SAmine Khaldi     pool = NULL;
1670f7932ba2SAmine Khaldi     status = pTpAllocPool(&pool, NULL);
167188a63011SJustin Miller     ok(!status, "TpAllocPool failed with status %lx\n", status);
1672f7932ba2SAmine Khaldi     ok(pool != NULL, "expected pool != NULL\n");
1673f7932ba2SAmine Khaldi 
1674f7932ba2SAmine Khaldi     /* allocate new wait items */
1675f7932ba2SAmine Khaldi     memset(&environment, 0, sizeof(environment));
1676f7932ba2SAmine Khaldi     environment.Version = 1;
1677f7932ba2SAmine Khaldi     environment.Pool = pool;
1678f7932ba2SAmine Khaldi 
1679f7932ba2SAmine Khaldi     wait1 = NULL;
1680f7932ba2SAmine Khaldi     status = pTpAllocWait(&wait1, wait_cb, &info, &environment);
168188a63011SJustin Miller     ok(!status, "TpAllocWait failed with status %lx\n", status);
1682f7932ba2SAmine Khaldi     ok(wait1 != NULL, "expected wait1 != NULL\n");
1683f7932ba2SAmine Khaldi 
1684f7932ba2SAmine Khaldi     wait2 = NULL;
1685f7932ba2SAmine Khaldi     status = pTpAllocWait(&wait2, wait_cb, &info, &environment);
168688a63011SJustin Miller     ok(!status, "TpAllocWait failed with status %lx\n", status);
1687f7932ba2SAmine Khaldi     ok(wait2 != NULL, "expected wait2 != NULL\n");
1688f7932ba2SAmine Khaldi 
1689f7932ba2SAmine Khaldi     /* infinite timeout, signal the semaphore immediately */
1690f7932ba2SAmine Khaldi     info.userdata = 0;
1691f7932ba2SAmine Khaldi     pTpSetWait(wait1, semaphores[1], NULL);
1692f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[1], 1, NULL);
1693f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
169488a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
169588a63011SJustin Miller     ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
1696f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[1], 0);
169788a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1698f7932ba2SAmine Khaldi 
1699f7932ba2SAmine Khaldi     /* relative timeout, no event */
1700f7932ba2SAmine Khaldi     info.userdata = 0;
1701f7932ba2SAmine Khaldi     when.QuadPart = (ULONGLONG)200 * -10000;
1702f7932ba2SAmine Khaldi     pTpSetWait(wait1, semaphores[1], &when);
1703f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
170488a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
170588a63011SJustin Miller     ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
1706f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 200);
170788a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
170888a63011SJustin Miller     ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
1709f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[1], 0);
171088a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1711f7932ba2SAmine Khaldi 
1712f7932ba2SAmine Khaldi     /* repeat test with call to TpWaitForWait(..., TRUE) */
1713f7932ba2SAmine Khaldi     info.userdata = 0;
1714f7932ba2SAmine Khaldi     when.QuadPart = (ULONGLONG)200 * -10000;
1715f7932ba2SAmine Khaldi     pTpSetWait(wait1, semaphores[1], &when);
1716f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
171788a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1718f7932ba2SAmine Khaldi     pTpWaitForWait(wait1, TRUE);
171988a63011SJustin Miller     ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
1720f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 200);
1721f7932ba2SAmine Khaldi     ok(result == WAIT_OBJECT_0 || broken(result == WAIT_TIMEOUT) /* Win 8 */,
172288a63011SJustin Miller        "WaitForSingleObject returned %lu\n", result);
1723f7932ba2SAmine Khaldi     if (result == WAIT_OBJECT_0)
172488a63011SJustin Miller         ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
1725f7932ba2SAmine Khaldi     else
172688a63011SJustin Miller         ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
1727f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[1], 0);
172888a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1729f7932ba2SAmine Khaldi 
1730f7932ba2SAmine Khaldi     /* relative timeout, with event */
1731f7932ba2SAmine Khaldi     info.userdata = 0;
1732f7932ba2SAmine Khaldi     when.QuadPart = (ULONGLONG)200 * -10000;
1733f7932ba2SAmine Khaldi     pTpSetWait(wait1, semaphores[1], &when);
1734f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
173588a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
173688a63011SJustin Miller     ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
1737f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[1], 1, NULL);
1738f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
173988a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
174088a63011SJustin Miller     ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
1741f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[1], 0);
174288a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1743f7932ba2SAmine Khaldi 
1744f7932ba2SAmine Khaldi     /* repeat test with call to TpWaitForWait(..., TRUE) */
1745f7932ba2SAmine Khaldi     info.userdata = 0;
1746f7932ba2SAmine Khaldi     when.QuadPart = (ULONGLONG)200 * -10000;
1747f7932ba2SAmine Khaldi     pTpSetWait(wait1, semaphores[1], &when);
1748f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
174988a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1750f7932ba2SAmine Khaldi     pTpWaitForWait(wait1, TRUE);
175188a63011SJustin Miller     ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
1752f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[1], 1, NULL);
1753f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
1754f7932ba2SAmine Khaldi     ok(result == WAIT_OBJECT_0 || broken(result == WAIT_TIMEOUT) /* Win 8 */,
175588a63011SJustin Miller        "WaitForSingleObject returned %lu\n", result);
1756f7932ba2SAmine Khaldi     if (result == WAIT_OBJECT_0)
1757f7932ba2SAmine Khaldi     {
175888a63011SJustin Miller         ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
1759f7932ba2SAmine Khaldi         result = WaitForSingleObject(semaphores[1], 0);
176088a63011SJustin Miller         ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1761f7932ba2SAmine Khaldi     }
1762f7932ba2SAmine Khaldi     else
1763f7932ba2SAmine Khaldi     {
176488a63011SJustin Miller         ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
1765f7932ba2SAmine Khaldi         result = WaitForSingleObject(semaphores[1], 0);
176688a63011SJustin Miller         ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1767f7932ba2SAmine Khaldi     }
1768f7932ba2SAmine Khaldi 
1769f7932ba2SAmine Khaldi     /* absolute timeout, no event */
1770f7932ba2SAmine Khaldi     info.userdata = 0;
1771f7932ba2SAmine Khaldi     NtQuerySystemTime( &when );
1772f7932ba2SAmine Khaldi     when.QuadPart += (ULONGLONG)200 * 10000;
1773f7932ba2SAmine Khaldi     pTpSetWait(wait1, semaphores[1], &when);
1774f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
177588a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
177688a63011SJustin Miller     ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
1777f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 200);
177888a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
177988a63011SJustin Miller     ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
1780f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[1], 0);
178188a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1782f7932ba2SAmine Khaldi 
1783f7932ba2SAmine Khaldi     /* absolute timeout, with event */
1784f7932ba2SAmine Khaldi     info.userdata = 0;
1785f7932ba2SAmine Khaldi     NtQuerySystemTime( &when );
1786f7932ba2SAmine Khaldi     when.QuadPart += (ULONGLONG)200 * 10000;
1787f7932ba2SAmine Khaldi     pTpSetWait(wait1, semaphores[1], &when);
1788f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
178988a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
179088a63011SJustin Miller     ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
1791f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[1], 1, NULL);
1792f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
179388a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
179488a63011SJustin Miller     ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
1795f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[1], 0);
179688a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1797f7932ba2SAmine Khaldi 
1798f7932ba2SAmine Khaldi     /* test timeout of zero */
1799f7932ba2SAmine Khaldi     info.userdata = 0;
1800f7932ba2SAmine Khaldi     when.QuadPart = 0;
1801f7932ba2SAmine Khaldi     pTpSetWait(wait1, semaphores[1], &when);
1802f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
180388a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
180488a63011SJustin Miller     ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
1805f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[1], 0);
180688a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1807f7932ba2SAmine Khaldi 
1808f7932ba2SAmine Khaldi     /* cancel a pending wait */
1809f7932ba2SAmine Khaldi     info.userdata = 0;
1810f7932ba2SAmine Khaldi     when.QuadPart = (ULONGLONG)250 * -10000;
1811f7932ba2SAmine Khaldi     pTpSetWait(wait1, semaphores[1], &when);
1812f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
181388a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1814f7932ba2SAmine Khaldi     pTpSetWait(wait1, NULL, (void *)0xdeadbeef);
1815f7932ba2SAmine Khaldi     Sleep(50);
1816f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[1], 1, NULL);
1817f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
181888a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
181988a63011SJustin Miller     ok(info.userdata == 0, "expected info.userdata = 0, got %lu\n", info.userdata);
1820f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[1], 0);
182188a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1822f7932ba2SAmine Khaldi 
1823f7932ba2SAmine Khaldi     /* test with INVALID_HANDLE_VALUE */
1824f7932ba2SAmine Khaldi     info.userdata = 0;
1825f7932ba2SAmine Khaldi     when.QuadPart = 0;
1826f7932ba2SAmine Khaldi     pTpSetWait(wait1, INVALID_HANDLE_VALUE, &when);
1827f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
182888a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
182988a63011SJustin Miller     ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
1830f7932ba2SAmine Khaldi 
1831f7932ba2SAmine Khaldi     /* cancel a pending wait with INVALID_HANDLE_VALUE */
1832f7932ba2SAmine Khaldi     info.userdata = 0;
1833f7932ba2SAmine Khaldi     when.QuadPart = (ULONGLONG)250 * -10000;
1834f7932ba2SAmine Khaldi     pTpSetWait(wait1, semaphores[1], &when);
1835f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
183688a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1837f7932ba2SAmine Khaldi     when.QuadPart = 0;
1838f7932ba2SAmine Khaldi     pTpSetWait(wait1, INVALID_HANDLE_VALUE, &when);
1839f7932ba2SAmine Khaldi     Sleep(50);
1840f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[1], 1, NULL);
1841f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
184288a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
184388a63011SJustin Miller     ok(info.userdata == 0x10000, "expected info.userdata = 0x10000, got %lu\n", info.userdata);
1844f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[1], 0);
184588a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1846f7932ba2SAmine Khaldi 
1847f7932ba2SAmine Khaldi     CloseHandle(semaphores[1]);
1848f7932ba2SAmine Khaldi     semaphores[1] = CreateSemaphoreW(NULL, 0, 2, NULL);
1849f7932ba2SAmine Khaldi     ok(semaphores[1] != NULL, "failed to create semaphore\n");
1850f7932ba2SAmine Khaldi 
1851f7932ba2SAmine Khaldi     /* add two wait objects with the same semaphore */
1852f7932ba2SAmine Khaldi     info.userdata = 0;
1853f7932ba2SAmine Khaldi     pTpSetWait(wait1, semaphores[1], NULL);
1854f7932ba2SAmine Khaldi     pTpSetWait(wait2, semaphores[1], NULL);
1855f7932ba2SAmine Khaldi     Sleep(50);
1856f7932ba2SAmine Khaldi     ReleaseSemaphore(semaphores[1], 1, NULL);
1857f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
185888a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1859f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
186088a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
186188a63011SJustin Miller     ok(info.userdata == 1, "expected info.userdata = 1, got %lu\n", info.userdata);
1862f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[1], 0);
186388a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1864f7932ba2SAmine Khaldi 
1865f7932ba2SAmine Khaldi     /* repeat test above with release count 2 */
1866f7932ba2SAmine Khaldi     info.userdata = 0;
1867f7932ba2SAmine Khaldi     pTpSetWait(wait1, semaphores[1], NULL);
1868f7932ba2SAmine Khaldi     pTpSetWait(wait2, semaphores[1], NULL);
1869f7932ba2SAmine Khaldi     Sleep(50);
1870f7932ba2SAmine Khaldi     result = ReleaseSemaphore(semaphores[1], 2, NULL);
1871f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
187288a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1873f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[0], 100);
187488a63011SJustin Miller     ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
187588a63011SJustin Miller     ok(info.userdata == 2, "expected info.userdata = 2, got %lu\n", info.userdata);
1876f7932ba2SAmine Khaldi     result = WaitForSingleObject(semaphores[1], 0);
187788a63011SJustin Miller     ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", result);
1878f7932ba2SAmine Khaldi 
1879f7932ba2SAmine Khaldi     /* cleanup */
1880f7932ba2SAmine Khaldi     pTpReleaseWait(wait1);
1881f7932ba2SAmine Khaldi     pTpReleaseWait(wait2);
1882f7932ba2SAmine Khaldi     pTpReleasePool(pool);
1883f7932ba2SAmine Khaldi     CloseHandle(semaphores[0]);
1884f7932ba2SAmine Khaldi     CloseHandle(semaphores[1]);
1885f7932ba2SAmine Khaldi }
1886f7932ba2SAmine Khaldi 
1887f7932ba2SAmine Khaldi static struct
1888f7932ba2SAmine Khaldi {
1889f7932ba2SAmine Khaldi     HANDLE semaphore;
1890f7932ba2SAmine Khaldi     DWORD result;
1891f7932ba2SAmine Khaldi } multi_wait_info;
1892f7932ba2SAmine Khaldi 
multi_wait_cb(TP_CALLBACK_INSTANCE * instance,void * userdata,TP_WAIT * wait,TP_WAIT_RESULT result)1893f7932ba2SAmine Khaldi static void CALLBACK multi_wait_cb(TP_CALLBACK_INSTANCE *instance, void *userdata, TP_WAIT *wait, TP_WAIT_RESULT result)
1894f7932ba2SAmine Khaldi {
1895f7932ba2SAmine Khaldi     DWORD index = (DWORD)(DWORD_PTR)userdata;
1896f7932ba2SAmine Khaldi 
1897f7932ba2SAmine Khaldi     if (result == WAIT_OBJECT_0)
1898f7932ba2SAmine Khaldi         multi_wait_info.result = index;
1899f7932ba2SAmine Khaldi     else if (result == WAIT_TIMEOUT)
1900f7932ba2SAmine Khaldi         multi_wait_info.result = 0x10000 | index;
1901f7932ba2SAmine Khaldi     else
190288a63011SJustin Miller         ok(0, "unexpected result %lu\n", result);
1903f7932ba2SAmine Khaldi     ReleaseSemaphore(multi_wait_info.semaphore, 1, NULL);
1904f7932ba2SAmine Khaldi }
1905f7932ba2SAmine Khaldi 
test_tp_multi_wait(void)1906f7932ba2SAmine Khaldi static void test_tp_multi_wait(void)
1907f7932ba2SAmine Khaldi {
190888a63011SJustin Miller     TP_POOL_STACK_INFORMATION stack_info;
1909f7932ba2SAmine Khaldi     TP_CALLBACK_ENVIRON environment;
1910f7932ba2SAmine Khaldi     HANDLE semaphores[512];
1911f7932ba2SAmine Khaldi     TP_WAIT *waits[512];
1912f7932ba2SAmine Khaldi     LARGE_INTEGER when;
1913f7932ba2SAmine Khaldi     HANDLE semaphore;
1914f7932ba2SAmine Khaldi     NTSTATUS status;
1915f7932ba2SAmine Khaldi     TP_POOL *pool;
1916f7932ba2SAmine Khaldi     DWORD result;
1917f7932ba2SAmine Khaldi     int i;
1918f7932ba2SAmine Khaldi 
1919f7932ba2SAmine Khaldi     semaphore = CreateSemaphoreW(NULL, 0, 512, NULL);
1920f7932ba2SAmine Khaldi     ok(semaphore != NULL, "failed to create semaphore\n");
1921f7932ba2SAmine Khaldi     multi_wait_info.semaphore = semaphore;
1922f7932ba2SAmine Khaldi 
1923f7932ba2SAmine Khaldi     /* allocate new threadpool */
1924f7932ba2SAmine Khaldi     pool = NULL;
1925f7932ba2SAmine Khaldi     status = pTpAllocPool(&pool, NULL);
192688a63011SJustin Miller     ok(!status, "TpAllocPool failed with status %lx\n", status);
1927f7932ba2SAmine Khaldi     ok(pool != NULL, "expected pool != NULL\n");
192888a63011SJustin Miller     /* many threads -> use the smallest stack possible */
192988a63011SJustin Miller     stack_info.StackReserve = 256 * 1024;
193088a63011SJustin Miller     stack_info.StackCommit = 4 * 1024;
193188a63011SJustin Miller     status = pTpSetPoolStackInformation(pool, &stack_info);
193288a63011SJustin Miller     ok(!status, "TpQueryPoolStackInformation failed: %lx\n", status);
1933f7932ba2SAmine Khaldi 
1934f7932ba2SAmine Khaldi     memset(&environment, 0, sizeof(environment));
1935f7932ba2SAmine Khaldi     environment.Version = 1;
1936f7932ba2SAmine Khaldi     environment.Pool = pool;
1937f7932ba2SAmine Khaldi 
1938f7932ba2SAmine Khaldi     /* create semaphores and corresponding wait objects */
193988a63011SJustin Miller     for (i = 0; i < ARRAY_SIZE(semaphores); i++)
1940f7932ba2SAmine Khaldi     {
1941f7932ba2SAmine Khaldi         semaphores[i] = CreateSemaphoreW(NULL, 0, 1, NULL);
1942f7932ba2SAmine Khaldi         ok(semaphores[i] != NULL, "failed to create semaphore %i\n", i);
1943f7932ba2SAmine Khaldi 
1944f7932ba2SAmine Khaldi         waits[i] = NULL;
1945f7932ba2SAmine Khaldi         status = pTpAllocWait(&waits[i], multi_wait_cb, (void *)(DWORD_PTR)i, &environment);
194688a63011SJustin Miller         ok(!status, "TpAllocWait failed with status %lx\n", status);
1947f7932ba2SAmine Khaldi         ok(waits[i] != NULL, "expected waits[%d] != NULL\n", i);
1948f7932ba2SAmine Khaldi 
1949f7932ba2SAmine Khaldi         pTpSetWait(waits[i], semaphores[i], NULL);
1950f7932ba2SAmine Khaldi     }
1951f7932ba2SAmine Khaldi 
1952f7932ba2SAmine Khaldi     /* release all semaphores and wait for callback */
195388a63011SJustin Miller     for (i = 0; i < ARRAY_SIZE(semaphores); i++)
1954f7932ba2SAmine Khaldi     {
1955f7932ba2SAmine Khaldi         multi_wait_info.result = 0;
1956f7932ba2SAmine Khaldi         ReleaseSemaphore(semaphores[i], 1, NULL);
1957f7932ba2SAmine Khaldi 
195888a63011SJustin Miller         result = WaitForSingleObject(semaphore, 2000);
195988a63011SJustin Miller         ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
196088a63011SJustin Miller         ok(multi_wait_info.result == i, "expected result %d, got %lu\n", i, multi_wait_info.result);
1961f7932ba2SAmine Khaldi 
1962f7932ba2SAmine Khaldi         pTpSetWait(waits[i], semaphores[i], NULL);
1963f7932ba2SAmine Khaldi     }
1964f7932ba2SAmine Khaldi 
1965f7932ba2SAmine Khaldi     /* repeat the same test in reverse order */
196688a63011SJustin Miller     for (i = ARRAY_SIZE(semaphores) - 1; i >= 0; i--)
1967f7932ba2SAmine Khaldi     {
1968f7932ba2SAmine Khaldi         multi_wait_info.result = 0;
1969f7932ba2SAmine Khaldi         ReleaseSemaphore(semaphores[i], 1, NULL);
1970f7932ba2SAmine Khaldi 
197188a63011SJustin Miller         result = WaitForSingleObject(semaphore, 2000);
197288a63011SJustin Miller         ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
197388a63011SJustin Miller         ok(multi_wait_info.result == i, "expected result %d, got %lu\n", i, multi_wait_info.result);
1974f7932ba2SAmine Khaldi 
1975f7932ba2SAmine Khaldi         pTpSetWait(waits[i], semaphores[i], NULL);
1976f7932ba2SAmine Khaldi     }
1977f7932ba2SAmine Khaldi 
1978f7932ba2SAmine Khaldi     /* test timeout of wait objects */
1979f7932ba2SAmine Khaldi     multi_wait_info.result = 0;
198088a63011SJustin Miller     for (i = 0; i < ARRAY_SIZE(semaphores); i++)
1981f7932ba2SAmine Khaldi     {
1982f7932ba2SAmine Khaldi         when.QuadPart = (ULONGLONG)50 * -10000;
1983f7932ba2SAmine Khaldi         pTpSetWait(waits[i], semaphores[i], &when);
1984f7932ba2SAmine Khaldi     }
1985f7932ba2SAmine Khaldi 
198688a63011SJustin Miller     for (i = 0; i < ARRAY_SIZE(semaphores); i++)
1987f7932ba2SAmine Khaldi     {
198888a63011SJustin Miller         result = WaitForSingleObject(semaphore, 2000);
198988a63011SJustin Miller         ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
1990f7932ba2SAmine Khaldi     }
1991f7932ba2SAmine Khaldi 
1992f7932ba2SAmine Khaldi     ok(multi_wait_info.result >> 16, "expected multi_wait_info.result >> 16 != 0\n");
1993f7932ba2SAmine Khaldi 
1994f7932ba2SAmine Khaldi     /* destroy the wait objects and semaphores while waiting */
199588a63011SJustin Miller     for (i = 0; i < ARRAY_SIZE(semaphores); i++)
1996f7932ba2SAmine Khaldi     {
1997f7932ba2SAmine Khaldi         pTpSetWait(waits[i], semaphores[i], NULL);
1998f7932ba2SAmine Khaldi     }
1999f7932ba2SAmine Khaldi 
2000f7932ba2SAmine Khaldi     Sleep(50);
2001f7932ba2SAmine Khaldi 
200288a63011SJustin Miller     for (i = 0; i < ARRAY_SIZE(semaphores); i++)
2003f7932ba2SAmine Khaldi     {
2004f7932ba2SAmine Khaldi         pTpReleaseWait(waits[i]);
2005f7932ba2SAmine Khaldi         NtClose(semaphores[i]);
2006f7932ba2SAmine Khaldi     }
2007f7932ba2SAmine Khaldi 
2008f7932ba2SAmine Khaldi     pTpReleasePool(pool);
2009f7932ba2SAmine Khaldi     CloseHandle(semaphore);
2010f7932ba2SAmine Khaldi }
2011f7932ba2SAmine Khaldi 
201288a63011SJustin Miller struct io_cb_ctx
201388a63011SJustin Miller {
201488a63011SJustin Miller     unsigned int count;
201588a63011SJustin Miller     void *ovl;
201688a63011SJustin Miller     NTSTATUS ret;
201788a63011SJustin Miller     ULONG_PTR length;
201888a63011SJustin Miller     TP_IO *io;
201988a63011SJustin Miller };
202088a63011SJustin Miller 
io_cb(TP_CALLBACK_INSTANCE * instance,void * userdata,void * cvalue,IO_STATUS_BLOCK * iosb,TP_IO * io)202188a63011SJustin Miller static void CALLBACK io_cb(TP_CALLBACK_INSTANCE *instance, void *userdata,
202288a63011SJustin Miller         void *cvalue, IO_STATUS_BLOCK *iosb, TP_IO *io)
202388a63011SJustin Miller {
202488a63011SJustin Miller     struct io_cb_ctx *ctx = userdata;
202588a63011SJustin Miller     ++ctx->count;
202688a63011SJustin Miller     ctx->ovl = cvalue;
202788a63011SJustin Miller     ctx->ret = iosb->Status;
202888a63011SJustin Miller     ctx->length = iosb->Information;
202988a63011SJustin Miller     ctx->io = io;
203088a63011SJustin Miller }
203188a63011SJustin Miller 
io_wait_thread(void * arg)203288a63011SJustin Miller static DWORD WINAPI io_wait_thread(void *arg)
203388a63011SJustin Miller {
203488a63011SJustin Miller     TP_IO *io = arg;
203588a63011SJustin Miller     pTpWaitForIoCompletion(io, FALSE);
203688a63011SJustin Miller     return 0;
203788a63011SJustin Miller }
203888a63011SJustin Miller 
test_tp_io(void)203988a63011SJustin Miller static void test_tp_io(void)
204088a63011SJustin Miller {
204188a63011SJustin Miller     TP_CALLBACK_ENVIRON environment = {.Version = 1};
2042*0bf42067SJustin Miller #ifdef __REACTOS__
2043*0bf42067SJustin Miller     OVERLAPPED ovl = {0}, ovl2 = {0};
2044*0bf42067SJustin Miller #else
204588a63011SJustin Miller     OVERLAPPED ovl = {}, ovl2 = {};
2046*0bf42067SJustin Miller #endif
204788a63011SJustin Miller     HANDLE client, server, thread;
204888a63011SJustin Miller     struct io_cb_ctx userdata;
204988a63011SJustin Miller     char in[1], in2[1];
205088a63011SJustin Miller     const char out[1];
205188a63011SJustin Miller     NTSTATUS status;
205288a63011SJustin Miller     DWORD ret_size;
205388a63011SJustin Miller     TP_POOL *pool;
205488a63011SJustin Miller     TP_IO *io;
205588a63011SJustin Miller     BOOL ret;
205688a63011SJustin Miller 
205788a63011SJustin Miller     ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
205888a63011SJustin Miller 
205988a63011SJustin Miller     status = pTpAllocPool(&pool, NULL);
206088a63011SJustin Miller     ok(!status, "failed to allocate pool, status %#lx\n", status);
206188a63011SJustin Miller 
206288a63011SJustin Miller     server = CreateNamedPipeA("\\\\.\\pipe\\wine_tp_test",
206388a63011SJustin Miller             PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0, 1, 1024, 1024, 0, NULL);
206488a63011SJustin Miller     ok(server != INVALID_HANDLE_VALUE, "Failed to create server pipe, error %lu.\n", GetLastError());
206588a63011SJustin Miller     client = CreateFileA("\\\\.\\pipe\\wine_tp_test", GENERIC_READ | GENERIC_WRITE,
206688a63011SJustin Miller             0, NULL, OPEN_EXISTING, 0, 0);
206788a63011SJustin Miller     ok(client != INVALID_HANDLE_VALUE, "Failed to create client pipe, error %lu.\n", GetLastError());
206888a63011SJustin Miller 
206988a63011SJustin Miller     environment.Pool = pool;
207088a63011SJustin Miller     io = NULL;
207188a63011SJustin Miller     status = pTpAllocIoCompletion(&io, server, io_cb, &userdata, &environment);
207288a63011SJustin Miller     ok(!status, "got %#lx\n", status);
207388a63011SJustin Miller     ok(!!io, "expected non-NULL TP_IO\n");
207488a63011SJustin Miller 
207588a63011SJustin Miller     pTpWaitForIoCompletion(io, FALSE);
207688a63011SJustin Miller 
207788a63011SJustin Miller     userdata.count = 0;
207888a63011SJustin Miller     pTpStartAsyncIoOperation(io);
207988a63011SJustin Miller 
208088a63011SJustin Miller     thread = CreateThread(NULL, 0, io_wait_thread, io, 0, NULL);
208188a63011SJustin Miller     ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "TpWaitForIoCompletion() should not return\n");
208288a63011SJustin Miller 
208388a63011SJustin Miller     ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
208488a63011SJustin Miller     ok(!ret, "wrong ret %d\n", ret);
208588a63011SJustin Miller     ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError());
208688a63011SJustin Miller 
208788a63011SJustin Miller     ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
208888a63011SJustin Miller     ok(ret, "WriteFile() failed, error %lu\n", GetLastError());
208988a63011SJustin Miller 
209088a63011SJustin Miller     pTpWaitForIoCompletion(io, FALSE);
209188a63011SJustin Miller     ok(userdata.count == 1, "callback ran %u times\n", userdata.count);
209288a63011SJustin Miller     ok(userdata.ovl == &ovl, "expected %p, got %p\n", &ovl, userdata.ovl);
209388a63011SJustin Miller     ok(userdata.ret == STATUS_SUCCESS, "got status %#lx\n", userdata.ret);
209488a63011SJustin Miller     ok(userdata.length == 1, "got length %Iu\n", userdata.length);
209588a63011SJustin Miller     ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io);
209688a63011SJustin Miller 
209788a63011SJustin Miller     ok(!WaitForSingleObject(thread, 1000), "wait timed out\n");
209888a63011SJustin Miller     CloseHandle(thread);
209988a63011SJustin Miller 
210088a63011SJustin Miller     userdata.count = 0;
210188a63011SJustin Miller     pTpStartAsyncIoOperation(io);
210288a63011SJustin Miller     pTpStartAsyncIoOperation(io);
210388a63011SJustin Miller 
210488a63011SJustin Miller     ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
210588a63011SJustin Miller     ok(!ret, "wrong ret %d\n", ret);
210688a63011SJustin Miller     ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError());
210788a63011SJustin Miller     ret = ReadFile(server, in2, sizeof(in2), NULL, &ovl2);
210888a63011SJustin Miller     ok(!ret, "wrong ret %d\n", ret);
210988a63011SJustin Miller     ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError());
211088a63011SJustin Miller 
211188a63011SJustin Miller     ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
211288a63011SJustin Miller     ok(ret, "WriteFile() failed, error %lu\n", GetLastError());
211388a63011SJustin Miller     ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
211488a63011SJustin Miller     ok(ret, "WriteFile() failed, error %lu\n", GetLastError());
211588a63011SJustin Miller 
211688a63011SJustin Miller     pTpWaitForIoCompletion(io, FALSE);
211788a63011SJustin Miller     ok(userdata.count == 2, "callback ran %u times\n", userdata.count);
211888a63011SJustin Miller     ok(userdata.ret == STATUS_SUCCESS, "got status %#lx\n", userdata.ret);
211988a63011SJustin Miller     ok(userdata.length == 1, "got length %Iu\n", userdata.length);
212088a63011SJustin Miller     ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io);
212188a63011SJustin Miller 
212288a63011SJustin Miller     /* The documentation is a bit unclear about passing TRUE to
212388a63011SJustin Miller      * WaitForThreadpoolIoCallbacks()—"pending I/O requests are not canceled"
212488a63011SJustin Miller      * [as with CancelIoEx()], but pending threadpool callbacks are, even those
212588a63011SJustin Miller      * which have not yet reached the completion port [as with
212688a63011SJustin Miller      * TpCancelAsyncIoOperation()]. */
212788a63011SJustin Miller     userdata.count = 0;
212888a63011SJustin Miller     pTpStartAsyncIoOperation(io);
212988a63011SJustin Miller 
213088a63011SJustin Miller     pTpWaitForIoCompletion(io, TRUE);
213188a63011SJustin Miller     ok(!userdata.count, "callback ran %u times\n", userdata.count);
213288a63011SJustin Miller 
213388a63011SJustin Miller     pTpStartAsyncIoOperation(io);
213488a63011SJustin Miller 
213588a63011SJustin Miller     ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
213688a63011SJustin Miller     ok(ret, "WriteFile() failed, error %lu\n", GetLastError());
213788a63011SJustin Miller 
213888a63011SJustin Miller     ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
213988a63011SJustin Miller     ok(ret, "wrong ret %d\n", ret);
214088a63011SJustin Miller 
214188a63011SJustin Miller     pTpWaitForIoCompletion(io, FALSE);
214288a63011SJustin Miller     ok(userdata.count == 1, "callback ran %u times\n", userdata.count);
214388a63011SJustin Miller     ok(userdata.ovl == &ovl, "expected %p, got %p\n", &ovl, userdata.ovl);
214488a63011SJustin Miller     ok(userdata.ret == STATUS_SUCCESS, "got status %#lx\n", userdata.ret);
214588a63011SJustin Miller     ok(userdata.length == 1, "got length %Iu\n", userdata.length);
214688a63011SJustin Miller     ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io);
214788a63011SJustin Miller 
214888a63011SJustin Miller     userdata.count = 0;
214988a63011SJustin Miller     pTpStartAsyncIoOperation(io);
215088a63011SJustin Miller 
215188a63011SJustin Miller     ret = ReadFile(server, NULL, 1, NULL, &ovl);
215288a63011SJustin Miller     ok(!ret, "wrong ret %d\n", ret);
215388a63011SJustin Miller     ok(GetLastError() == ERROR_NOACCESS, "wrong error %lu\n", GetLastError());
215488a63011SJustin Miller 
215588a63011SJustin Miller     pTpCancelAsyncIoOperation(io);
215688a63011SJustin Miller     pTpWaitForIoCompletion(io, FALSE);
215788a63011SJustin Miller     ok(!userdata.count, "callback ran %u times\n", userdata.count);
215888a63011SJustin Miller 
215988a63011SJustin Miller     userdata.count = 0;
216088a63011SJustin Miller     pTpStartAsyncIoOperation(io);
216188a63011SJustin Miller 
216288a63011SJustin Miller     ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
216388a63011SJustin Miller     ok(!ret, "wrong ret %d\n", ret);
216488a63011SJustin Miller     ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError());
216588a63011SJustin Miller     ret = CancelIo(server);
216688a63011SJustin Miller     ok(ret, "CancelIo() failed, error %lu\n", GetLastError());
216788a63011SJustin Miller 
216888a63011SJustin Miller     pTpWaitForIoCompletion(io, FALSE);
216988a63011SJustin Miller     ok(userdata.count == 1, "callback ran %u times\n", userdata.count);
217088a63011SJustin Miller     ok(userdata.ovl == &ovl, "expected %p, got %p\n", &ovl, userdata.ovl);
217188a63011SJustin Miller     ok(userdata.ret == STATUS_CANCELLED, "got status %#lx\n", userdata.ret);
217288a63011SJustin Miller     ok(!userdata.length, "got length %Iu\n", userdata.length);
217388a63011SJustin Miller     ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io);
217488a63011SJustin Miller 
217588a63011SJustin Miller     userdata.count = 0;
217688a63011SJustin Miller     pTpStartAsyncIoOperation(io);
217788a63011SJustin Miller     pTpCancelAsyncIoOperation(io);
217888a63011SJustin Miller     ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
217988a63011SJustin Miller     ok(!ret, "wrong ret %d\n", ret);
218088a63011SJustin Miller     ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
218188a63011SJustin Miller     ok(ret, "WriteFile() failed, error %lu\n", GetLastError());
218288a63011SJustin Miller     ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError());
218388a63011SJustin Miller 
218488a63011SJustin Miller     pTpWaitForIoCompletion(io, FALSE);
218588a63011SJustin Miller     if (0)
218688a63011SJustin Miller     {
218788a63011SJustin Miller         /* Add a sleep to check that callback is not called later. Commented out to
218888a63011SJustin Miller          * save the test time. */
218988a63011SJustin Miller         Sleep(200);
219088a63011SJustin Miller     }
219188a63011SJustin Miller     ok(userdata.count == 0, "callback ran %u times\n", userdata.count);
219288a63011SJustin Miller 
219388a63011SJustin Miller     pTpReleaseIoCompletion(io);
219488a63011SJustin Miller     CloseHandle(server);
219588a63011SJustin Miller 
219688a63011SJustin Miller     /* Test TPIO object destruction. */
219788a63011SJustin Miller     server = CreateNamedPipeA("\\\\.\\pipe\\wine_tp_test",
219888a63011SJustin Miller             PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0, 1, 1024, 1024, 0, NULL);
219988a63011SJustin Miller     ok(server != INVALID_HANDLE_VALUE, "Failed to create server pipe, error %lu.\n", GetLastError());
220088a63011SJustin Miller     io = NULL;
220188a63011SJustin Miller     status = pTpAllocIoCompletion(&io, server, io_cb, &userdata, &environment);
220288a63011SJustin Miller     ok(!status, "got %#lx\n", status);
220388a63011SJustin Miller 
220488a63011SJustin Miller     ret = HeapValidate(GetProcessHeap(), 0, io);
220588a63011SJustin Miller     ok(ret, "Got unexpected ret %#x.\n", ret);
220688a63011SJustin Miller     pTpReleaseIoCompletion(io);
220788a63011SJustin Miller     ret = HeapValidate(GetProcessHeap(), 0, io);
220888a63011SJustin Miller     ok(!ret, "Got unexpected ret %#x.\n", ret);
220988a63011SJustin Miller     CloseHandle(server);
221088a63011SJustin Miller     CloseHandle(client);
221188a63011SJustin Miller 
221288a63011SJustin Miller     server = CreateNamedPipeA("\\\\.\\pipe\\wine_tp_test",
221388a63011SJustin Miller             PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0, 1, 1024, 1024, 0, NULL);
221488a63011SJustin Miller     ok(server != INVALID_HANDLE_VALUE, "Failed to create server pipe, error %lu.\n", GetLastError());
221588a63011SJustin Miller     client = CreateFileA("\\\\.\\pipe\\wine_tp_test", GENERIC_READ | GENERIC_WRITE,
221688a63011SJustin Miller             0, NULL, OPEN_EXISTING, 0, 0);
221788a63011SJustin Miller     ok(client != INVALID_HANDLE_VALUE, "Failed to create client pipe, error %lu.\n", GetLastError());
221888a63011SJustin Miller 
221988a63011SJustin Miller     io = NULL;
222088a63011SJustin Miller     status = pTpAllocIoCompletion(&io, server, io_cb, &userdata, &environment);
222188a63011SJustin Miller     ok(!status, "got %#lx\n", status);
222288a63011SJustin Miller     pTpStartAsyncIoOperation(io);
222388a63011SJustin Miller     pTpWaitForIoCompletion(io, TRUE);
222488a63011SJustin Miller     ret = HeapValidate(GetProcessHeap(), 0, io);
222588a63011SJustin Miller     ok(ret, "Got unexpected ret %#x.\n", ret);
222688a63011SJustin Miller     pTpReleaseIoCompletion(io);
222788a63011SJustin Miller     ret = HeapValidate(GetProcessHeap(), 0, io);
222888a63011SJustin Miller     ok(ret, "Got unexpected ret %#x.\n", ret);
222988a63011SJustin Miller 
223088a63011SJustin Miller     if (0)
223188a63011SJustin Miller     {
223288a63011SJustin Miller         /* Object destruction will wait until one completion arrives (which was started but not cancelled).
223388a63011SJustin Miller          * Commented out to save test time. */
223488a63011SJustin Miller         Sleep(1000);
223588a63011SJustin Miller         ret = HeapValidate(GetProcessHeap(), 0, io);
223688a63011SJustin Miller         ok(ret, "Got unexpected ret %#x.\n", ret);
223788a63011SJustin Miller         ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
223888a63011SJustin Miller         ok(!ret, "wrong ret %d\n", ret);
223988a63011SJustin Miller         ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
224088a63011SJustin Miller         ok(ret, "WriteFile() failed, error %lu\n", GetLastError());
224188a63011SJustin Miller         Sleep(2000);
224288a63011SJustin Miller         ret = HeapValidate(GetProcessHeap(), 0, io);
224388a63011SJustin Miller         ok(!ret, "Got unexpected ret %#x.\n", ret);
224488a63011SJustin Miller     }
224588a63011SJustin Miller 
224688a63011SJustin Miller     CloseHandle(server);
224788a63011SJustin Miller     CloseHandle(ovl.hEvent);
224888a63011SJustin Miller     CloseHandle(client);
224988a63011SJustin Miller     pTpReleasePool(pool);
225088a63011SJustin Miller }
225188a63011SJustin Miller 
kernel32_io_cb(TP_CALLBACK_INSTANCE * instance,void * userdata,void * ovl,ULONG ret,ULONG_PTR length,TP_IO * io)225288a63011SJustin Miller static void CALLBACK kernel32_io_cb(TP_CALLBACK_INSTANCE *instance, void *userdata,
225388a63011SJustin Miller         void *ovl, ULONG ret, ULONG_PTR length, TP_IO *io)
225488a63011SJustin Miller {
225588a63011SJustin Miller     struct io_cb_ctx *ctx = userdata;
225688a63011SJustin Miller     ++ctx->count;
225788a63011SJustin Miller     ctx->ovl = ovl;
225888a63011SJustin Miller     ctx->ret = ret;
225988a63011SJustin Miller     ctx->length = length;
226088a63011SJustin Miller     ctx->io = io;
226188a63011SJustin Miller }
226288a63011SJustin Miller 
test_kernel32_tp_io(void)226388a63011SJustin Miller static void test_kernel32_tp_io(void)
226488a63011SJustin Miller {
226588a63011SJustin Miller     TP_CALLBACK_ENVIRON environment = {.Version = 1};
2266*0bf42067SJustin Miller #ifdef __REACTOS__
2267*0bf42067SJustin Miller     OVERLAPPED ovl = {0}, ovl2 = {0};
2268*0bf42067SJustin Miller #else
226988a63011SJustin Miller     OVERLAPPED ovl = {}, ovl2 = {};
2270*0bf42067SJustin Miller #endif
227188a63011SJustin Miller     HANDLE client, server, thread;
227288a63011SJustin Miller     struct io_cb_ctx userdata;
227388a63011SJustin Miller     char in[1], in2[1];
227488a63011SJustin Miller     const char out[1];
227588a63011SJustin Miller     NTSTATUS status;
227688a63011SJustin Miller     DWORD ret_size;
227788a63011SJustin Miller     TP_POOL *pool;
227888a63011SJustin Miller     TP_IO *io;
227988a63011SJustin Miller     BOOL ret;
228088a63011SJustin Miller 
228188a63011SJustin Miller     ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
228288a63011SJustin Miller 
228388a63011SJustin Miller     status = pTpAllocPool(&pool, NULL);
228488a63011SJustin Miller     ok(!status, "failed to allocate pool, status %#lx\n", status);
228588a63011SJustin Miller 
228688a63011SJustin Miller     server = CreateNamedPipeA("\\\\.\\pipe\\wine_tp_test",
228788a63011SJustin Miller             PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0, 1, 1024, 1024, 0, NULL);
228888a63011SJustin Miller     ok(server != INVALID_HANDLE_VALUE, "Failed to create server pipe, error %lu.\n", GetLastError());
228988a63011SJustin Miller     client = CreateFileA("\\\\.\\pipe\\wine_tp_test", GENERIC_READ | GENERIC_WRITE,
229088a63011SJustin Miller             0, NULL, OPEN_EXISTING, 0, 0);
229188a63011SJustin Miller     ok(client != INVALID_HANDLE_VALUE, "Failed to create client pipe, error %lu.\n", GetLastError());
229288a63011SJustin Miller 
229388a63011SJustin Miller     environment.Pool = pool;
229488a63011SJustin Miller     io = NULL;
229588a63011SJustin Miller     io = pCreateThreadpoolIo(server, kernel32_io_cb, &userdata, &environment);
229688a63011SJustin Miller     ok(!!io, "expected non-NULL TP_IO\n");
229788a63011SJustin Miller 
229888a63011SJustin Miller     pWaitForThreadpoolIoCallbacks(io, FALSE);
229988a63011SJustin Miller 
230088a63011SJustin Miller     userdata.count = 0;
230188a63011SJustin Miller     pStartThreadpoolIo(io);
230288a63011SJustin Miller 
230388a63011SJustin Miller     thread = CreateThread(NULL, 0, io_wait_thread, io, 0, NULL);
230488a63011SJustin Miller     ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "TpWaitForIoCompletion() should not return\n");
230588a63011SJustin Miller 
230688a63011SJustin Miller     ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
230788a63011SJustin Miller     ok(!ret, "wrong ret %d\n", ret);
230888a63011SJustin Miller     ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError());
230988a63011SJustin Miller 
231088a63011SJustin Miller     ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
231188a63011SJustin Miller     ok(ret, "WriteFile() failed, error %lu\n", GetLastError());
231288a63011SJustin Miller 
231388a63011SJustin Miller     pWaitForThreadpoolIoCallbacks(io, FALSE);
231488a63011SJustin Miller     ok(userdata.count == 1, "callback ran %u times\n", userdata.count);
231588a63011SJustin Miller     ok(userdata.ovl == &ovl, "expected %p, got %p\n", &ovl, userdata.ovl);
231688a63011SJustin Miller     ok(userdata.ret == ERROR_SUCCESS, "got status %#lx\n", userdata.ret);
231788a63011SJustin Miller     ok(userdata.length == 1, "got length %Iu\n", userdata.length);
231888a63011SJustin Miller     ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io);
231988a63011SJustin Miller 
232088a63011SJustin Miller     ok(!WaitForSingleObject(thread, 1000), "wait timed out\n");
232188a63011SJustin Miller     CloseHandle(thread);
232288a63011SJustin Miller 
232388a63011SJustin Miller     userdata.count = 0;
232488a63011SJustin Miller     pStartThreadpoolIo(io);
232588a63011SJustin Miller     pStartThreadpoolIo(io);
232688a63011SJustin Miller 
232788a63011SJustin Miller     ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
232888a63011SJustin Miller     ok(!ret, "wrong ret %d\n", ret);
232988a63011SJustin Miller     ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError());
233088a63011SJustin Miller     ret = ReadFile(server, in2, sizeof(in2), NULL, &ovl2);
233188a63011SJustin Miller     ok(!ret, "wrong ret %d\n", ret);
233288a63011SJustin Miller     ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError());
233388a63011SJustin Miller 
233488a63011SJustin Miller     ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
233588a63011SJustin Miller     ok(ret, "WriteFile() failed, error %lu\n", GetLastError());
233688a63011SJustin Miller     ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
233788a63011SJustin Miller     ok(ret, "WriteFile() failed, error %lu\n", GetLastError());
233888a63011SJustin Miller 
233988a63011SJustin Miller     pWaitForThreadpoolIoCallbacks(io, FALSE);
234088a63011SJustin Miller     ok(userdata.count == 2, "callback ran %u times\n", userdata.count);
234188a63011SJustin Miller     ok(userdata.ret == STATUS_SUCCESS, "got status %#lx\n", userdata.ret);
234288a63011SJustin Miller     ok(userdata.length == 1, "got length %Iu\n", userdata.length);
234388a63011SJustin Miller     ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io);
234488a63011SJustin Miller 
234588a63011SJustin Miller     userdata.count = 0;
234688a63011SJustin Miller     pStartThreadpoolIo(io);
234788a63011SJustin Miller     pWaitForThreadpoolIoCallbacks(io, TRUE);
234888a63011SJustin Miller     ok(!userdata.count, "callback ran %u times\n", userdata.count);
234988a63011SJustin Miller 
235088a63011SJustin Miller     pStartThreadpoolIo(io);
235188a63011SJustin Miller 
235288a63011SJustin Miller     ret = WriteFile(client, out, sizeof(out), &ret_size, NULL);
235388a63011SJustin Miller     ok(ret, "WriteFile() failed, error %lu\n", GetLastError());
235488a63011SJustin Miller 
235588a63011SJustin Miller     ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
235688a63011SJustin Miller     ok(ret, "wrong ret %d\n", ret);
235788a63011SJustin Miller 
235888a63011SJustin Miller     pWaitForThreadpoolIoCallbacks(io, FALSE);
235988a63011SJustin Miller     ok(userdata.count == 1, "callback ran %u times\n", userdata.count);
236088a63011SJustin Miller     ok(userdata.ovl == &ovl, "expected %p, got %p\n", &ovl, userdata.ovl);
236188a63011SJustin Miller     ok(userdata.ret == ERROR_SUCCESS, "got status %#lx\n", userdata.ret);
236288a63011SJustin Miller     ok(userdata.length == 1, "got length %Iu\n", userdata.length);
236388a63011SJustin Miller     ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io);
236488a63011SJustin Miller 
236588a63011SJustin Miller     userdata.count = 0;
236688a63011SJustin Miller     pStartThreadpoolIo(io);
236788a63011SJustin Miller 
236888a63011SJustin Miller     ret = ReadFile(server, NULL, 1, NULL, &ovl);
236988a63011SJustin Miller     ok(!ret, "wrong ret %d\n", ret);
237088a63011SJustin Miller     ok(GetLastError() == ERROR_NOACCESS, "wrong error %lu\n", GetLastError());
237188a63011SJustin Miller 
237288a63011SJustin Miller     pCancelThreadpoolIo(io);
237388a63011SJustin Miller     pWaitForThreadpoolIoCallbacks(io, FALSE);
237488a63011SJustin Miller     ok(!userdata.count, "callback ran %u times\n", userdata.count);
237588a63011SJustin Miller 
237688a63011SJustin Miller     userdata.count = 0;
237788a63011SJustin Miller     pStartThreadpoolIo(io);
237888a63011SJustin Miller 
237988a63011SJustin Miller     ret = ReadFile(server, in, sizeof(in), NULL, &ovl);
238088a63011SJustin Miller     ok(!ret, "wrong ret %d\n", ret);
238188a63011SJustin Miller     ok(GetLastError() == ERROR_IO_PENDING, "wrong error %lu\n", GetLastError());
238288a63011SJustin Miller     ret = CancelIo(server);
238388a63011SJustin Miller     ok(ret, "CancelIo() failed, error %lu\n", GetLastError());
238488a63011SJustin Miller 
238588a63011SJustin Miller     pWaitForThreadpoolIoCallbacks(io, FALSE);
238688a63011SJustin Miller     ok(userdata.count == 1, "callback ran %u times\n", userdata.count);
238788a63011SJustin Miller     ok(userdata.ovl == &ovl, "expected %p, got %p\n", &ovl, userdata.ovl);
238888a63011SJustin Miller     ok(userdata.ret == ERROR_OPERATION_ABORTED, "got status %#lx\n", userdata.ret);
238988a63011SJustin Miller     ok(!userdata.length, "got length %Iu\n", userdata.length);
239088a63011SJustin Miller     ok(userdata.io == io, "expected %p, got %p\n", io, userdata.io);
239188a63011SJustin Miller 
239288a63011SJustin Miller     CloseHandle(ovl.hEvent);
239388a63011SJustin Miller     CloseHandle(client);
239488a63011SJustin Miller     CloseHandle(server);
239588a63011SJustin Miller     pCloseThreadpoolIo(io);
239688a63011SJustin Miller     pTpReleasePool(pool);
239788a63011SJustin Miller }
239888a63011SJustin Miller 
START_TEST(threadpool)2399f7932ba2SAmine Khaldi START_TEST(threadpool)
2400f7932ba2SAmine Khaldi {
2401f7932ba2SAmine Khaldi     test_RtlQueueWorkItem();
2402f7932ba2SAmine Khaldi     test_RtlRegisterWait();
2403f7932ba2SAmine Khaldi 
2404f7932ba2SAmine Khaldi     if (!init_threadpool())
2405f7932ba2SAmine Khaldi         return;
2406f7932ba2SAmine Khaldi 
2407f7932ba2SAmine Khaldi     test_tp_simple();
2408f7932ba2SAmine Khaldi     test_tp_work();
2409f7932ba2SAmine Khaldi     test_tp_work_scheduler();
2410f7932ba2SAmine Khaldi     test_tp_group_wait();
2411f7932ba2SAmine Khaldi     test_tp_group_cancel();
2412f7932ba2SAmine Khaldi     test_tp_instance();
2413f7932ba2SAmine Khaldi     test_tp_disassociate();
2414f7932ba2SAmine Khaldi     test_tp_timer();
2415f7932ba2SAmine Khaldi     test_tp_window_length();
2416f7932ba2SAmine Khaldi     test_tp_wait();
2417f7932ba2SAmine Khaldi     test_tp_multi_wait();
241888a63011SJustin Miller     test_tp_io();
241988a63011SJustin Miller     test_kernel32_tp_io();
2420f7932ba2SAmine Khaldi }
2421