server: Correct mapping of mutex access rights.
[wine.git] / dlls / kernel32 / tests / sync.c
blob98d996fabe7d33fac4b20c752dd6facff783582d
1 /*
2 * Synchronization tests
4 * Copyright 2005 Mike McCormack for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define _WIN32_WINNT 0x500
22 #include <stdarg.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <windef.h>
26 #include <winbase.h>
28 #include "wine/test.h"
30 static BOOL (WINAPI *pChangeTimerQueueTimer)(HANDLE, HANDLE, ULONG, ULONG);
31 static HANDLE (WINAPI *pCreateTimerQueue)(void);
32 static BOOL (WINAPI *pCreateTimerQueueTimer)(PHANDLE, HANDLE, WAITORTIMERCALLBACK,
33 PVOID, DWORD, DWORD, ULONG);
34 static HANDLE (WINAPI *pCreateWaitableTimerA)(SECURITY_ATTRIBUTES*,BOOL,LPCSTR);
35 static BOOL (WINAPI *pDeleteTimerQueueEx)(HANDLE, HANDLE);
36 static BOOL (WINAPI *pDeleteTimerQueueTimer)(HANDLE, HANDLE, HANDLE);
37 static HANDLE (WINAPI *pOpenWaitableTimerA)(DWORD,BOOL,LPCSTR);
39 static void test_signalandwait(void)
41 DWORD (WINAPI *pSignalObjectAndWait)(HANDLE, HANDLE, DWORD, BOOL);
42 HMODULE kernel32;
43 DWORD r;
44 HANDLE event[2], semaphore[2], file;
46 kernel32 = GetModuleHandle("kernel32");
47 pSignalObjectAndWait = (void*) GetProcAddress(kernel32, "SignalObjectAndWait");
49 if (!pSignalObjectAndWait)
50 return;
52 /* invalid parameters */
53 r = pSignalObjectAndWait(NULL, NULL, 0, 0);
54 if (r == ERROR_INVALID_FUNCTION)
56 win_skip("SignalObjectAndWait is not implemented\n");
57 return; /* Win98/ME */
59 ok( r == WAIT_FAILED, "should fail\n");
61 event[0] = CreateEvent(NULL, 0, 0, NULL);
62 event[1] = CreateEvent(NULL, 1, 1, NULL);
64 ok( event[0] && event[1], "failed to create event flags\n");
66 r = pSignalObjectAndWait(event[0], NULL, 0, FALSE);
67 ok( r == WAIT_FAILED, "should fail\n");
69 r = pSignalObjectAndWait(NULL, event[0], 0, FALSE);
70 ok( r == WAIT_FAILED, "should fail\n");
73 /* valid parameters */
74 r = pSignalObjectAndWait(event[0], event[1], 0, FALSE);
75 ok( r == WAIT_OBJECT_0, "should succeed\n");
77 /* event[0] is now signalled */
78 r = pSignalObjectAndWait(event[0], event[0], 0, FALSE);
79 ok( r == WAIT_OBJECT_0, "should succeed\n");
81 /* event[0] is not signalled */
82 r = WaitForSingleObject(event[0], 0);
83 ok( r == WAIT_TIMEOUT, "event was signalled\n");
85 r = pSignalObjectAndWait(event[0], event[0], 0, FALSE);
86 ok( r == WAIT_OBJECT_0, "should succeed\n");
88 /* clear event[1] and check for a timeout */
89 ok(ResetEvent(event[1]), "failed to clear event[1]\n");
90 r = pSignalObjectAndWait(event[0], event[1], 0, FALSE);
91 ok( r == WAIT_TIMEOUT, "should timeout\n");
93 CloseHandle(event[0]);
94 CloseHandle(event[1]);
96 /* semaphores */
97 semaphore[0] = CreateSemaphore( NULL, 0, 1, NULL );
98 semaphore[1] = CreateSemaphore( NULL, 1, 1, NULL );
99 ok( semaphore[0] && semaphore[1], "failed to create semaphore\n");
101 r = pSignalObjectAndWait(semaphore[0], semaphore[1], 0, FALSE);
102 ok( r == WAIT_OBJECT_0, "should succeed\n");
104 r = pSignalObjectAndWait(semaphore[0], semaphore[1], 0, FALSE);
105 ok( r == WAIT_FAILED, "should fail\n");
107 r = ReleaseSemaphore(semaphore[0],1,NULL);
108 ok( r == FALSE, "should fail\n");
110 r = ReleaseSemaphore(semaphore[1],1,NULL);
111 ok( r == TRUE, "should succeed\n");
113 CloseHandle(semaphore[0]);
114 CloseHandle(semaphore[1]);
116 /* try a registry key */
117 file = CreateFile("x", GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
118 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL);
119 r = pSignalObjectAndWait(file, file, 0, FALSE);
120 ok( r == WAIT_FAILED, "should fail\n");
121 ok( ERROR_INVALID_HANDLE == GetLastError(), "should return invalid handle error\n");
122 CloseHandle(file);
125 static void test_mutex(void)
127 DWORD wait_ret;
128 BOOL ret;
129 HANDLE hCreated;
130 HANDLE hOpened;
131 int i;
132 DWORD failed = 0;
134 hCreated = CreateMutex(NULL, FALSE, "WineTestMutex");
135 ok(hCreated != NULL, "CreateMutex failed with error %d\n", GetLastError());
137 hOpened = OpenMutex(0, FALSE, "WineTestMutex");
138 ok(hOpened == NULL, "OpenMutex succeded\n");
140 hOpened = OpenMutex(GENERIC_EXECUTE, FALSE, "WineTestMutex");
141 ok(hOpened != NULL, "OpenMutex failed with error %d\n", GetLastError());
142 wait_ret = WaitForSingleObject(hOpened, INFINITE);
143 ok(wait_ret == WAIT_OBJECT_0, "WaitForSingleObject failed with error %d\n", GetLastError());
144 CloseHandle(hOpened);
146 for(i=0; i < 31; i++)
148 wait_ret = WaitForSingleObject(hCreated, INFINITE);
149 ok(wait_ret == WAIT_OBJECT_0, "WaitForSingleObject failed with error 0x%08x\n", wait_ret);
152 hOpened = OpenMutex(GENERIC_READ | GENERIC_WRITE, FALSE, "WineTestMutex");
153 ok(hOpened != NULL, "OpenMutex failed with error %d\n", GetLastError());
154 wait_ret = WaitForSingleObject(hOpened, INFINITE);
155 ok(wait_ret == WAIT_FAILED, "WaitForSingleObject succeeded\n");
156 CloseHandle(hOpened);
158 for (i = 0; i < 32; i++)
160 hOpened = OpenMutex(0x1 << i, FALSE, "WineTestMutex");
161 if(hOpened != NULL)
163 ret = ReleaseMutex(hOpened);
164 ok(ret, "ReleaseMutex failed with error %d, access %x\n", GetLastError(), 1 << i);
165 CloseHandle(hOpened);
167 else
169 ReleaseMutex(hCreated);
170 failed |=0x1 << i;
174 ok( failed == 0x0de0fffe, "open succeded when it shouldn't: %x\n", failed);
176 ret = ReleaseMutex(hCreated);
177 ok(!ret && (GetLastError() == ERROR_NOT_OWNER),
178 "ReleaseMutex should have failed with ERROR_NOT_OWNER instead of %d\n", GetLastError());
180 /* test case sensitivity */
182 SetLastError(0xdeadbeef);
183 hOpened = OpenMutex(READ_CONTROL, FALSE, "WINETESTMUTEX");
184 ok(!hOpened, "OpenMutex succeeded\n");
185 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %u\n", GetLastError());
187 SetLastError(0xdeadbeef);
188 hOpened = OpenMutex(READ_CONTROL, FALSE, "winetestmutex");
189 ok(!hOpened, "OpenMutex succeeded\n");
190 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %u\n", GetLastError());
192 SetLastError(0xdeadbeef);
193 hOpened = CreateMutex(NULL, FALSE, "WineTestMutex");
194 ok(hOpened != NULL, "CreateMutex failed with error %d\n", GetLastError());
195 ok(GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %u\n", GetLastError());
196 CloseHandle(hOpened);
198 SetLastError(0xdeadbeef);
199 hOpened = CreateMutex(NULL, FALSE, "WINETESTMUTEX");
200 ok(hOpened != NULL, "CreateMutex failed with error %d\n", GetLastError());
201 ok(GetLastError() == 0, "wrong error %u\n", GetLastError());
202 CloseHandle(hOpened);
204 CloseHandle(hCreated);
207 static void test_slist(void)
209 struct item
211 SLIST_ENTRY entry;
212 int value;
213 } item1, item2, item3, *pitem;
215 SLIST_HEADER slist_header;
216 PSLIST_ENTRY entry;
217 USHORT size;
219 VOID (WINAPI *pInitializeSListHead)(PSLIST_HEADER);
220 USHORT (WINAPI *pQueryDepthSList)(PSLIST_HEADER);
221 PSLIST_ENTRY (WINAPI *pInterlockedFlushSList)(PSLIST_HEADER);
222 PSLIST_ENTRY (WINAPI *pInterlockedPopEntrySList)(PSLIST_HEADER);
223 PSLIST_ENTRY (WINAPI *pInterlockedPushEntrySList)(PSLIST_HEADER,PSLIST_ENTRY);
224 HMODULE kernel32;
226 kernel32 = GetModuleHandle("KERNEL32.DLL");
227 pInitializeSListHead = (void*) GetProcAddress(kernel32, "InitializeSListHead");
228 pQueryDepthSList = (void*) GetProcAddress(kernel32, "QueryDepthSList");
229 pInterlockedFlushSList = (void*) GetProcAddress(kernel32, "InterlockedFlushSList");
230 pInterlockedPopEntrySList = (void*) GetProcAddress(kernel32, "InterlockedPopEntrySList");
231 pInterlockedPushEntrySList = (void*) GetProcAddress(kernel32, "InterlockedPushEntrySList");
232 if (pInitializeSListHead == NULL ||
233 pQueryDepthSList == NULL ||
234 pInterlockedFlushSList == NULL ||
235 pInterlockedPopEntrySList == NULL ||
236 pInterlockedPushEntrySList == NULL)
238 win_skip("some required slist entrypoints were not found, skipping tests\n");
239 return;
242 memset(&slist_header, 0xFF, sizeof(slist_header));
243 pInitializeSListHead(&slist_header);
244 size = pQueryDepthSList(&slist_header);
245 ok(size == 0, "initially created slist has size %d, expected 0\n", size);
247 item1.value = 1;
248 ok(pInterlockedPushEntrySList(&slist_header, &item1.entry) == NULL,
249 "previous entry in empty slist wasn't NULL\n");
250 size = pQueryDepthSList(&slist_header);
251 ok(size == 1, "slist with 1 item has size %d\n", size);
253 item2.value = 2;
254 entry = pInterlockedPushEntrySList(&slist_header, &item2.entry);
255 ok(entry != NULL, "previous entry in non-empty slist was NULL\n");
256 if (entry != NULL)
258 pitem = (struct item*) entry;
259 ok(pitem->value == 1, "previous entry in slist wasn't the one added\n");
261 size = pQueryDepthSList(&slist_header);
262 ok(size == 2, "slist with 2 items has size %d\n", size);
264 item3.value = 3;
265 entry = pInterlockedPushEntrySList(&slist_header, &item3.entry);
266 ok(entry != NULL, "previous entry in non-empty slist was NULL\n");
267 if (entry != NULL)
269 pitem = (struct item*) entry;
270 ok(pitem->value == 2, "previous entry in slist wasn't the one added\n");
272 size = pQueryDepthSList(&slist_header);
273 ok(size == 3, "slist with 3 items has size %d\n", size);
275 entry = pInterlockedPopEntrySList(&slist_header);
276 ok(entry != NULL, "entry shouldn't be NULL\n");
277 if (entry != NULL)
279 pitem = (struct item*) entry;
280 ok(pitem->value == 3, "unexpected entry removed\n");
282 size = pQueryDepthSList(&slist_header);
283 ok(size == 2, "slist with 2 items has size %d\n", size);
285 entry = pInterlockedFlushSList(&slist_header);
286 size = pQueryDepthSList(&slist_header);
287 ok(size == 0, "flushed slist should be empty, size is %d\n", size);
288 if (size == 0)
290 ok(pInterlockedPopEntrySList(&slist_header) == NULL,
291 "popping empty slist didn't return NULL\n");
293 ok(((struct item*)entry)->value == 2, "item 2 not in front of list\n");
294 ok(((struct item*)entry->Next)->value == 1, "item 1 not at the back of list\n");
297 static void test_event(void)
299 HANDLE handle, handle2;
300 SECURITY_ATTRIBUTES sa;
301 SECURITY_DESCRIPTOR sd;
302 ACL acl;
304 /* no sd */
305 handle = CreateEventA(NULL, FALSE, FALSE, __FILE__ ": Test Event");
306 ok(handle != NULL, "CreateEventW with blank sd failed with error %d\n", GetLastError());
307 CloseHandle(handle);
309 sa.nLength = sizeof(sa);
310 sa.lpSecurityDescriptor = &sd;
311 sa.bInheritHandle = FALSE;
313 InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
315 /* blank sd */
316 handle = CreateEventA(&sa, FALSE, FALSE, __FILE__ ": Test Event");
317 ok(handle != NULL, "CreateEventW with blank sd failed with error %d\n", GetLastError());
318 CloseHandle(handle);
320 /* sd with NULL dacl */
321 SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
322 handle = CreateEventA(&sa, FALSE, FALSE, __FILE__ ": Test Event");
323 ok(handle != NULL, "CreateEventW with blank sd failed with error %d\n", GetLastError());
324 CloseHandle(handle);
326 /* sd with empty dacl */
327 InitializeAcl(&acl, sizeof(acl), ACL_REVISION);
328 SetSecurityDescriptorDacl(&sd, TRUE, &acl, FALSE);
329 handle = CreateEventA(&sa, FALSE, FALSE, __FILE__ ": Test Event");
330 ok(handle != NULL, "CreateEventW with blank sd failed with error %d\n", GetLastError());
331 CloseHandle(handle);
333 /* test case sensitivity */
335 SetLastError(0xdeadbeef);
336 handle = CreateEventA(NULL, FALSE, FALSE, __FILE__ ": Test Event");
337 ok( handle != NULL, "CreateEvent failed with error %u\n", GetLastError());
338 ok( GetLastError() == 0, "wrong error %u\n", GetLastError());
340 SetLastError(0xdeadbeef);
341 handle2 = CreateEventA(NULL, FALSE, FALSE, __FILE__ ": Test Event");
342 ok( handle2 != NULL, "CreateEvent failed with error %d\n", GetLastError());
343 ok( GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %u\n", GetLastError());
344 CloseHandle( handle2 );
346 SetLastError(0xdeadbeef);
347 handle2 = CreateEventA(NULL, FALSE, FALSE, __FILE__ ": TEST EVENT");
348 ok( handle2 != NULL, "CreateEvent failed with error %d\n", GetLastError());
349 ok( GetLastError() == 0, "wrong error %u\n", GetLastError());
350 CloseHandle( handle2 );
352 SetLastError(0xdeadbeef);
353 handle2 = OpenEventA( EVENT_ALL_ACCESS, FALSE, __FILE__ ": Test Event");
354 ok( handle2 != NULL, "OpenEvent failed with error %d\n", GetLastError());
355 CloseHandle( handle2 );
357 SetLastError(0xdeadbeef);
358 handle2 = OpenEventA( EVENT_ALL_ACCESS, FALSE, __FILE__ ": TEST EVENT");
359 ok( !handle2, "OpenEvent succeeded\n");
360 ok( GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %u\n", GetLastError());
362 CloseHandle( handle );
365 static void test_semaphore(void)
367 HANDLE handle, handle2;
369 /* test case sensitivity */
371 SetLastError(0xdeadbeef);
372 handle = CreateSemaphoreA(NULL, 0, 1, __FILE__ ": Test Semaphore");
373 ok(handle != NULL, "CreateSemaphore failed with error %u\n", GetLastError());
374 ok(GetLastError() == 0, "wrong error %u\n", GetLastError());
376 SetLastError(0xdeadbeef);
377 handle2 = CreateSemaphoreA(NULL, 0, 1, __FILE__ ": Test Semaphore");
378 ok( handle2 != NULL, "CreateSemaphore failed with error %d\n", GetLastError());
379 ok( GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %u\n", GetLastError());
380 CloseHandle( handle2 );
382 SetLastError(0xdeadbeef);
383 handle2 = CreateSemaphoreA(NULL, 0, 1, __FILE__ ": TEST SEMAPHORE");
384 ok( handle2 != NULL, "CreateSemaphore failed with error %d\n", GetLastError());
385 ok( GetLastError() == 0, "wrong error %u\n", GetLastError());
386 CloseHandle( handle2 );
388 SetLastError(0xdeadbeef);
389 handle2 = OpenSemaphoreA( SEMAPHORE_ALL_ACCESS, FALSE, __FILE__ ": Test Semaphore");
390 ok( handle2 != NULL, "OpenSemaphore failed with error %d\n", GetLastError());
391 CloseHandle( handle2 );
393 SetLastError(0xdeadbeef);
394 handle2 = OpenSemaphoreA( SEMAPHORE_ALL_ACCESS, FALSE, __FILE__ ": TEST SEMAPHORE");
395 ok( !handle2, "OpenSemaphore succeeded\n");
396 ok( GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %u\n", GetLastError());
398 CloseHandle( handle );
401 static void test_waitable_timer(void)
403 HANDLE handle, handle2;
405 if (!pCreateWaitableTimerA || !pOpenWaitableTimerA)
407 win_skip("{Create,Open}WaitableTimerA() is not available\n");
408 return;
411 /* test case sensitivity */
413 SetLastError(0xdeadbeef);
414 handle = pCreateWaitableTimerA(NULL, FALSE, __FILE__ ": Test WaitableTimer");
415 ok(handle != NULL, "CreateWaitableTimer failed with error %u\n", GetLastError());
416 ok(GetLastError() == 0, "wrong error %u\n", GetLastError());
418 SetLastError(0xdeadbeef);
419 handle2 = pCreateWaitableTimerA(NULL, FALSE, __FILE__ ": Test WaitableTimer");
420 ok( handle2 != NULL, "CreateWaitableTimer failed with error %d\n", GetLastError());
421 ok( GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %u\n", GetLastError());
422 CloseHandle( handle2 );
424 SetLastError(0xdeadbeef);
425 handle2 = pCreateWaitableTimerA(NULL, FALSE, __FILE__ ": TEST WAITABLETIMER");
426 ok( handle2 != NULL, "CreateWaitableTimer failed with error %d\n", GetLastError());
427 ok( GetLastError() == 0, "wrong error %u\n", GetLastError());
428 CloseHandle( handle2 );
430 SetLastError(0xdeadbeef);
431 handle2 = pOpenWaitableTimerA( TIMER_ALL_ACCESS, FALSE, __FILE__ ": Test WaitableTimer");
432 ok( handle2 != NULL, "OpenWaitableTimer failed with error %d\n", GetLastError());
433 CloseHandle( handle2 );
435 SetLastError(0xdeadbeef);
436 handle2 = pOpenWaitableTimerA( TIMER_ALL_ACCESS, FALSE, __FILE__ ": TEST WAITABLETIMER");
437 ok( !handle2, "OpenWaitableTimer succeeded\n");
438 ok( GetLastError() == ERROR_FILE_NOT_FOUND ||
439 GetLastError() == ERROR_INVALID_NAME, /* win98 */
440 "wrong error %u\n", GetLastError());
442 CloseHandle( handle );
445 static HANDLE sem = 0;
447 static void CALLBACK iocp_callback(DWORD dwErrorCode, DWORD dwNumberOfBytesTransferred, LPOVERLAPPED lpOverlapped)
449 ReleaseSemaphore(sem, 1, NULL);
452 static BOOL (WINAPI *p_BindIoCompletionCallback)( HANDLE FileHandle, LPOVERLAPPED_COMPLETION_ROUTINE Function, ULONG Flags) = NULL;
454 static void test_iocp_callback(void)
456 char temp_path[MAX_PATH];
457 char filename[MAX_PATH];
458 DWORD ret;
459 BOOL retb;
460 static const char prefix[] = "pfx";
461 HANDLE hFile;
462 HMODULE hmod = GetModuleHandleA("kernel32.dll");
463 DWORD bytesWritten;
464 const char *buffer = "12345678123456781234567812345678";
465 OVERLAPPED overlapped;
467 p_BindIoCompletionCallback = (void*)GetProcAddress(hmod, "BindIoCompletionCallback");
468 if(!p_BindIoCompletionCallback) {
469 win_skip("BindIoCompletionCallback not found in this DLL\n");
470 return;
473 sem = CreateSemaphore(NULL, 0, 1, NULL);
474 ok(sem != INVALID_HANDLE_VALUE, "Creating a semaphore failed\n");
476 ret = GetTempPathA(MAX_PATH, temp_path);
477 ok(ret != 0, "GetTempPathA error %d\n", GetLastError());
478 ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n");
480 ret = GetTempFileNameA(temp_path, prefix, 0, filename);
481 ok(ret != 0, "GetTempFileNameA error %d\n", GetLastError());
483 hFile = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
484 CREATE_ALWAYS, FILE_FLAG_RANDOM_ACCESS, 0);
485 ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA: error %d\n", GetLastError());
487 retb = p_BindIoCompletionCallback(hFile, iocp_callback, 0);
488 ok(retb == FALSE, "BindIoCompletionCallback succeeded on a file that wasn't created with FILE_FLAG_OVERLAPPED\n");
489 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error is %d\n", GetLastError());
491 ret = CloseHandle(hFile);
492 ok( ret, "CloseHandle: error %d\n", GetLastError());
493 ret = DeleteFileA(filename);
494 ok( ret, "DeleteFileA: error %d\n", GetLastError());
496 hFile = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
497 CREATE_ALWAYS, FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_OVERLAPPED, 0);
498 ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA: error %d\n", GetLastError());
500 retb = p_BindIoCompletionCallback(hFile, iocp_callback, 0);
501 ok(retb == TRUE, "BindIoCompletionCallback failed\n");
503 memset(&overlapped, 0, sizeof(overlapped));
504 retb = WriteFile(hFile, buffer, 4, &bytesWritten, &overlapped);
505 ok(retb == TRUE || GetLastError() == ERROR_IO_PENDING, "WriteFile failed, lastError = %d\n", GetLastError());
507 ret = WaitForSingleObject(sem, 5000);
508 ok(ret == WAIT_OBJECT_0, "Wait for the IO completion callback failed\n");
509 CloseHandle(sem);
511 retb = p_BindIoCompletionCallback(hFile, iocp_callback, 0);
512 ok(retb == FALSE, "BindIoCompletionCallback succeeded when setting the same callback on the file again\n");
513 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error is %d\n", GetLastError());
514 retb = p_BindIoCompletionCallback(hFile, NULL, 0);
515 ok(retb == FALSE, "BindIoCompletionCallback succeeded when setting the callback to NULL\n");
516 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error is %d\n", GetLastError());
518 ret = CloseHandle(hFile);
519 ok( ret, "CloseHandle: error %d\n", GetLastError());
520 ret = DeleteFileA(filename);
521 ok( ret, "DeleteFileA: error %d\n", GetLastError());
523 /* win2k3 requires the Flags parameter to be zero */
524 SetLastError(0xdeadbeef);
525 hFile = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
526 CREATE_ALWAYS, FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_OVERLAPPED, 0);
527 ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA: error %d\n", GetLastError());
528 retb = p_BindIoCompletionCallback(hFile, iocp_callback, 12345);
529 if (!retb)
530 ok(GetLastError() == ERROR_INVALID_PARAMETER,
531 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
532 else
533 ok(retb == TRUE, "BindIoCompletionCallback failed with Flags != 0\n");
534 ret = CloseHandle(hFile);
535 ok( ret, "CloseHandle: error %d\n", GetLastError());
536 ret = DeleteFileA(filename);
537 ok( ret, "DeleteFileA: error %d\n", GetLastError());
539 retb = p_BindIoCompletionCallback(NULL, iocp_callback, 0);
540 ok(retb == FALSE, "BindIoCompletionCallback succeeded on a NULL file\n");
541 ok(GetLastError() == ERROR_INVALID_HANDLE ||
542 GetLastError() == ERROR_INVALID_PARAMETER, /* vista */
543 "Last error is %d\n", GetLastError());
546 static void CALLBACK timer_queue_cb1(PVOID p, BOOLEAN timedOut)
548 int *pn = p;
549 ok(timedOut, "Timer callbacks should always time out\n");
550 ++*pn;
553 struct timer_queue_data1
555 int num_calls;
556 int max_calls;
557 HANDLE q, t;
560 static void CALLBACK timer_queue_cb2(PVOID p, BOOLEAN timedOut)
562 struct timer_queue_data1 *d = p;
563 ok(timedOut, "Timer callbacks should always time out\n");
564 if (d->t && ++d->num_calls == d->max_calls)
566 BOOL ret;
567 SetLastError(0xdeadbeef);
568 /* Note, XP SP2 does *not* do any deadlock checking, so passing
569 INVALID_HANDLE_VALUE here will just hang. */
570 ret = pDeleteTimerQueueTimer(d->q, d->t, NULL);
571 ok(!ret, "DeleteTimerQueueTimer\n");
572 ok(GetLastError() == ERROR_IO_PENDING, "DeleteTimerQueueTimer\n");
576 static void CALLBACK timer_queue_cb3(PVOID p, BOOLEAN timedOut)
578 struct timer_queue_data1 *d = p;
579 ok(timedOut, "Timer callbacks should always time out\n");
580 if (d->t && ++d->num_calls == d->max_calls)
582 /* Basically kill the timer since it won't have time to run
583 again. */
584 BOOL ret = pChangeTimerQueueTimer(d->q, d->t, 10000, 0);
585 ok(ret, "ChangeTimerQueueTimer\n");
589 static void CALLBACK timer_queue_cb4(PVOID p, BOOLEAN timedOut)
591 struct timer_queue_data1 *d = p;
592 ok(timedOut, "Timer callbacks should always time out\n");
593 if (d->t)
595 /* This tests whether a timer gets flagged for deletion before
596 or after the callback runs. If we start this timer with a
597 period of zero (run once), then ChangeTimerQueueTimer will
598 fail if the timer is already flagged. Hence we really run
599 only once. Otherwise we will run multiple times. */
600 BOOL ret = pChangeTimerQueueTimer(d->q, d->t, 50, 50);
601 ok(ret, "ChangeTimerQueueTimer\n");
602 ++d->num_calls;
606 static void CALLBACK timer_queue_cb5(PVOID p, BOOLEAN timedOut)
608 DWORD_PTR delay = (DWORD_PTR) p;
609 ok(timedOut, "Timer callbacks should always time out\n");
610 if (delay)
611 Sleep(delay);
614 static void CALLBACK timer_queue_cb6(PVOID p, BOOLEAN timedOut)
616 struct timer_queue_data1 *d = p;
617 ok(timedOut, "Timer callbacks should always time out\n");
618 /* This tests an original implementation bug where a deleted timer may get
619 to run, but it is tricky to set up. */
620 if (d->q && d->num_calls++ == 0)
622 /* First run: delete ourselves, then insert and remove a timer
623 that goes in front of us in the sorted timeout list. Once
624 removed, we will still timeout at the faster timer's due time,
625 but this should be a no-op if we are bug-free. There should
626 not be a second run. We can test the value of num_calls later. */
627 BOOL ret;
628 HANDLE t;
630 /* The delete will pend while we are in this callback. */
631 SetLastError(0xdeadbeef);
632 ret = pDeleteTimerQueueTimer(d->q, d->t, NULL);
633 ok(!ret, "DeleteTimerQueueTimer\n");
634 ok(GetLastError() == ERROR_IO_PENDING, "DeleteTimerQueueTimer\n");
636 ret = pCreateTimerQueueTimer(&t, d->q, timer_queue_cb1, NULL, 100, 0, 0);
637 ok(ret, "CreateTimerQueueTimer\n");
638 ok(t != NULL, "CreateTimerQueueTimer\n");
640 ret = pDeleteTimerQueueTimer(d->q, t, INVALID_HANDLE_VALUE);
641 ok(ret, "DeleteTimerQueueTimer\n");
643 /* Now we stay alive by hanging around in the callback. */
644 Sleep(500);
648 static void test_timer_queue(void)
650 HANDLE q, t1, t2, t3, t4, t5;
651 int n1, n2, n3, n4, n5;
652 struct timer_queue_data1 d1, d2, d3, d4;
653 HANDLE e, et1, et2;
654 BOOL ret;
656 if (!pChangeTimerQueueTimer || !pCreateTimerQueue || !pCreateTimerQueueTimer
657 || !pDeleteTimerQueueEx || !pDeleteTimerQueueTimer)
659 win_skip("TimerQueue API not present\n");
660 return;
663 /* Test asynchronous deletion of the queue. */
664 q = pCreateTimerQueue();
665 ok(q != NULL, "CreateTimerQueue\n");
667 SetLastError(0xdeadbeef);
668 ret = pDeleteTimerQueueEx(q, NULL);
669 ok(ret /* vista */ || GetLastError() == ERROR_IO_PENDING,
670 "DeleteTimerQueueEx, GetLastError: expected ERROR_IO_PENDING, got %d\n",
671 GetLastError());
673 /* Test synchronous deletion of the queue and running timers. */
674 q = pCreateTimerQueue();
675 ok(q != NULL, "CreateTimerQueue\n");
677 /* Called once. */
678 t1 = NULL;
679 n1 = 0;
680 ret = pCreateTimerQueueTimer(&t1, q, timer_queue_cb1, &n1, 0,
681 0, 0);
682 ok(ret, "CreateTimerQueueTimer\n");
683 ok(t1 != NULL, "CreateTimerQueueTimer\n");
685 /* A slow one. */
686 t2 = NULL;
687 n2 = 0;
688 ret = pCreateTimerQueueTimer(&t2, q, timer_queue_cb1, &n2, 0,
689 100, 0);
690 ok(ret, "CreateTimerQueueTimer\n");
691 ok(t2 != NULL, "CreateTimerQueueTimer\n");
693 /* A fast one. */
694 t3 = NULL;
695 n3 = 0;
696 ret = pCreateTimerQueueTimer(&t3, q, timer_queue_cb1, &n3, 0,
697 10, 0);
698 ok(ret, "CreateTimerQueueTimer\n");
699 ok(t3 != NULL, "CreateTimerQueueTimer\n");
701 /* Start really late (it won't start). */
702 t4 = NULL;
703 n4 = 0;
704 ret = pCreateTimerQueueTimer(&t4, q, timer_queue_cb1, &n4, 10000,
705 10, 0);
706 ok(ret, "CreateTimerQueueTimer\n");
707 ok(t4 != NULL, "CreateTimerQueueTimer\n");
709 /* Start soon, but delay so long it won't run again. */
710 t5 = NULL;
711 n5 = 0;
712 ret = pCreateTimerQueueTimer(&t5, q, timer_queue_cb1, &n5, 0,
713 10000, 0);
714 ok(ret, "CreateTimerQueueTimer\n");
715 ok(t5 != NULL, "CreateTimerQueueTimer\n");
717 /* Give them a chance to do some work. */
718 Sleep(500);
720 /* Test deleting a once-only timer. */
721 ret = pDeleteTimerQueueTimer(q, t1, INVALID_HANDLE_VALUE);
722 ok(ret, "DeleteTimerQueueTimer\n");
724 /* A periodic timer. */
725 ret = pDeleteTimerQueueTimer(q, t2, INVALID_HANDLE_VALUE);
726 ok(ret, "DeleteTimerQueueTimer\n");
728 ret = pDeleteTimerQueueEx(q, INVALID_HANDLE_VALUE);
729 ok(ret, "DeleteTimerQueueEx\n");
730 ok(n1 == 1, "Timer callback 1\n");
731 ok(n2 < n3, "Timer callback 2 should be much slower than 3\n");
732 ok(n4 == 0, "Timer callback 4\n");
733 ok(n5 == 1, "Timer callback 5\n");
735 /* Test synchronous deletion of the timer/queue with event trigger. */
736 e = CreateEvent(NULL, TRUE, FALSE, NULL);
737 et1 = CreateEvent(NULL, TRUE, FALSE, NULL);
738 et2 = CreateEvent(NULL, TRUE, FALSE, NULL);
739 if (!e || !et1 || !et2)
741 skip("Failed to create timer queue descruction event\n");
742 return;
745 q = pCreateTimerQueue();
746 ok(q != NULL, "CreateTimerQueue\n");
748 /* Run once and finish quickly (should be done when we delete it). */
749 t1 = NULL;
750 ret = pCreateTimerQueueTimer(&t1, q, timer_queue_cb5, NULL, 0, 0, 0);
751 ok(ret, "CreateTimerQueueTimer\n");
752 ok(t1 != NULL, "CreateTimerQueueTimer\n");
754 /* Run once and finish slowly (shouldn't be done when we delete it). */
755 t2 = NULL;
756 ret = pCreateTimerQueueTimer(&t2, q, timer_queue_cb5, (PVOID) 1000, 0,
757 0, 0);
758 ok(ret, "CreateTimerQueueTimer\n");
759 ok(t2 != NULL, "CreateTimerQueueTimer\n");
761 /* Run once and finish quickly (should be done when we delete it). */
762 t3 = NULL;
763 ret = pCreateTimerQueueTimer(&t3, q, timer_queue_cb5, NULL, 0, 0, 0);
764 ok(ret, "CreateTimerQueueTimer\n");
765 ok(t3 != NULL, "CreateTimerQueueTimer\n");
767 /* Run once and finish slowly (shouldn't be done when we delete it). */
768 t4 = NULL;
769 ret = pCreateTimerQueueTimer(&t4, q, timer_queue_cb5, (PVOID) 1000, 0,
770 0, 0);
771 ok(ret, "CreateTimerQueueTimer\n");
772 ok(t4 != NULL, "CreateTimerQueueTimer\n");
774 /* Give them a chance to start. */
775 Sleep(400);
777 /* DeleteTimerQueueTimer always returns PENDING with a NULL event,
778 even if the timer is finished. */
779 SetLastError(0xdeadbeef);
780 ret = pDeleteTimerQueueTimer(q, t1, NULL);
781 ok(ret /* vista */ || GetLastError() == ERROR_IO_PENDING,
782 "DeleteTimerQueueTimer, GetLastError: expected ERROR_IO_PENDING, got %d\n",
783 GetLastError());
785 SetLastError(0xdeadbeef);
786 ret = pDeleteTimerQueueTimer(q, t2, NULL);
787 ok(!ret, "DeleteTimerQueueTimer call was expected to fail\n");
788 ok(GetLastError() == ERROR_IO_PENDING,
789 "DeleteTimerQueueTimer, GetLastError: expected ERROR_IO_PENDING, got %d\n",
790 GetLastError());
792 SetLastError(0xdeadbeef);
793 ret = pDeleteTimerQueueTimer(q, t3, et1);
794 ok(ret, "DeleteTimerQueueTimer call was expected to fail\n");
795 ok(GetLastError() == 0xdeadbeef,
796 "DeleteTimerQueueTimer, GetLastError: expected 0xdeadbeef, got %d\n",
797 GetLastError());
798 ok(WaitForSingleObject(et1, 250) == WAIT_OBJECT_0,
799 "Timer destruction event not triggered\n");
801 SetLastError(0xdeadbeef);
802 ret = pDeleteTimerQueueTimer(q, t4, et2);
803 ok(!ret, "DeleteTimerQueueTimer call was expected to fail\n");
804 ok(GetLastError() == ERROR_IO_PENDING,
805 "DeleteTimerQueueTimer, GetLastError: expected ERROR_IO_PENDING, got %d\n",
806 GetLastError());
807 ok(WaitForSingleObject(et2, 1000) == WAIT_OBJECT_0,
808 "Timer destruction event not triggered\n");
810 SetLastError(0xdeadbeef);
811 ret = pDeleteTimerQueueEx(q, e);
812 ok(ret /* vista */ || GetLastError() == ERROR_IO_PENDING,
813 "DeleteTimerQueueEx, GetLastError: expected ERROR_IO_PENDING, got %d\n",
814 GetLastError());
815 ok(WaitForSingleObject(e, 250) == WAIT_OBJECT_0,
816 "Queue destruction event not triggered\n");
817 CloseHandle(e);
819 /* Test deleting/changing a timer in execution. */
820 q = pCreateTimerQueue();
821 ok(q != NULL, "CreateTimerQueue\n");
823 /* Test changing a once-only timer before it fires (this is allowed,
824 whereas after it fires you cannot). */
825 n1 = 0;
826 ret = pCreateTimerQueueTimer(&t1, q, timer_queue_cb1, &n1, 10000,
827 0, 0);
828 ok(ret, "CreateTimerQueueTimer\n");
829 ok(t1 != NULL, "CreateTimerQueueTimer\n");
830 ret = pChangeTimerQueueTimer(q, t1, 0, 0);
831 ok(ret, "ChangeTimerQueueTimer\n");
833 d2.t = t2 = NULL;
834 d2.num_calls = 0;
835 d2.max_calls = 3;
836 d2.q = q;
837 ret = pCreateTimerQueueTimer(&t2, q, timer_queue_cb2, &d2, 10,
838 10, 0);
839 d2.t = t2;
840 ok(ret, "CreateTimerQueueTimer\n");
841 ok(t2 != NULL, "CreateTimerQueueTimer\n");
843 d3.t = t3 = NULL;
844 d3.num_calls = 0;
845 d3.max_calls = 4;
846 d3.q = q;
847 ret = pCreateTimerQueueTimer(&t3, q, timer_queue_cb3, &d3, 10,
848 10, 0);
849 d3.t = t3;
850 ok(ret, "CreateTimerQueueTimer\n");
851 ok(t3 != NULL, "CreateTimerQueueTimer\n");
853 d4.t = t4 = NULL;
854 d4.num_calls = 0;
855 d4.q = q;
856 ret = pCreateTimerQueueTimer(&t4, q, timer_queue_cb4, &d4, 10,
857 0, 0);
858 d4.t = t4;
859 ok(ret, "CreateTimerQueueTimer\n");
860 ok(t4 != NULL, "CreateTimerQueueTimer\n");
862 Sleep(500);
864 ret = pDeleteTimerQueueEx(q, INVALID_HANDLE_VALUE);
865 ok(ret, "DeleteTimerQueueEx\n");
866 ok(n1 == 1, "ChangeTimerQueueTimer\n");
867 ok(d2.num_calls == d2.max_calls, "DeleteTimerQueueTimer\n");
868 ok(d3.num_calls == d3.max_calls, "ChangeTimerQueueTimer\n");
869 ok(d4.num_calls == 1, "Timer flagged for deletion incorrectly\n");
871 /* Test an obscure bug that was in the original implementation. */
872 q = pCreateTimerQueue();
873 ok(q != NULL, "CreateTimerQueue\n");
875 /* All the work is done in the callback. */
876 d1.t = t1 = NULL;
877 d1.num_calls = 0;
878 d1.q = q;
879 ret = pCreateTimerQueueTimer(&t1, q, timer_queue_cb6, &d1, 100,
880 100, WT_EXECUTELONGFUNCTION);
881 d1.t = t1;
882 ok(ret, "CreateTimerQueueTimer\n");
883 ok(t1 != NULL, "CreateTimerQueueTimer\n");
885 Sleep(750);
887 SetLastError(0xdeadbeef);
888 ret = pDeleteTimerQueueEx(q, NULL);
889 ok(ret /* vista */ || GetLastError() == ERROR_IO_PENDING,
890 "DeleteTimerQueueEx, GetLastError: expected ERROR_IO_PENDING, got %d\n",
891 GetLastError());
892 ok(d1.num_calls == 1, "DeleteTimerQueueTimer\n");
894 /* Test functions on the default timer queue. */
895 t1 = NULL;
896 n1 = 0;
897 ret = pCreateTimerQueueTimer(&t1, NULL, timer_queue_cb1, &n1, 1000,
898 1000, 0);
899 ok(ret, "CreateTimerQueueTimer, default queue\n");
900 ok(t1 != NULL, "CreateTimerQueueTimer, default queue\n");
902 ret = pChangeTimerQueueTimer(NULL, t1, 2000, 2000);
903 ok(ret, "ChangeTimerQueueTimer, default queue\n");
905 ret = pDeleteTimerQueueTimer(NULL, t1, INVALID_HANDLE_VALUE);
906 ok(ret, "DeleteTimerQueueTimer, default queue\n");
908 /* Try mixing default and non-default queues. Apparently this works. */
909 q = pCreateTimerQueue();
910 ok(q != NULL, "CreateTimerQueue\n");
912 t1 = NULL;
913 n1 = 0;
914 ret = pCreateTimerQueueTimer(&t1, q, timer_queue_cb1, &n1, 1000,
915 1000, 0);
916 ok(ret, "CreateTimerQueueTimer\n");
917 ok(t1 != NULL, "CreateTimerQueueTimer\n");
919 t2 = NULL;
920 n2 = 0;
921 ret = pCreateTimerQueueTimer(&t2, NULL, timer_queue_cb1, &n2, 1000,
922 1000, 0);
923 ok(ret, "CreateTimerQueueTimer\n");
924 ok(t2 != NULL, "CreateTimerQueueTimer\n");
926 ret = pChangeTimerQueueTimer(NULL, t1, 2000, 2000);
927 ok(ret, "ChangeTimerQueueTimer\n");
929 ret = pChangeTimerQueueTimer(q, t2, 2000, 2000);
930 ok(ret, "ChangeTimerQueueTimer\n");
932 ret = pDeleteTimerQueueTimer(NULL, t1, INVALID_HANDLE_VALUE);
933 ok(ret, "DeleteTimerQueueTimer\n");
935 ret = pDeleteTimerQueueTimer(q, t2, INVALID_HANDLE_VALUE);
936 ok(ret, "DeleteTimerQueueTimer\n");
938 /* Try to delete the default queue? In any case: not allowed. */
939 SetLastError(0xdeadbeef);
940 ret = pDeleteTimerQueueEx(NULL, NULL);
941 ok(!ret, "DeleteTimerQueueEx call was expected to fail\n");
942 ok(GetLastError() == ERROR_INVALID_HANDLE,
943 "DeleteTimerQueueEx, GetLastError: expected ERROR_INVALID_HANDLE, got %d\n",
944 GetLastError());
946 SetLastError(0xdeadbeef);
947 ret = pDeleteTimerQueueEx(q, NULL);
948 ok(ret /* vista */ || GetLastError() == ERROR_IO_PENDING,
949 "DeleteTimerQueueEx, GetLastError: expected ERROR_IO_PENDING, got %d\n",
950 GetLastError());
953 static HANDLE modify_handle(HANDLE handle, DWORD modify)
955 DWORD tmp = HandleToULong(handle);
956 tmp |= modify;
957 return ULongToHandle(tmp);
960 static void test_WaitForSingleObject(void)
962 HANDLE signaled, nonsignaled, invalid;
963 DWORD ret;
965 signaled = CreateEventW(NULL, TRUE, TRUE, NULL);
966 nonsignaled = CreateEventW(NULL, TRUE, FALSE, NULL);
967 invalid = (HANDLE) 0xdeadbee0;
969 /* invalid handle with different values for lower 2 bits */
970 SetLastError(0xdeadbeef);
971 ret = WaitForSingleObject(invalid, 0);
972 ok(ret == WAIT_FAILED, "expected WAIT_FAILED, got %d\n", ret);
973 ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
975 SetLastError(0xdeadbeef);
976 ret = WaitForSingleObject(modify_handle(invalid, 1), 0);
977 ok(ret == WAIT_FAILED, "expected WAIT_FAILED, got %d\n", ret);
978 ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
980 SetLastError(0xdeadbeef);
981 ret = WaitForSingleObject(modify_handle(invalid, 2), 0);
982 ok(ret == WAIT_FAILED, "expected WAIT_FAILED, got %d\n", ret);
983 ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
985 SetLastError(0xdeadbeef);
986 ret = WaitForSingleObject(modify_handle(invalid, 3), 0);
987 ok(ret == WAIT_FAILED, "expected WAIT_FAILED, got %d\n", ret);
988 ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
990 /* valid handle with different values for lower 2 bits */
991 SetLastError(0xdeadbeef);
992 ret = WaitForSingleObject(nonsignaled, 0);
993 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %d\n", ret);
994 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
996 SetLastError(0xdeadbeef);
997 ret = WaitForSingleObject(modify_handle(nonsignaled, 1), 0);
998 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %d\n", ret);
999 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1001 SetLastError(0xdeadbeef);
1002 ret = WaitForSingleObject(modify_handle(nonsignaled, 2), 0);
1003 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %d\n", ret);
1004 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1006 SetLastError(0xdeadbeef);
1007 ret = WaitForSingleObject(modify_handle(nonsignaled, 3), 0);
1008 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %d\n", ret);
1009 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1011 /* valid handle with different values for lower 2 bits */
1012 SetLastError(0xdeadbeef);
1013 ret = WaitForSingleObject(signaled, 0);
1014 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %d\n", ret);
1015 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1017 SetLastError(0xdeadbeef);
1018 ret = WaitForSingleObject(modify_handle(signaled, 1), 0);
1019 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %d\n", ret);
1020 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1022 SetLastError(0xdeadbeef);
1023 ret = WaitForSingleObject(modify_handle(signaled, 2), 0);
1024 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %d\n", ret);
1025 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1027 SetLastError(0xdeadbeef);
1028 ret = WaitForSingleObject(modify_handle(signaled, 3), 0);
1029 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %d\n", ret);
1030 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
1032 CloseHandle(signaled);
1033 CloseHandle(nonsignaled);
1036 static void test_WaitForMultipleObjects(void)
1038 DWORD r;
1039 int i;
1040 HANDLE maxevents[MAXIMUM_WAIT_OBJECTS];
1042 /* create the maximum number of events and make sure
1043 * we can wait on that many */
1044 for (i=0; i<MAXIMUM_WAIT_OBJECTS; i++)
1046 maxevents[i] = CreateEvent(NULL, i==0, TRUE, NULL);
1047 ok( maxevents[i] != 0, "should create enough events\n");
1050 /* a manual-reset event remains signaled, an auto-reset event is cleared */
1051 r = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, 0, 0);
1052 ok( r == WAIT_OBJECT_0, "should signal lowest handle first, got %d\n", r);
1053 r = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, 0, 0);
1054 ok( r == WAIT_OBJECT_0, "should signal handle #0 first, got %d\n", r);
1055 ok(ResetEvent(maxevents[0]), "ResetEvent\n");
1056 for (i=1; i<MAXIMUM_WAIT_OBJECTS; i++)
1058 /* the lowest index is checked first and remaining events are untouched */
1059 r = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, 0, 0);
1060 ok( r == WAIT_OBJECT_0+i, "should signal handle #%d first, got %d\n", i, r);
1063 for (i=0; i<MAXIMUM_WAIT_OBJECTS; i++)
1064 if (maxevents[i]) CloseHandle(maxevents[i]);
1067 START_TEST(sync)
1069 HMODULE hdll = GetModuleHandle("kernel32");
1070 pChangeTimerQueueTimer = (void*)GetProcAddress(hdll, "ChangeTimerQueueTimer");
1071 pCreateTimerQueue = (void*)GetProcAddress(hdll, "CreateTimerQueue");
1072 pCreateTimerQueueTimer = (void*)GetProcAddress(hdll, "CreateTimerQueueTimer");
1073 pCreateWaitableTimerA = (void*)GetProcAddress(hdll, "CreateWaitableTimerA");
1074 pDeleteTimerQueueEx = (void*)GetProcAddress(hdll, "DeleteTimerQueueEx");
1075 pDeleteTimerQueueTimer = (void*)GetProcAddress(hdll, "DeleteTimerQueueTimer");
1076 pOpenWaitableTimerA = (void*)GetProcAddress(hdll, "OpenWaitableTimerA");
1078 test_signalandwait();
1079 test_mutex();
1080 test_slist();
1081 test_event();
1082 test_semaphore();
1083 test_waitable_timer();
1084 test_iocp_callback();
1085 test_timer_queue();
1086 test_WaitForSingleObject();
1087 test_WaitForMultipleObjects();