1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5/*============================================================
6**
7** Source: test6.c
8**
9** Purpose: Test for WaitForMultipleObjectsEx in multiple
10** scenarios
11**
12**
13**=========================================================*/
14
15#include <palsuite.h>
16
17#define MAX_COUNT 10000
18#define MAX_THREADS 256
19
20BOOL g_bMutex = 0;
21BOOL g_bEvent = 0;
22BOOL g_bNamedEvent = 0;
23BOOL g_bSemaphore = 0;
24BOOL g_bProcess = 0;
25BOOL g_bLocalWaitAll = 0;
26BOOL g_bRemoteWaitAll = 0;
27BOOL g_bRandom = 0;
28
29int iCount = 1;
30int iThreads = 1;
31HANDLE hThreads[MAX_THREADS];
32
33#ifndef MIN
34#define MIN(a,b) (((a)<(b)) ? (a) : (b))
35#endif
36
37DWORD PALAPI EventTestThread(PVOID pArg)
38{
39 BOOL bRet;
40 DWORD dwRet;
41 HANDLE hEvent[2];
42 HANDLE (*prgHandles)[] = (HANDLE (*)[])pArg;
43
44 Trace("[EventTestThread] Starting\n");
45
46 bRet = DuplicateHandle(GetCurrentProcess(), (*prgHandles)[0], GetCurrentProcess(),
47 &hEvent[0], 0, FALSE, DUPLICATE_SAME_ACCESS);
48 bRet &= DuplicateHandle(GetCurrentProcess(), (*prgHandles)[1], GetCurrentProcess(),
49 &hEvent[1], 0, FALSE, DUPLICATE_SAME_ACCESS);
50 if (FALSE == bRet)
51 {
52 Fail("[EventTestThread] Failed to duplicate handles\n");
53 }
54
55 Sleep(1000);
56 bRet = SetEvent(hEvent[1]);
57 if (FALSE == bRet)
58 {
59 Fail("SetEvent failed\n");
60 Fail("[EventTestThread] SetEvent failed [GetLastError()=%u]\n",
61 GetLastError());
62 }
63
64 dwRet = WaitForSingleObject(hEvent[1], INFINITE);
65 if (WAIT_FAILED == dwRet)
66 {
67 Fail("[EventTestThread] WaitForMultipleObjects failed [GetLastError()=%u]\n",
68 GetLastError());
69 }
70
71 Sleep(1000);
72 bRet = SetEvent(hEvent[0]);
73 if (FALSE == bRet)
74 {
75 Fail("[EventTestThread] SetEvent failed [GetLastError()=%u]\n",
76 GetLastError());
77 }
78
79 Sleep(1000);
80 bRet = SetEvent(hEvent[1]);
81 if (FALSE == bRet)
82 {
83 Fail("[EventTestThread] SetEvent failed [GetLastError()=%u]\n",
84 GetLastError());
85 }
86
87 CloseHandle(hEvent[0]);
88 CloseHandle(hEvent[1]);
89
90 Trace("[EventTestThread] Done\n");
91 return 0;
92}
93
94DWORD PALAPI MutexTestThread(PVOID pArg)
95{
96 BOOL bRet;
97 DWORD dwRet;
98 HANDLE hMutex;
99
100 Trace("[MutexTestThread] Starting\n");
101
102 bRet = DuplicateHandle(GetCurrentProcess(), (HANDLE)pArg, GetCurrentProcess(), &hMutex,
103 0, FALSE, DUPLICATE_SAME_ACCESS);
104 if (FALSE == bRet)
105 {
106 Fail("[EventTestThread] DuplicateHandle failed [GetLastError()=%u]\n",
107 GetLastError());
108 }
109
110 dwRet = WaitForSingleObject(hMutex, INFINITE);
111 if (WAIT_FAILED == dwRet)
112 {
113 Fail("[EventTestThread] WaitForMultipleObjects failed [GetLastError()=%u]\n",
114 GetLastError());
115 }
116
117 Sleep(1000);
118 CloseHandle(hMutex);
119
120 Trace("[MutexTestThread] Done\n");
121
122 return 0;
123}
124
125DWORD PALAPI TestThread(PVOID pArg)
126{
127 BOOL bRet;
128 DWORD dwRet;
129 PROCESS_INFORMATION pi;
130 STARTUPINFO si;
131 HANDLE hNamedEvent;
132 HANDLE hEvent[2] = { 0, 0 };
133 HANDLE hMutex = 0;
134 HANDLE hSemaphore = 0;
135 HANDLE hObjs[2];
136 DWORD dwThreadNum;
137 DWORD dwSlaveThreadTid = 0;
138 HANDLE hThread;
139 int i, iCnt, iRet;
140 char szTestName[128];
141 char szCmd[128];
142 char szEventName[128] = { 0 };
143 char szMutexName[128] = { 0 };
144 char szSemName[128] = { 0 };
145 WCHAR wszEventName[128] = { 0 };
146 WCHAR wszMutexName[128] = { 0 };
147 WCHAR wszSemName[128] = { 0 };
148 BOOL bMutex = g_bMutex;
149 BOOL bEvent = g_bEvent;
150 BOOL bNamedEvent = g_bNamedEvent;
151 BOOL bSemaphore = g_bSemaphore;
152 BOOL bProcess = g_bProcess;
153 BOOL bLocalWaitAll = g_bLocalWaitAll;
154 BOOL bRemoteWaitAll = g_bRemoteWaitAll;
155 int iDesiredExitCode;
156
157 dwThreadNum = (DWORD)pArg;
158
159 sprintf_s (szTestName, 128, "Test6_%u", dwThreadNum);
160 szTestName[127] = 0;
161
162 sprintf_s(szEventName, 128, "%s_Event", szTestName);
163 szEventName[127] = 0;
164 sprintf_s(szMutexName, 128, "%s_Mutex", szTestName);
165 szMutexName[127] = 0;
166 sprintf_s(szSemName, 128, "%s_Semaphore", szTestName);
167 szSemName[127] = 0;
168
169 iRet = MultiByteToWideChar(CP_ACP, 0, szEventName, strlen(szEventName)+1, wszEventName, 128);
170 iRet &= MultiByteToWideChar(CP_ACP, 0, szMutexName, strlen(szMutexName)+1, wszMutexName, 128);
171 iRet &= MultiByteToWideChar(CP_ACP, 0, szSemName, strlen(szSemName)+1, wszSemName, 128);
172
173 if (0 == iRet)
174 {
175 Fail("[TestThread] Failed to convert strings\n");
176 }
177
178 Trace("[TestThread] TestName=%s Event: %S, Mutex: %S, Semaphore = %S\n",
179 szTestName, wszEventName, wszMutexName, wszSemName);
180
181 hEvent[0] = CreateEventA(NULL, FALSE, FALSE, NULL);
182 hEvent[1] = CreateEventA(NULL, FALSE, FALSE, NULL);
183
184 hNamedEvent = CreateEventW(NULL, FALSE, FALSE, wszEventName);
185 hMutex = CreateMutexW(NULL, FALSE, wszMutexName);
186 hSemaphore = CreateSemaphoreW(NULL, 0, 256, wszSemName);
187
188 if (NULL == hEvent[0] || NULL == hEvent[1] || NULL == hMutex ||
189 NULL == hNamedEvent || NULL == hSemaphore)
190 {
191 Fail("[TestThread] Failed to create objects "
192 "[hNamedEvent=%p hMutex=%p hSemaphore=%p]\n",
193 (VOID*)hNamedEvent, (VOID*)hMutex, (VOID*)hSemaphore);
194 }
195
196 for (iCnt=0; iCnt<iCount; iCnt++)
197 {
198 if (g_bRandom)
199 {
200 int iRnd;
201
202 bMutex = 0;
203 bEvent = 0;
204 bNamedEvent = 0;
205 bSemaphore = 0;
206 bProcess = 0;
207 bLocalWaitAll = 0;
208 bRemoteWaitAll = 0;
209
210 iRnd = rand() % 7;
211 switch(iRnd)
212 {
213 case 0:
214 bMutex = 1;
215 break;
216 case 1:
217 bEvent = 1;
218 break;
219 case 2:
220 bNamedEvent = 1;
221 break;
222 case 3:
223 bSemaphore = 1;
224 break;
225 case 4:
226 bProcess = 1;
227 break;
228 case 5:
229 bLocalWaitAll = 1;
230 break;
231 case 6:
232 bRemoteWaitAll = 1;
233 break;
234 }
235 }
236
237 if (bEvent)
238 {
239 Trace("======================================================================\n");
240 Trace("Local unnamed event test\n");
241 Trace("----------------------------------------\n");
242 hThread = CreateThread(NULL, 0, EventTestThread, (PVOID)hEvent, 0, &dwSlaveThreadTid);
243 if (NULL == hThread)
244 {
245 Fail("Failed to create thread\n");
246 }
247
248 hObjs[0] = hEvent[0];
249 dwRet = WaitForMultipleObjects(1, hObjs, FALSE, INFINITE);
250 if (WAIT_FAILED == dwRet)
251 {
252 Fail("WaitForMultipleObjects failed\n");
253 }
254
255 hObjs[0] = hThread;
256 dwRet = WaitForMultipleObjects(1, hObjs, FALSE, INFINITE);
257 if (WAIT_FAILED == dwRet)
258 {
259 Fail("WaitForMultipleObjects failed\n");
260 }
261
262 CloseHandle(hThread);
263 Trace("Local unnamed event test done \n");
264 Trace("======================================================================\n");
265 }
266
267 if (bMutex)
268 {
269 Trace("======================================================================\n");
270 Trace("Mutex with remote thread awakening test\n");
271 Trace("----------------------------------------\n");
272
273 hThread = CreateThread(NULL, 0, MutexTestThread, (PVOID)hMutex, 0, &dwSlaveThreadTid);
274 if (NULL == hThread)
275 {
276 Fail("Failed to create thread\n");
277 }
278
279 Sleep(1000);
280
281 hObjs[0] = hMutex;
282
283 for (i=0;i<10;i++)
284 {
285 dwRet = WaitForMultipleObjects(1, hObjs, FALSE, INFINITE);
286 if (WAIT_FAILED == dwRet)
287 {
288 Fail("WaitForMultipleObjects failed [dwRet=%x GetLastError()=%d\n",
289 dwRet, GetLastError());
290 }
291 }
292
293 hObjs[0] = hThread;
294 dwRet = WaitForMultipleObjects(1, hObjs, FALSE, INFINITE);
295 if (WAIT_FAILED == dwRet)
296 {
297 Fail("WaitForMultipleObjects failed [GetLastError()=%u]\n",
298 GetLastError());
299 }
300
301 for (i=0;i<10;i++)
302 {
303 bRet = ReleaseMutex(hMutex);
304 if (FALSE == bRet)
305 {
306 Fail("ReleaseMutex failed [GetLastError()=%u]\n",
307 GetLastError());
308 }
309 }
310
311 CloseHandle(hThread);
312 Trace("Mutex with remote thread awakening test done\n");
313 Trace("======================================================================\n");
314 }
315
316 if (bNamedEvent)
317 {
318 Trace("======================================================================\n");
319 Trace("Named event with remote thread awakening test\n");
320 Trace("----------------------------------------\n");
321
322 ZeroMemory ( &si, sizeof(si) );
323 si.cb = sizeof(si);
324 ZeroMemory ( &pi, sizeof(pi) );
325
326 sprintf_s (szCmd, 128, "child6 -event %s", szTestName);
327 szCmd[127] = 0;
328
329 bRet = CreateProcessA(NULL, szCmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
330 if (FALSE == bRet)
331 {
332 Fail("CreateProcess failed [GetLastError()=%u]\n",
333 GetLastError());
334 }
335
336 hObjs[0] = pi.hProcess;
337 hObjs[1] = hNamedEvent;
338
339 dwRet = WaitForMultipleObjects(2, hObjs, FALSE, INFINITE);
340 if (1 != dwRet)
341 {
342 Fail("WaitForMultipleObjects failed [dwRet=%u GetLastError()=%u]\n",
343 dwRet, GetLastError());
344 }
345
346 dwRet = WaitForSingleObject(pi.hProcess, INFINITE);
347 if (WAIT_FAILED == dwRet)
348 {
349 Fail("WaitForMultipleObjects failed [GetLastError()=%u]\n",
350 GetLastError());
351 }
352 Trace("Named event with remote thread awakening test done\n");
353 Trace("======================================================================\n");
354 }
355
356 if (bSemaphore)
357 {
358 Trace("======================================================================\n");
359 Trace("Semaphore with remote thread awakening test\n");
360 Trace("----------------------------------------\n");
361
362 ZeroMemory ( &si, sizeof(si) );
363 si.cb = sizeof(si);
364 ZeroMemory ( &pi, sizeof(pi) );
365
366 sprintf_s (szCmd, 128, "child6 -semaphore %s", szTestName);
367 szCmd[127] = 0;
368
369 bRet = CreateProcessA(NULL, szCmd, NULL, NULL, FALSE,
370 0, NULL, NULL, &si, &pi);
371 if (FALSE == bRet)
372 {
373 Fail("CreateProcessA failed [GetLastError()=%u]\n",
374 GetLastError());
375 }
376
377 Trace("Setting event %s\n", szEventName);
378 bRet = SetEvent(hNamedEvent);
379 if (FALSE == bRet)
380 {
381 Fail("[child] SetEvent failed [GetLastError()=%u]\n",
382 GetLastError());
383 }
384
385 Trace("Going to wait on semaphore %s\n", szSemName);
386
387
388 hObjs[0] = pi.hProcess;
389 hObjs[0] = hEvent[0];
390 hObjs[1] = hSemaphore;
391 for (i=0;i<10;i++)
392 {
393 dwRet = WaitForMultipleObjects(2, hObjs, FALSE, INFINITE);
394 if (1 != dwRet)
395 {
396 Trace("WaitForMultipleObjects failed [tid=%u dwRet=%u GetLastError()=%u]\n",
397 GetCurrentThreadId(), dwRet, GetLastError());
398 DebugBreak();
399 }
400 }
401
402 dwRet = WaitForSingleObject(pi.hProcess, INFINITE);
403 if (WAIT_FAILED == dwRet)
404 {
405 Fail("WaitForMultipleObjects failed [GetLastError()=%u]\n",
406 GetLastError());
407 }
408 Trace("Semaphore with remote thread awakening test done\n");
409 Trace("======================================================================\n");
410 }
411
412 if (bProcess)
413 {
414 DWORD dwExitCode;
415
416 Trace("======================================================================\n");
417 Trace("Process wait test\n");
418 Trace("----------------------------------------\n");
419
420 iDesiredExitCode = rand() % 0xFF;
421
422 ZeroMemory ( &si, sizeof(si) );
423 si.cb = sizeof(si);
424 ZeroMemory ( &pi, sizeof(pi) );
425
426 sprintf_s (szCmd, 128, "child6 -mutex %s -exitcode %d", szTestName, iDesiredExitCode);
427 szCmd[127] = 0;
428
429 bRet = CreateProcessA(NULL, szCmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
430 if (FALSE == bRet)
431 {
432 Fail("CreateProcess failed [GetLastError()=%u]\n",
433 GetLastError());
434 }
435
436 Trace("Going to wait on event %s\n", szEventName);
437 dwRet = WaitForSingleObject(hNamedEvent, INFINITE);
438 if (WAIT_FAILED == dwRet)
439 {
440 Fail("WaitForMultipleObjects failed [GetLastError()=%u]\n",
441 GetLastError());
442 }
443
444 hObjs[0] = hEvent[0]; // dummy, this is a local event
445 hObjs[1] = hMutex;
446
447 dwRet = WaitForMultipleObjects(2, hObjs, FALSE, INFINITE);
448 if (WAIT_FAILED == dwRet)
449 {
450 Fail("WaitForMultipleObjects failed [GetLastError()=%u]\n",
451 GetLastError());
452 }
453 if (1 == dwRet || (1 + WAIT_ABANDONED_0) == dwRet)
454 {
455 bRet = ReleaseMutex(hMutex);
456 if (FALSE == bRet)
457 {
458 Fail("ReleaseMutex failed [GetLastError()=%u]\n",
459 GetLastError());
460 }
461 }
462
463 dwRet = WaitForSingleObject(pi.hProcess, INFINITE);
464 if (WAIT_FAILED == dwRet)
465 {
466 Fail("WaitForMultipleObjects failed [GetLastError()=%u]\n",
467 GetLastError());
468 }
469
470 if (!GetExitCodeProcess(pi.hProcess, &dwExitCode))
471 {
472 Trace("GetExitCodeProcess call failed LastError:(%u)\n",
473 GetLastError());
474 dwExitCode = FAIL;
475 }
476
477 if (iDesiredExitCode != dwExitCode)
478 {
479 Fail("Wrong return code: %u [%d]\n", dwExitCode, iDesiredExitCode);
480 }
481 CloseHandle(pi.hProcess);
482 CloseHandle(pi.hThread);
483 Trace("Process wait test done\n");
484 Trace("======================================================================\n");
485 }
486
487 if (bLocalWaitAll)
488 {
489 Trace("======================================================================\n");
490 Trace("WaitAll with local thread awakening test\n");
491 Trace("----------------------------------------\n");
492
493 hThread = CreateThread(NULL, 0, EventTestThread, (PVOID)hEvent, 0, &dwSlaveThreadTid);
494 if (NULL == hThread)
495 {
496 Fail("CreateThread failed [GetLastError()=%u]\n",
497 GetLastError());
498 }
499
500 dwRet = WaitForMultipleObjects(2, hEvent, TRUE, INFINITE);
501 if (WAIT_FAILED == dwRet)
502 {
503 Fail("WaitForMultipleObjects failed [GetLastError()=%u]\n",
504 GetLastError());
505 }
506
507 hObjs[0] = hThread;
508 dwRet = WaitForMultipleObjects(1, hObjs, FALSE, INFINITE);
509 if (WAIT_FAILED == dwRet)
510 {
511 Fail("WaitForMultipleObjects failed [GetLastError()=%u]\n",
512 GetLastError());
513 }
514
515 CloseHandle(hThread);
516 Trace("WaitAll with local thread awakening test done\n");
517 Trace("======================================================================\n");
518 }
519
520 if (bRemoteWaitAll)
521 {
522 Trace("======================================================================\n");
523 Trace("WaitAll with remote thread awakening test\n");
524 Trace("----------------------------------------\n");
525
526 ZeroMemory ( &si, sizeof(si) );
527 si.cb = sizeof(si);
528 ZeroMemory ( &pi, sizeof(pi) );
529
530 sprintf_s (szCmd, 128, "child6 -mutex_and_named_event %s", szTestName);
531 szCmd[127] = 0;
532
533 bRet = CreateProcessA(NULL, szCmd, NULL, NULL, FALSE,
534 0, NULL, NULL, &si, &pi);
535 if (FALSE == bRet)
536 {
537 Fail("CreateProcess failed [GetLastError()=%u]\n",
538 GetLastError());
539 }
540
541 Sleep(1000);
542
543 hObjs[0] = hMutex;
544 hObjs[1] = hNamedEvent;
545
546 dwRet = WaitForMultipleObjects(2, hObjs, TRUE, INFINITE);
547 if (WAIT_FAILED == dwRet)
548 {
549 Fail("WaitForMultipleObjects failed [GetLastError()=%u]\n",
550 GetLastError());
551 }
552
553 bRet = ReleaseMutex(hMutex);
554 if (FALSE == bRet)
555 {
556 Fail("ReleaseMutex failed [GetLastError()=%u]\n",
557 GetLastError());
558 }
559
560 dwRet = WaitForSingleObject(pi.hProcess, INFINITE);
561 if (WAIT_FAILED == dwRet)
562 {
563 Fail("WaitForMultipleObjects failed [GetLastError()=%u]\n",
564 GetLastError());
565 }
566
567 CloseHandle(pi.hProcess);
568 CloseHandle(pi.hThread);
569 Trace("WaitAll with remote thread awakening test done\n");
570 Trace("======================================================================\n");
571 }
572 }
573
574 return 0;
575}
576
577int __cdecl main(int argc, char **argv)
578{
579 DWORD dwRet;
580 DWORD dwSlaveThreadTid = 0;
581 int i, iCnt;
582
583 if(0 != (PAL_Initialize(argc, argv)))
584 {
585 return ( FAIL );
586 }
587
588 srand(time(NULL) * GetCurrentProcessId());
589
590 if (argc == 1)
591 {
592 g_bMutex = 1;
593 g_bEvent = 1;
594 g_bNamedEvent = 1;
595 g_bSemaphore = 1;
596 g_bProcess = 1;
597 g_bLocalWaitAll = 1;
598 g_bRemoteWaitAll = 1;
599 }
600 else
601 {
602 for (i=1;i<argc;i++)
603 {
604 if (0 == strcmp(argv[i], "-mutex"))
605 {
606 g_bMutex = 1;
607 }
608 else if (0 == strcmp(argv[i], "-event"))
609 {
610 g_bEvent = 1;
611 }
612 else if (0 == strcmp(argv[i], "-namedevent"))
613 {
614 g_bNamedEvent = 1;
615 }
616 else if (0 == strcmp(argv[i], "-semaphore"))
617 {
618 g_bSemaphore = 1;
619 }
620 else if (0 == strcmp(argv[i], "-process"))
621 {
622 g_bProcess = 1;
623 }
624 else if (0 == strcmp(argv[i], "-localwaitall"))
625 {
626 g_bLocalWaitAll = 1;
627 }
628 else if (0 == strcmp(argv[i], "-remotewaitall"))
629 {
630 g_bRemoteWaitAll = 1;
631 }
632 else if (0 == strcmp(argv[i], "-all"))
633 {
634 g_bMutex = 1;
635 g_bEvent = 1;
636 g_bNamedEvent = 1;
637 g_bSemaphore = 1;
638 g_bProcess = 1;
639 g_bLocalWaitAll = 1;
640 g_bRemoteWaitAll = 1;
641 }
642 else if (0 == strcmp(argv[i], "-random"))
643 {
644 g_bRandom = 1;
645 }
646 else if ((0 == strcmp(argv[i], "-count")) && (argc > i+1))
647 {
648 i++;
649 iCnt = atoi(argv[i]);
650 if (iCnt > 0 && iCnt < MAX_COUNT)
651 {
652 iCount = iCnt;
653 }
654 }
655 else if ((0 == strcmp(argv[i], "-threads")) && (argc > i+1))
656 {
657 i++;
658 iCnt = atoi(argv[i]);
659 if (iCnt > 0 && iCnt <= MAX_THREADS)
660 {
661 iThreads = iCnt;
662 }
663 }
664 else
665 {
666 Trace("Unknown option %s ignored\n", argv[i]);
667 }
668 }
669 }
670
671
672 iCnt = 0;
673 for (i=0;i<iThreads;i++)
674 {
675 hThreads[iCnt] = CreateThread(NULL, 0, TestThread, (VOID*)iCnt, 0, &dwSlaveThreadTid);
676 if (NULL == hThreads[iCnt])
677 {
678 Trace("Failed to create thread\n");
679 }
680 else
681 {
682 iCnt++;
683 }
684 }
685
686 if (0 == iCnt)
687 {
688 Fail("Can't create any thread\n");
689 }
690
691 for (i=0; i<iCnt; i+=64)
692 {
693 dwRet = WaitForMultipleObjects(MIN(64, iCnt-i), &hThreads[i], TRUE, INFINITE);
694 if (WAIT_FAILED == dwRet)
695 {
696 Fail("WaitForMultipleObjects failed [dwRet=%u GetLastError()=%u iCnt=%d i=%d]\n",
697 dwRet, GetLastError(), iCnt, i);
698 }
699 }
700
701
702 for (i=0; i<iCnt; i++)
703 {
704 CloseHandle(hThreads[i]);
705 }
706
707 PAL_Terminate();
708 return PASS;
709}
710