1 /*
2 * Synchronization tests
3 *
4 * Copyright 2005 Mike McCormack for CodeWeavers
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include <stdarg.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <windef.h>
25 #define _WIN32_WINNT 0x500
26 #include <winbase.h>
27
28 #include "wine/test.h"
29
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);
38
39 static void test_signalandwait(void)
40 {
41 DWORD (WINAPI *pSignalObjectAndWait)(HANDLE, HANDLE, DWORD, BOOL);
42 HMODULE kernel32;
43 DWORD r;
44 int i;
45 HANDLE event[2], maxevents[MAXIMUM_WAIT_OBJECTS], semaphore[2], file;
46
47 kernel32 = GetModuleHandle("kernel32");
48 pSignalObjectAndWait = (void*) GetProcAddress(kernel32, "SignalObjectAndWait");
49
50 if (!pSignalObjectAndWait)
51 return;
52
53 /* invalid parameters */
54 r = pSignalObjectAndWait(NULL, NULL, 0, 0);
55 if (r == ERROR_INVALID_FUNCTION)
56 {
57 skip("SignalObjectAndWait is not implemented\n");
58 return; /* Win98/ME */
59 }
60 ok( r == WAIT_FAILED, "should fail\n");
61
62 event[0] = CreateEvent(NULL, 0, 0, NULL);
63 event[1] = CreateEvent(NULL, 1, 1, NULL);
64
65 ok( event[0] && event[1], "failed to create event flags\n");
66
67 r = pSignalObjectAndWait(event[0], NULL, 0, FALSE);
68 ok( r == WAIT_FAILED, "should fail\n");
69
70 r = pSignalObjectAndWait(NULL, event[0], 0, FALSE);
71 ok( r == WAIT_FAILED, "should fail\n");
72
73
74 /* valid parameters */
75 r = pSignalObjectAndWait(event[0], event[1], 0, FALSE);
76 ok( r == WAIT_OBJECT_0, "should succeed\n");
77
78 /* event[0] is now signalled */
79 r = pSignalObjectAndWait(event[0], event[0], 0, FALSE);
80 ok( r == WAIT_OBJECT_0, "should succeed\n");
81
82 /* event[0] is not signalled */
83 r = WaitForSingleObject(event[0], 0);
84 ok( r == WAIT_TIMEOUT, "event was signalled\n");
85
86 r = pSignalObjectAndWait(event[0], event[0], 0, FALSE);
87 ok( r == WAIT_OBJECT_0, "should succeed\n");
88
89 /* clear event[1] and check for a timeout */
90 ok(ResetEvent(event[1]), "failed to clear event[1]\n");
91 r = pSignalObjectAndWait(event[0], event[1], 0, FALSE);
92 ok( r == WAIT_TIMEOUT, "should timeout\n");
93
94 CloseHandle(event[0]);
95 CloseHandle(event[1]);
96
97 /* create the maximum number of events and make sure
98 * we can wait on that many */
99 for (i=0; i<MAXIMUM_WAIT_OBJECTS; i++)
100 {
101 maxevents[i] = CreateEvent(NULL, 1, 1, NULL);
102 ok( maxevents[i] != 0, "should create enough events\n");
103 }
104 r = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, 0, 0);
105 ok( r != WAIT_FAILED && r != WAIT_TIMEOUT, "should succeed\n");
106
107 for (i=0; i<MAXIMUM_WAIT_OBJECTS; i++)
108 if (maxevents[i]) CloseHandle(maxevents[i]);
109
110 /* semaphores */
111 semaphore[0] = CreateSemaphore( NULL, 0, 1, NULL );
112 semaphore[1] = CreateSemaphore( NULL, 1, 1, NULL );
113 ok( semaphore[0] && semaphore[1], "failed to create semaphore\n");
114
115 r = pSignalObjectAndWait(semaphore[0], semaphore[1], 0, FALSE);
116 ok( r == WAIT_OBJECT_0, "should succeed\n");
117
118 r = pSignalObjectAndWait(semaphore[0], semaphore[1], 0, FALSE);
119 ok( r == WAIT_FAILED, "should fail\n");
120
121 r = ReleaseSemaphore(semaphore[0],1,NULL);
122 ok( r == FALSE, "should fail\n");
123
124 r = ReleaseSemaphore(semaphore[1],1,NULL);
125 ok( r == TRUE, "should succeed\n");
126
127 CloseHandle(semaphore[0]);
128 CloseHandle(semaphore[1]);
129
130 /* try a registry key */
131 file = CreateFile("x", GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
132 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL);
133 r = pSignalObjectAndWait(file, file, 0, FALSE);
134 ok( r == WAIT_FAILED, "should fail\n");
135 ok( ERROR_INVALID_HANDLE == GetLastError(), "should return invalid handle error\n");
136 CloseHandle(file);
137 }
138
139 static void test_mutex(void)
140 {
141 DWORD wait_ret;
142 BOOL ret;
143 HANDLE hCreated;
144 HANDLE hOpened;
145
146 hCreated = CreateMutex(NULL, FALSE, "WineTestMutex");
147 ok(hCreated != NULL, "CreateMutex failed with error %d\n", GetLastError());
148 wait_ret = WaitForSingleObject(hCreated, INFINITE);
149 ok(wait_ret == WAIT_OBJECT_0, "WaitForSingleObject failed with error 0x%08x\n", wait_ret);
150
151 /* yes, opening with just READ_CONTROL access allows us to successfully
152 * call ReleaseMutex */
153 hOpened = OpenMutex(READ_CONTROL, FALSE, "WineTestMutex");
154 ok(hOpened != NULL, "OpenMutex failed with error %d\n", GetLastError());
155 ret = ReleaseMutex(hOpened);
156 todo_wine ok(ret, "ReleaseMutex failed with error %d\n", GetLastError());
157 ret = ReleaseMutex(hCreated);
158 todo_wine ok(!ret && (GetLastError() == ERROR_NOT_OWNER),
159 "ReleaseMutex should have failed with ERROR_NOT_OWNER instead of %d\n", GetLastError());
160
161 /* test case sensitivity */
162
163 SetLastError(0xdeadbeef);
164 hOpened = OpenMutex(READ_CONTROL, FALSE, "WINETESTMUTEX");
165 ok(!hOpened, "OpenMutex succeeded\n");
166 ok(GetLastError() == ERROR_FILE_NOT_FOUND ||
167 GetLastError() == ERROR_INVALID_NAME, /* win9x */
168 "wrong error %u\n", GetLastError());
169
170 SetLastError(0xdeadbeef);
171 hOpened = OpenMutex(READ_CONTROL, FALSE, "winetestmutex");
172 ok(!hOpened, "OpenMutex succeeded\n");
173 ok(GetLastError() == ERROR_FILE_NOT_FOUND ||
174 GetLastError() == ERROR_INVALID_NAME, /* win9x */
175 "wrong error %u\n", GetLastError());
176
177 SetLastError(0xdeadbeef);
178 hOpened = CreateMutex(NULL, FALSE, "WineTestMutex");
179 ok(hOpened != NULL, "CreateMutex failed with error %d\n", GetLastError());
180 ok(GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %u\n", GetLastError());
181 CloseHandle(hOpened);
182
183 SetLastError(0xdeadbeef);
184 hOpened = CreateMutex(NULL, FALSE, "WINETESTMUTEX");
185 ok(hOpened != NULL, "CreateMutex failed with error %d\n", GetLastError());
186 ok(GetLastError() == 0, "wrong error %u\n", GetLastError());
187 CloseHandle(hOpened);
188
189 CloseHandle(hCreated);
190 }
191
192 static void test_slist(void)
193 {
194 struct item
195 {
196 SLIST_ENTRY entry;
197 int value;
198 } item1, item2, item3, *pitem;
199
200 SLIST_HEADER slist_header, test_header;
201 PSLIST_ENTRY entry;
202 USHORT size;
203
204 VOID (WINAPI *pInitializeSListHead)(PSLIST_HEADER);
205 USHORT (WINAPI *pQueryDepthSList)(PSLIST_HEADER);
206 PSLIST_ENTRY (WINAPI *pInterlockedFlushSList)(PSLIST_HEADER);
207 PSLIST_ENTRY (WINAPI *pInterlockedPopEntrySList)(PSLIST_HEADER);
208 PSLIST_ENTRY (WINAPI *pInterlockedPushEntrySList)(PSLIST_HEADER,PSLIST_ENTRY);
209 HMODULE kernel32;
210
211 kernel32 = GetModuleHandle("KERNEL32.DLL");
212 pInitializeSListHead = (void*) GetProcAddress(kernel32, "InitializeSListHead");
213 pQueryDepthSList = (void*) GetProcAddress(kernel32, "QueryDepthSList");
214 pInterlockedFlushSList = (void*) GetProcAddress(kernel32, "InterlockedFlushSList");
215 pInterlockedPopEntrySList = (void*) GetProcAddress(kernel32, "InterlockedPopEntrySList");
216 pInterlockedPushEntrySList = (void*) GetProcAddress(kernel32, "InterlockedPushEntrySList");
217 if (pInitializeSListHead == NULL ||
218 pQueryDepthSList == NULL ||
219 pInterlockedFlushSList == NULL ||
220 pInterlockedPopEntrySList == NULL ||
221 pInterlockedPushEntrySList == NULL)
222 {
223 skip("some required slist entrypoints were not found, skipping tests\n");
224 return;
225 }
226
227 memset(&test_header, 0, sizeof(test_header));
228 memset(&slist_header, 0xFF, sizeof(slist_header));
229 pInitializeSListHead(&slist_header);
230 ok(memcmp(&test_header, &slist_header, sizeof(SLIST_HEADER)) == 0,
231 "InitializeSListHead didn't zero-fill list header\n");
232 size = pQueryDepthSList(&slist_header);
233 ok(size == 0, "initially created slist has size %d, expected 0\n", size);
234
235 item1.value = 1;
236 ok(pInterlockedPushEntrySList(&slist_header, &item1.entry) == NULL,
237 "previous entry in empty slist wasn't NULL\n");
238 size = pQueryDepthSList(&slist_header);
239 ok(size == 1, "slist with 1 item has size %d\n", size);
240
241 item2.value = 2;
242 entry = pInterlockedPushEntrySList(&slist_header, &item2.entry);
243 ok(entry != NULL, "previous entry in non-empty slist was NULL\n");
244 if (entry != NULL)
245 {
246 pitem = (struct item*) entry;
247 ok(pitem->value == 1, "previous entry in slist wasn't the one added\n");
248 }
249 size = pQueryDepthSList(&slist_header);
250 ok(size == 2, "slist with 2 items has size %d\n", size);
251
252 item3.value = 3;
253 entry = pInterlockedPushEntrySList(&slist_header, &item3.entry);
254 ok(entry != NULL, "previous entry in non-empty slist was NULL\n");
255 if (entry != NULL)
256 {
257 pitem = (struct item*) entry;
258 ok(pitem->value == 2, "previous entry in slist wasn't the one added\n");
259 }
260 size = pQueryDepthSList(&slist_header);
261 ok(size == 3, "slist with 3 items has size %d\n", size);
262
263 entry = pInterlockedPopEntrySList(&slist_header);
264 ok(entry != NULL, "entry shouldn't be NULL\n");
265 if (entry != NULL)
266 {
267 pitem = (struct item*) entry;
268 ok(pitem->value == 3, "unexpected entry removed\n");
269 }
270 size = pQueryDepthSList(&slist_header);
271 ok(size == 2, "slist with 2 items has size %d\n", size);
272
273 entry = pInterlockedFlushSList(&slist_header);
274 size = pQueryDepthSList(&slist_header);
275 ok(size == 0, "flushed slist should be empty, size is %d\n", size);
276 if (size == 0)
277 {
278 ok(pInterlockedPopEntrySList(&slist_header) == NULL,
279 "popping empty slist didn't return NULL\n");
280 }
281 ok(((struct item*)entry)->value == 2, "item 2 not in front of list\n");
282 ok(((struct item*)entry->Next)->value == 1, "item 1 not at the back of list\n");
283 }
284
285 static void test_event(void)
286 {
287 HANDLE handle, handle2;
288 SECURITY_ATTRIBUTES sa;
289 SECURITY_DESCRIPTOR sd;
290 ACL acl;
291
292 /* no sd */
293 handle = CreateEventA(NULL, FALSE, FALSE, __FILE__ ": Test Event");
294 ok(handle != NULL, "CreateEventW with blank sd failed with error %d\n", GetLastError());
295 CloseHandle(handle);
296
297 sa.nLength = sizeof(sa);
298 sa.lpSecurityDescriptor = &sd;
299 sa.bInheritHandle = FALSE;
300
301 InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
302
303 /* blank sd */
304 handle = CreateEventA(&sa, FALSE, FALSE, __FILE__ ": Test Event");
305 ok(handle != NULL, "CreateEventW with blank sd failed with error %d\n", GetLastError());
306 CloseHandle(handle);
307
308 /* sd with NULL dacl */
309 SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
310 handle = CreateEventA(&sa, FALSE, FALSE, __FILE__ ": Test Event");
311 ok(handle != NULL, "CreateEventW with blank sd failed with error %d\n", GetLastError());
312 CloseHandle(handle);
313
314 /* sd with empty dacl */
315 InitializeAcl(&acl, sizeof(acl), ACL_REVISION);
316 SetSecurityDescriptorDacl(&sd, TRUE, &acl, FALSE);
317 handle = CreateEventA(&sa, FALSE, FALSE, __FILE__ ": Test Event");
318 ok(handle != NULL, "CreateEventW with blank sd failed with error %d\n", GetLastError());
319 CloseHandle(handle);
320
321 /* test case sensitivity */
322
323 SetLastError(0xdeadbeef);
324 handle = CreateEventA(NULL, FALSE, FALSE, __FILE__ ": Test Event");
325 ok( handle != NULL, "CreateEvent failed with error %u\n", GetLastError());
326 ok( GetLastError() == 0, "wrong error %u\n", GetLastError());
327
328 SetLastError(0xdeadbeef);
329 handle2 = CreateEventA(NULL, FALSE, FALSE, __FILE__ ": Test Event");
330 ok( handle2 != NULL, "CreateEvent failed with error %d\n", GetLastError());
331 ok( GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %u\n", GetLastError());
332 CloseHandle( handle2 );
333
334 SetLastError(0xdeadbeef);
335 handle2 = CreateEventA(NULL, FALSE, FALSE, __FILE__ ": TEST EVENT");
336 ok( handle2 != NULL, "CreateEvent failed with error %d\n", GetLastError());
337 ok( GetLastError() == 0, "wrong error %u\n", GetLastError());
338 CloseHandle( handle2 );
339
340 SetLastError(0xdeadbeef);
341 handle2 = OpenEventA( EVENT_ALL_ACCESS, FALSE, __FILE__ ": Test Event");
342 ok( handle2 != NULL, "OpenEvent failed with error %d\n", GetLastError());
343 CloseHandle( handle2 );
344
345 SetLastError(0xdeadbeef);
346 handle2 = OpenEventA( EVENT_ALL_ACCESS, FALSE, __FILE__ ": TEST EVENT");
347 ok( !handle2, "OpenEvent succeeded\n");
348 ok( GetLastError() == ERROR_FILE_NOT_FOUND ||
349 GetLastError() == ERROR_INVALID_NAME, /* win9x */
350 "wrong error %u\n", GetLastError());
351
352 CloseHandle( handle );
353 }
354
355 static void test_semaphore(void)
356 {
357 HANDLE handle, handle2;
358
359 /* test case sensitivity */
360
361 SetLastError(0xdeadbeef);
362 handle = CreateSemaphoreA(NULL, 0, 1, __FILE__ ": Test Semaphore");
363 ok(handle != NULL, "CreateSemaphore failed with error %u\n", GetLastError());
364 ok(GetLastError() == 0, "wrong error %u\n", GetLastError());
365
366 SetLastError(0xdeadbeef);
367 handle2 = CreateSemaphoreA(NULL, 0, 1, __FILE__ ": Test Semaphore");
368 ok( handle2 != NULL, "CreateSemaphore failed with error %d\n", GetLastError());
369 ok( GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %u\n", GetLastError());
370 CloseHandle( handle2 );
371
372 SetLastError(0xdeadbeef);
373 handle2 = CreateSemaphoreA(NULL, 0, 1, __FILE__ ": TEST SEMAPHORE");
374 ok( handle2 != NULL, "CreateSemaphore failed with error %d\n", GetLastError());
375 ok( GetLastError() == 0, "wrong error %u\n", GetLastError());
376 CloseHandle( handle2 );
377
378 SetLastError(0xdeadbeef);
379 handle2 = OpenSemaphoreA( SEMAPHORE_ALL_ACCESS, FALSE, __FILE__ ": Test Semaphore");
380 ok( handle2 != NULL, "OpenSemaphore failed with error %d\n", GetLastError());
381 CloseHandle( handle2 );
382
383 SetLastError(0xdeadbeef);
384 handle2 = OpenSemaphoreA( SEMAPHORE_ALL_ACCESS, FALSE, __FILE__ ": TEST SEMAPHORE");
385 ok( !handle2, "OpenSemaphore succeeded\n");
386 ok( GetLastError() == ERROR_FILE_NOT_FOUND ||
387 GetLastError() == ERROR_INVALID_NAME, /* win9x */
388 "wrong error %u\n", GetLastError());
389
390 CloseHandle( handle );
391 }
392
393 static void test_waitable_timer(void)
394 {
395 HANDLE handle, handle2;
396
397 if (!pCreateWaitableTimerA || !pOpenWaitableTimerA)
398 {
399 skip("{Create,Open}WaitableTimerA() is not available\n");
400 return;
401 }
402
403 /* test case sensitivity */
404
405 SetLastError(0xdeadbeef);
406 handle = pCreateWaitableTimerA(NULL, FALSE, __FILE__ ": Test WaitableTimer");
407 ok(handle != NULL, "CreateWaitableTimer failed with error %u\n", GetLastError());
408 ok(GetLastError() == 0, "wrong error %u\n", GetLastError());
409
410 SetLastError(0xdeadbeef);
411 handle2 = pCreateWaitableTimerA(NULL, FALSE, __FILE__ ": Test WaitableTimer");
412 ok( handle2 != NULL, "CreateWaitableTimer failed with error %d\n", GetLastError());
413 ok( GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %u\n", GetLastError());
414 CloseHandle( handle2 );
415
416 SetLastError(0xdeadbeef);
417 handle2 = pCreateWaitableTimerA(NULL, FALSE, __FILE__ ": TEST WAITABLETIMER");
418 ok( handle2 != NULL, "CreateWaitableTimer failed with error %d\n", GetLastError());
419 ok( GetLastError() == 0, "wrong error %u\n", GetLastError());
420 CloseHandle( handle2 );
421
422 SetLastError(0xdeadbeef);
423 handle2 = pOpenWaitableTimerA( TIMER_ALL_ACCESS, FALSE, __FILE__ ": Test WaitableTimer");
424 ok( handle2 != NULL, "OpenWaitableTimer failed with error %d\n", GetLastError());
425 CloseHandle( handle2 );
426
427 SetLastError(0xdeadbeef);
428 handle2 = pOpenWaitableTimerA( TIMER_ALL_ACCESS, FALSE, __FILE__ ": TEST WAITABLETIMER");
429 ok( !handle2, "OpenWaitableTimer succeeded\n");
430 ok( GetLastError() == ERROR_FILE_NOT_FOUND ||
431 GetLastError() == ERROR_INVALID_NAME, /* win98 */
432 "wrong error %u\n", GetLastError());
433
434 CloseHandle( handle );
435 }
436
437 static HANDLE sem = 0;
438
439 static void CALLBACK iocp_callback(DWORD dwErrorCode, DWORD dwNumberOfBytesTransferred, LPOVERLAPPED lpOverlapped)
440 {
441 ReleaseSemaphore(sem, 1, NULL);
442 }
443
444 static BOOL (WINAPI *p_BindIoCompletionCallback)( HANDLE FileHandle, LPOVERLAPPED_COMPLETION_ROUTINE Function, ULONG Flags) = NULL;
445
446 static void test_iocp_callback(void)
447 {
448 char temp_path[MAX_PATH];
449 char filename[MAX_PATH];
450 DWORD ret;
451 BOOL retb;
452 static const char prefix[] = "pfx";
453 HANDLE hFile;
454 HMODULE hmod = GetModuleHandleA("kernel32.dll");
455 DWORD bytesWritten;
456 const char *buffer = "12345678123456781234567812345678";
457 OVERLAPPED overlapped;
458
459 p_BindIoCompletionCallback = (void*)GetProcAddress(hmod, "BindIoCompletionCallback");
460 if(!p_BindIoCompletionCallback) {
461 skip("BindIoCompletionCallback not found in this DLL\n");
462 return;
463 }
464
465 sem = CreateSemaphore(NULL, 0, 1, NULL);
466 ok(sem != INVALID_HANDLE_VALUE, "Creating a semaphore failed\n");
467
468 ret = GetTempPathA(MAX_PATH, temp_path);
469 ok(ret != 0, "GetTempPathA error %d\n", GetLastError());
470 ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n");
471
472 ret = GetTempFileNameA(temp_path, prefix, 0, filename);
473 ok(ret != 0, "GetTempFileNameA error %d\n", GetLastError());
474
475 hFile = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
476 CREATE_ALWAYS, FILE_FLAG_RANDOM_ACCESS, 0);
477 ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA: error %d\n", GetLastError());
478
479 retb = p_BindIoCompletionCallback(hFile, iocp_callback, 0);
480 ok(retb == FALSE, "BindIoCompletionCallback succeeded on a file that wasn't created with FILE_FLAG_OVERLAPPED\n");
481 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error is %d\n", GetLastError());
482
483 ret = CloseHandle(hFile);
484 ok( ret, "CloseHandle: error %d\n", GetLastError());
485 ret = DeleteFileA(filename);
486 ok( ret, "DeleteFileA: error %d\n", GetLastError());
487
488 hFile = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
489 CREATE_ALWAYS, FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_OVERLAPPED, 0);
490 ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA: error %d\n", GetLastError());
491
492 retb = p_BindIoCompletionCallback(hFile, iocp_callback, 0);
493 ok(retb == TRUE, "BindIoCompletionCallback failed\n");
494
495 memset(&overlapped, 0, sizeof(overlapped));
496 retb = WriteFile(hFile, (const void *) buffer, 4, &bytesWritten, &overlapped);
497 ok(retb == TRUE || GetLastError() == ERROR_IO_PENDING, "WriteFile failed, lastError = %d\n", GetLastError());
498
499 ret = WaitForSingleObject(sem, 5000);
500 ok(ret == WAIT_OBJECT_0, "Wait for the IO completion callback failed\n");
501 CloseHandle(sem);
502
503 retb = p_BindIoCompletionCallback(hFile, iocp_callback, 0);
504 ok(retb == FALSE, "BindIoCompletionCallback succeeded when setting the same callback on the file again\n");
505 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error is %d\n", GetLastError());
506 retb = p_BindIoCompletionCallback(hFile, NULL, 0);
507 ok(retb == FALSE, "BindIoCompletionCallback succeeded when setting the callback to NULL\n");
508 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error is %d\n", GetLastError());
509
510 ret = CloseHandle(hFile);
511 ok( ret, "CloseHandle: error %d\n", GetLastError());
512 ret = DeleteFileA(filename);
513 ok( ret, "DeleteFileA: error %d\n", GetLastError());
514
515 hFile = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
516 CREATE_ALWAYS, FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_OVERLAPPED, 0);
517 ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA: error %d\n", GetLastError());
518 retb = p_BindIoCompletionCallback(hFile, NULL, 0);
519 ok(retb == TRUE, "BindIoCompletionCallback failed with a NULL callback(first time set)\n");
520 ret = CloseHandle(hFile);
521 ok( ret, "CloseHandle: error %d\n", GetLastError());
522 ret = DeleteFileA(filename);
523 ok( ret, "DeleteFileA: error %d\n", GetLastError());
524
525 /* win2k3 requires the Flags parameter to be zero */
526 SetLastError(0xdeadbeef);
527 hFile = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
528 CREATE_ALWAYS, FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_OVERLAPPED, 0);
529 ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA: error %d\n", GetLastError());
530 retb = p_BindIoCompletionCallback(hFile, iocp_callback, 12345);
531 if (!retb)
532 ok(GetLastError() == ERROR_INVALID_PARAMETER,
533 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
534 else
535 ok(retb == TRUE, "BindIoCompletionCallback failed with Flags != 0\n");
536 ret = CloseHandle(hFile);
537 ok( ret, "CloseHandle: error %d\n", GetLastError());
538 ret = DeleteFileA(filename);
539 ok( ret, "DeleteFileA: error %d\n", GetLastError());
540
541 retb = p_BindIoCompletionCallback(NULL, iocp_callback, 0);
542 ok(retb == FALSE, "BindIoCompletionCallback succeeded on a NULL file\n");
543 ok(GetLastError() == ERROR_INVALID_HANDLE, "Last error is %d\n", GetLastError());
544 }
545
546 static void CALLBACK timer_queue_cb1(PVOID p, BOOLEAN timedOut)
547 {
548 int *pn = (int *) p;
549 ok(timedOut, "Timer callbacks should always time out\n");
550 ++*pn;
551 }
552
553 struct timer_queue_data1
554 {
555 int num_calls;
556 int max_calls;
557 HANDLE q, t;
558 };
559
560 static void CALLBACK timer_queue_cb2(PVOID p, BOOLEAN timedOut)
561 {
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)
565 {
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");
573 }
574 }
575
576 static void CALLBACK timer_queue_cb3(PVOID p, BOOLEAN timedOut)
577 {
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)
581 {
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");
586 }
587 }
588
589 static void CALLBACK timer_queue_cb4(PVOID p, BOOLEAN timedOut)
590 {
591 struct timer_queue_data1 *d = p;
592 ok(timedOut, "Timer callbacks should always time out\n");
593 if (d->t)
594 {
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;
603 }
604 }
605
606 static void CALLBACK timer_queue_cb5(PVOID p, BOOLEAN timedOut)
607 {
608 DWORD delay = (DWORD) p;
609 ok(timedOut, "Timer callbacks should always time out\n");
610 if (delay)
611 Sleep(delay);
612 }
613
614 static void CALLBACK timer_queue_cb6(PVOID p, BOOLEAN timedOut)
615 {
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)
621 {
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;
629
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");
635
636 ret = pCreateTimerQueueTimer(&t, d->q, timer_queue_cb1, NULL, 100, 0, 0);
637 ok(ret, "CreateTimerQueueTimer\n");
638 ok(t != NULL, "CreateTimerQueueTimer\n");
639
640 ret = pDeleteTimerQueueTimer(d->q, t, INVALID_HANDLE_VALUE);
641 ok(ret, "DeleteTimerQueueTimer\n");
642
643 /* Now we stay alive by hanging around in the callback. */
644 Sleep(500);
645 }
646 }
647
648 static void test_timer_queue(void)
649 {
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;
655
656 if (!pChangeTimerQueueTimer || !pCreateTimerQueue || !pCreateTimerQueueTimer
657 || !pDeleteTimerQueueEx || !pDeleteTimerQueueTimer)
658 {
659 skip("TimerQueue API not present\n");
660 return;
661 }
662
663 /* Test asynchronous deletion of the queue. */
664 q = pCreateTimerQueue();
665 ok(q != NULL, "CreateTimerQueue\n");
666
667 SetLastError(0xdeadbeef);
668 ret = pDeleteTimerQueueEx(q, NULL);
669 ok(!ret, "DeleteTimerQueueEx\n");
670 ok(GetLastError() == ERROR_IO_PENDING, "DeleteTimerQueueEx\n");
671
672 /* Test synchronous deletion of the queue and running timers. */
673 q = pCreateTimerQueue();
674 ok(q != NULL, "CreateTimerQueue\n");
675
676 /* Called once. */
677 t1 = NULL;
678 n1 = 0;
679 ret = pCreateTimerQueueTimer(&t1, q, timer_queue_cb1, &n1, 0,
680 0, 0);
681 ok(ret, "CreateTimerQueueTimer\n");
682 ok(t1 != NULL, "CreateTimerQueueTimer\n");
683
684 /* A slow one. */
685 t2 = NULL;
686 n2 = 0;
687 ret = pCreateTimerQueueTimer(&t2, q, timer_queue_cb1, &n2, 0,
688 100, 0);
689 ok(ret, "CreateTimerQueueTimer\n");
690 ok(t2 != NULL, "CreateTimerQueueTimer\n");
691
692 /* A fast one. */
693 t3 = NULL;
694 n3 = 0;
695 ret = pCreateTimerQueueTimer(&t3, q, timer_queue_cb1, &n3, 0,
696 10, 0);
697 ok(ret, "CreateTimerQueueTimer\n");
698 ok(t3 != NULL, "CreateTimerQueueTimer\n");
699
700 /* Start really late (it won't start). */
701 t4 = NULL;
702 n4 = 0;
703 ret = pCreateTimerQueueTimer(&t4, q, timer_queue_cb1, &n4, 10000,
704 10, 0);
705 ok(ret, "CreateTimerQueueTimer\n");
706 ok(t4 != NULL, "CreateTimerQueueTimer\n");
707
708 /* Start soon, but delay so long it won't run again. */
709 t5 = NULL;
710 n5 = 0;
711 ret = pCreateTimerQueueTimer(&t5, q, timer_queue_cb1, &n5, 0,
712 10000, 0);
713 ok(ret, "CreateTimerQueueTimer\n");
714 ok(t5 != NULL, "CreateTimerQueueTimer\n");
715
716 /* Give them a chance to do some work. */
717 Sleep(500);
718
719 /* Test deleting a once-only timer. */
720 ret = pDeleteTimerQueueTimer(q, t1, INVALID_HANDLE_VALUE);
721 ok(ret, "DeleteTimerQueueTimer\n");
722
723 /* A periodic timer. */
724 ret = pDeleteTimerQueueTimer(q, t2, INVALID_HANDLE_VALUE);
725 ok(ret, "DeleteTimerQueueTimer\n");
726
727 ret = pDeleteTimerQueueEx(q, INVALID_HANDLE_VALUE);
728 ok(ret, "DeleteTimerQueueEx\n");
729 ok(n1 == 1, "Timer callback 1\n");
730 ok(n2 < n3, "Timer callback 2 should be much slower than 3\n");
731 ok(n4 == 0, "Timer callback 4\n");
732 ok(n5 == 1, "Timer callback 5\n");
733
734 /* Test synchronous deletion of the timer/queue with event trigger. */
735 e = CreateEvent(NULL, TRUE, FALSE, NULL);
736 et1 = CreateEvent(NULL, TRUE, FALSE, NULL);
737 et2 = CreateEvent(NULL, TRUE, FALSE, NULL);
738 if (!e || !et1 || !et2)
739 {
740 skip("Failed to create timer queue descruction event\n");
741 return;
742 }
743
744 q = pCreateTimerQueue();
745 ok(q != NULL, "CreateTimerQueue\n");
746
747 /* Run once and finish quickly (should be done when we delete it). */
748 t1 = NULL;
749 ret = pCreateTimerQueueTimer(&t1, q, timer_queue_cb5, (PVOID) 0, 0,
750 0, 0);
751 ok(ret, "CreateTimerQueueTimer\n");
752 ok(t1 != NULL, "CreateTimerQueueTimer\n");
753
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");
760
761 /* Run once and finish quickly (should be done when we delete it). */
762 t3 = NULL;
763 ret = pCreateTimerQueueTimer(&t3, q, timer_queue_cb5, (PVOID) 0, 0,
764 0, 0);
765 ok(ret, "CreateTimerQueueTimer\n");
766 ok(t3 != NULL, "CreateTimerQueueTimer\n");
767
768 /* Run once and finish slowly (shouldn't be done when we delete it). */
769 t4 = NULL;
770 ret = pCreateTimerQueueTimer(&t4, q, timer_queue_cb5, (PVOID) 1000, 0,
771 0, 0);
772 ok(ret, "CreateTimerQueueTimer\n");
773 ok(t4 != NULL, "CreateTimerQueueTimer\n");
774
775 /* Give them a chance to start. */
776 Sleep(400);
777
778 /* DeleteTimerQueueTimer always returns PENDING with a NULL event,
779 even if the timer is finished. */
780 SetLastError(0xdeadbeef);
781 ret = pDeleteTimerQueueTimer(q, t1, NULL);
782 ok(!ret, "DeleteTimerQueueTimer\n");
783 ok(GetLastError() == ERROR_IO_PENDING, "DeleteTimerQueueTimer\n");
784
785 SetLastError(0xdeadbeef);
786 ret = pDeleteTimerQueueTimer(q, t2, NULL);
787 ok(!ret, "DeleteTimerQueueTimer\n");
788 ok(GetLastError() == ERROR_IO_PENDING, "DeleteTimerQueueTimer\n");
789
790 SetLastError(0xdeadbeef);
791 ret = pDeleteTimerQueueTimer(q, t3, et1);
792 ok(ret, "DeleteTimerQueueTimer\n");
793 ok(GetLastError() == 0xdeadbeef, "DeleteTimerQueueTimer\n");
794 ok(WaitForSingleObject(et1, 250) =