master
c 1,701 lines 43.8 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 WaitPid.c
8
9 Abstract:
10
11 This file is a WaitPid test.
12
13 --*/
14
15 #include "lxtcommon.h"
16 #include "unittests.h"
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <fcntl.h>
20 #include <sys/wait.h>
21 #include <sys/resource.h>
22 #include <sys/syscall.h>
23 #include <sys/prctl.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include "lxtutil.h"
27
28 #define LXT_NAME "WaitPid"
29
30 #define WAITPID_DEFAULT_WAIT_TIMEOUT_US 100000
31 #define WAITPID_DEFAULT_WAIT_COUNT 20
32 #define WAITPID_THREADGROUP_LEADER_UID 1044
33 #define WAITPID_PTHREAD_UID 1055
34
35 bool g_VmMode = false;
36
37 int GetPPidPoll(pid_t ExpectedPid);
38
39 LXT_VARIATION_HANDLER WaitPidVariationExitStatusBlock;
40
41 int WaitPidVariationExitStatusHelper(PLXT_ARGS Args, int Blocking);
42
43 LXT_VARIATION_HANDLER WaitPidVariationExitStatusPoll;
44 LXT_VARIATION_HANDLER WaitPidVariationInitPid;
45 LXT_VARIATION_HANDLER WaitPidVariationParentChild;
46 LXT_VARIATION_HANDLER WaitPidVariationProcessGroup;
47 LXT_VARIATION_HANDLER WaitPidVariationInvalidParameter;
48 LXT_VARIATION_HANDLER WaitPidVariationWaitId;
49 LXT_VARIATION_HANDLER WaitPidVariationCloneParent;
50 LXT_VARIATION_HANDLER WaitPidVariationZombie;
51 LXT_VARIATION_HANDLER WaitPidVariationZombieStress;
52
53 //
54 // Global constants
55 //
56 // FIXME: Enable parent\child test when clone gs issue is resolved.
57 //
58
59 static const LXT_VARIATION g_LxtVariations[] = {
60 {"WaitPidVariation - Exit status poll", WaitPidVariationExitStatusPoll},
61 {"WaitPidVariation - Exit status block", WaitPidVariationExitStatusBlock},
62 {"WaitPidVariation - Init pid", WaitPidVariationInitPid},
63 {"WaitPidVariation - Process groups", WaitPidVariationProcessGroup},
64 {"WaitPidVariation - Invalid parameter", WaitPidVariationInvalidParameter},
65 {"WaitPidVariation - waitid", WaitPidVariationWaitId},
66 {"WaitPidVariation - CLONE_PARENT", WaitPidVariationCloneParent},
67 {"WaitPidVariation - zombie support", WaitPidVariationZombie},
68 {"WaitPidVariation - zombie stress", WaitPidVariationZombieStress}};
69
70 int WaitPidTestEntry(int Argc, char* Argv[])
71
72 /*++
73 --*/
74
75 {
76
77 LXT_ARGS Args;
78 int Result;
79
80 if (LxtWslVersion() == 2)
81 {
82 g_VmMode = true;
83 }
84
85 LxtCheckResult(LxtInitialize(Argc, Argv, &Args, LXT_NAME));
86 LXT_SYNCHRONIZATION_POINT_INIT();
87 LxtCheckResult(LxtRunVariations(&Args, g_LxtVariations, LXT_COUNT_OF(g_LxtVariations)));
88
89 ErrorExit:
90 LXT_SYNCHRONIZATION_POINT_DESTROY();
91 LxtUninitialize();
92 return !LXT_SUCCESS(Result);
93 }
94
95 int GetPPidPoll(pid_t ExpectedPPid)
96
97 /*++
98 --*/
99
100 {
101
102 pid_t CurrentPPid;
103 int Result;
104 int WaitCount;
105
106 //
107 // Wait for the current ppid to reach the expected ppid.
108 //
109
110 for (WaitCount = 0; WaitCount < WAITPID_DEFAULT_WAIT_COUNT; ++WaitCount)
111 {
112 CurrentPPid = getppid();
113 if (CurrentPPid == ExpectedPPid)
114 {
115 break;
116 }
117
118 usleep(WAITPID_DEFAULT_WAIT_TIMEOUT_US);
119 }
120
121 if (WaitCount == WAITPID_DEFAULT_WAIT_COUNT)
122 {
123 Result = LXT_RESULT_FAILURE;
124 LxtLogError("Unexpected pid, %d != %d", CurrentPPid, ExpectedPPid);
125 goto ErrorExit;
126 }
127
128 Result = LXT_RESULT_SUCCESS;
129
130 ErrorExit:
131 return Result;
132 }
133
134 int LxtWaitPidHelper(pid_t ChildPid, int ExpectedWaitStatus, int Blocking)
135
136 /*++
137 --*/
138
139 {
140
141 int SecondWaitPidStatus;
142 int Result;
143 int WaitCount;
144 int WaitPidResult;
145 int WaitPidStatus;
146
147 if (Blocking == 0)
148 {
149 LxtCheckResult(LxtWaitPidPoll(ChildPid, ExpectedWaitStatus));
150 }
151 else
152 {
153 LxtCheckErrno((WaitPidResult = waitpid(ChildPid, &WaitPidStatus, 0)));
154 if ((WaitPidStatus & 0xFFFF0000) != 0)
155 {
156 Result = LXT_RESULT_FAILURE;
157 LxtLogError("Unexpected high short status: %d - %d", WaitPidStatus, ExpectedWaitStatus);
158
159 goto ErrorExit;
160 }
161
162 if (WaitPidStatus != ExpectedWaitStatus)
163 {
164 Result = LXT_RESULT_FAILURE;
165 LxtLogError("Unexpected status: %d != %d", WaitPidStatus, ExpectedWaitStatus);
166
167 goto ErrorExit;
168 }
169
170 if (WIFEXITED(WaitPidStatus) != 0)
171 {
172 LxtCheckErrnoFailure(waitpid(ChildPid, &SecondWaitPidStatus, WNOHANG), ECHILD);
173 }
174 }
175
176 ErrorExit:
177 return Result;
178 }
179
180 int WaitPidVariationInitPid(PLXT_ARGS Args)
181
182 /*++
183 --*/
184
185 {
186
187 pid_t ChildPid;
188 int ExitCodeIndex;
189 unsigned char ExitCode;
190 int ExpectedPid;
191 int ExpectedWaitStatus;
192 pid_t ParentParentPid;
193 LXT_PIPE Pipe = {-1, -1};
194 int Result;
195 pid_t WaitPidResult;
196 int WaitPidStatus;
197 int WaitPipe;
198
199 //
200 // Determine who the subreaper of the test is. On WSL 1 it will be init, on
201 // WSL 2 it will be the relay process (parent of this process).
202 //
203
204 ExpectedPid = LXT_INIT_PID;
205 if (g_VmMode != false)
206 {
207 ExpectedPid = getppid();
208 }
209
210 LxtCheckResult(LxtCreatePipe(&Pipe));
211
212 //
213 // Check when a parent dies, the child has a parent pid of the subreaper.
214 //
215
216 ExitCode = 0;
217 LxtCheckErrno(ChildPid = fork());
218 if (ChildPid == 0)
219 {
220 LxtCheckErrno(ChildPid = fork());
221 if (ChildPid == 0)
222 {
223 LxtCheckResult(GetPPidPoll(ExpectedPid));
224 LxtCheckErrno(write(Pipe.Write, &WaitPipe, sizeof(WaitPipe)));
225 }
226
227 _exit(ExitCode);
228 }
229 else
230 {
231 LxtCheckResult(LxtWaitPidPoll(-1, ExitCode));
232 LxtCheckErrno(read(Pipe.Read, &WaitPipe, sizeof(WaitPipe)));
233 }
234
235 //
236 // The init process should never be a child.
237 //
238
239 LxtCheckErrnoFailure(waitpid(LXT_INIT_PID, &WaitPidStatus, WNOHANG), ECHILD);
240
241 ErrorExit:
242 LxtClosePipe(&Pipe);
243
244 return Result;
245 }
246
247 int WaitPidVariationExitStatusBlock(PLXT_ARGS Args)
248
249 /*++
250 --*/
251
252 {
253
254 return WaitPidVariationExitStatusHelper(Args, 1);
255 }
256
257 int WaitPidVariationExitStatusHelper(PLXT_ARGS Args, int Blocking)
258
259 /*++
260 --*/
261
262 {
263
264 int ExitCodeIndex;
265 unsigned char ExitCodes[] = {0, 1, 128, 255};
266 pid_t ChildPid[LXT_COUNT_OF(ExitCodes)];
267 int ExpectedWaitStatus;
268 pid_t ParentParentPid;
269 pid_t ParentPid;
270 int Result;
271
272 //
273 // Check that the correct _exit status is returned to a parent process and
274 // that it can only be checked once serially.
275 //
276
277 ParentParentPid = getppid();
278 ParentPid = getpid();
279 for (ExitCodeIndex = 0; ExitCodeIndex < LXT_COUNT_OF(ExitCodes); ++ExitCodeIndex)
280 {
281 LxtCheckErrno(ChildPid[ExitCodeIndex] = fork());
282 if (ChildPid[ExitCodeIndex] == 0)
283 {
284 ChildPid[ExitCodeIndex] = getpid();
285 if (getppid() != ParentPid)
286 {
287 Result = LXT_RESULT_FAILURE;
288 LxtLogError("Unexpected parent pid in child - %d != %d", ChildPid[ExitCodeIndex], ParentPid);
289
290 goto ErrorExit;
291 }
292
293 _exit(ExitCodes[ExitCodeIndex]);
294 }
295 else
296 {
297 ExpectedWaitStatus = ExitCodes[ExitCodeIndex] << 8;
298 LxtCheckResult(LxtWaitPidHelper(ChildPid[ExitCodeIndex], ExpectedWaitStatus, Blocking));
299 }
300 }
301
302 //
303 // Recheck the results after launching the children in parallel.
304 //
305
306 LxtLogInfo("Running forks in parallel...");
307 for (ExitCodeIndex = 0; ExitCodeIndex < LXT_COUNT_OF(ExitCodes); ++ExitCodeIndex)
308 {
309 LxtCheckErrno(ChildPid[ExitCodeIndex] = fork());
310 if (ChildPid[ExitCodeIndex] == 0)
311 {
312 ChildPid[ExitCodeIndex] = getpid();
313 if (getppid() != ParentPid)
314 {
315 Result = LXT_RESULT_FAILURE;
316 LxtLogError("Unexpected parent pid in child - %d != %d", ChildPid[ExitCodeIndex], ParentPid);
317
318 goto ErrorExit;
319 }
320
321 _exit(ExitCodes[ExitCodeIndex]);
322 }
323 }
324
325 while (ExitCodeIndex--)
326 {
327 ExpectedWaitStatus = ExitCodes[ExitCodeIndex] << 8;
328 LxtCheckResult(LxtWaitPidHelper(ChildPid[ExitCodeIndex], ExpectedWaitStatus, Blocking));
329 }
330
331 ErrorExit:
332 return Result;
333 }
334
335 int WaitPidVariationExitStatusPoll(PLXT_ARGS Args)
336
337 /*++
338 --*/
339
340 {
341
342 return WaitPidVariationExitStatusHelper(Args, 0);
343 }
344
345 typedef struct _WAIT_PID_PARENT_DATA
346 {
347 int Generation;
348 pid_t ParentPid;
349 pid_t ParentTid;
350 LXT_PIPE Pipes[4];
351 LXT_CLONE_ARGS CloneArgs[2];
352 pid_t ForkPid;
353 } WAIT_PID_PARENT_DATA, *PWAIT_PID_PARENT_DATA;
354
355 void WaitPidPrintData(PWAIT_PID_PARENT_DATA CurrentData, char* Message)
356
357 {
358
359 int Index;
360 pid_t WaitResult;
361 int WaitStatus;
362
363 //
364 // TODO: Enable _CLONE
365 //
366
367 LxtLogInfo("***** %s", Message);
368 WaitStatus = -1;
369 for (Index = 0; Index < LXT_COUNT_OF(CurrentData->CloneArgs); ++Index)
370 {
371 LxtLogInfo("Before waitpid", Message);
372 WaitResult = waitpid(CurrentData->CloneArgs[Index].CloneId, &WaitStatus, WNOHANG);
373 LxtLogInfo("%s - Clone %d WNOHANG - %d, %d", Message, CurrentData->CloneArgs[Index].CloneId, WaitResult, WaitStatus);
374 // WaitResult = waitpid(CurrentData->CloneArgs[Index].CloneId, &WaitStatus, WNOHANG | __WCLONE);
375 // LxtLogInfo("%s - Clone %d WNOHANG | __WCLONE - %d, %d", Message, CurrentData->CloneArgs[Index].CloneId, WaitResult, WaitStatus);
376 }
377
378 WaitResult = waitpid(CurrentData->ForkPid, &WaitStatus, WNOHANG);
379 LxtLogInfo("%s - Fork %d WNOHANG - %d, %d", Message, CurrentData->ForkPid, WaitResult, WaitStatus);
380 // WaitResult = waitpid(CurrentData->ForkPid, &WaitStatus, WNOHANG | __WCLONE);
381 // LxtLogInfo("%s - Fork %d WNOHANG | __WCLONE - %d, %d", Message, CurrentData->ForkPid, WaitResult, WaitStatus);
382 LxtLogInfo("***** %s", Message);
383
384 return;
385 }
386
387 int WaitPidVariationParentChildClone(void* Parameter)
388
389 /*++
390 --*/
391
392 {
393
394 int CloneIndex;
395 PWAIT_PID_PARENT_DATA CurrentData;
396 pid_t CurrentPid;
397 pid_t CurrentTid;
398 int Index;
399 int ParentIndex;
400 int Result;
401 int WaitPipe;
402
403 CurrentData = Parameter;
404 CurrentTid = gettid();
405 for (Index = 0; Index < LXT_COUNT_OF(CurrentData->CloneArgs); ++Index)
406 {
407 if (CurrentData->CloneArgs[Index].CloneId == CurrentTid)
408 {
409 CloneIndex = Index;
410 break;
411 }
412 }
413
414 if (Index == LXT_COUNT_OF(CurrentData->CloneArgs))
415 {
416 Result = LXT_RESULT_FAILURE;
417 LxtLogError("Unable to find clone tid %d", CurrentTid);
418 goto ErrorExit;
419 }
420
421 LxtCheckErrno(read(CurrentData->Pipes[CloneIndex].Read, &WaitPipe, sizeof(WaitPipe)));
422 CurrentPid = getpid();
423 if (CurrentPid != CurrentData->ParentPid)
424 {
425 Result = LXT_RESULT_FAILURE;
426 LxtLogError("Unexpected pid for clone %d: %d != %d", CloneIndex, CurrentPid, CurrentData->ParentPid);
427
428 goto ErrorExit;
429 }
430
431 WaitPidPrintData(CurrentData, "Clone");
432 ParentIndex = LXT_COUNT_OF(CurrentData->CloneArgs) + 1;
433 LxtCheckErrno(write(CurrentData->Pipes[ParentIndex].Write, &WaitPipe, sizeof(WaitPipe)));
434 LxtCheckErrno(read(CurrentData->Pipes[CloneIndex].Read, &WaitPipe, sizeof(WaitPipe)));
435
436 ErrorExit:
437 LxtLogInfo("Clone %d exit", CloneIndex);
438 return Result;
439 }
440
441 int WaitPidVariationParentChildFork(PWAIT_PID_PARENT_DATA ParentData)
442
443 /*++
444 --*/
445
446 {
447
448 WAIT_PID_PARENT_DATA CurrentData;
449 int ForkIndex;
450 pid_t ParentPid;
451 int ParentIndex;
452 int Result;
453 int WaitPipe;
454
455 ForkIndex = LXT_COUNT_OF(ParentData->CloneArgs);
456 LxtCheckErrno(read(ParentData->Pipes[ForkIndex].Read, &WaitPipe, sizeof(WaitPipe)));
457 CurrentData.ParentPid = getpid();
458 CurrentData.ParentTid = gettid();
459 if (CurrentData.ParentPid != CurrentData.ParentTid)
460 {
461 Result = LXT_RESULT_FAILURE;
462 LxtLogError("Current fork thread is not thread group leader %d != %d", CurrentData.ParentPid, CurrentData.ParentTid);
463 goto ErrorExit;
464 }
465
466 ParentPid = getppid();
467 if (ParentPid != ParentData->ParentPid)
468 {
469 Result = LXT_RESULT_FAILURE;
470 LxtLogError("Unexpected ppid %d != %d", ParentPid, ParentData->ParentPid);
471 goto ErrorExit;
472 }
473
474 if (CurrentData.ParentPid == ParentData->ParentPid)
475 {
476 Result = LXT_RESULT_FAILURE;
477 LxtLogError("Unexpected pid %d == %d", CurrentData.ParentPid, ParentData->ParentPid);
478 goto ErrorExit;
479 }
480
481 ParentData->ForkPid = getpid();
482 WaitPidPrintData(ParentData, "Fork");
483 ParentIndex = LXT_COUNT_OF(ParentData->CloneArgs) + 1;
484 LxtCheckErrno(write(ParentData->Pipes[ParentIndex].Write, &WaitPipe, sizeof(WaitPipe)));
485 LxtCheckErrno(read(ParentData->Pipes[ForkIndex].Read, &WaitPipe, sizeof(WaitPipe)));
486
487 ErrorExit:
488 _exit(Result);
489 }
490
491 int WaitPidVariationCreateParentData(PWAIT_PID_PARENT_DATA CurrentData)
492
493 /*++
494 --*/
495
496 {
497
498 int Index;
499 int ParentIndex;
500 int Result;
501 int WaitPipe;
502 pid_t WaitResult;
503 int WaitStatus;
504
505 CurrentData->Generation = CurrentData->Generation + 1;
506 CurrentData->ParentPid = getpid();
507 CurrentData->ParentTid = gettid();
508 if (CurrentData->ParentPid != CurrentData->ParentTid)
509 {
510 Result = LXT_RESULT_FAILURE;
511 LxtLogError("Current thread is not thread group leader %d != %d", CurrentData->ParentPid, CurrentData->ParentTid);
512 goto ErrorExit;
513 }
514
515 for (Index = 0; Index < LXT_COUNT_OF(CurrentData->Pipes); ++Index)
516 {
517 LxtCheckResult(LxtCreatePipe(&CurrentData->Pipes[Index]));
518 }
519
520 //
521 // TODO: Enable _CLONE
522 //
523
524 for (Index = 0; Index < LXT_COUNT_OF(CurrentData->CloneArgs); ++Index)
525 {
526 LxtCheckResult(LxtClone(WaitPidVariationParentChildClone, CurrentData, LXT_CLONE_FLAGS_DEFAULT, &CurrentData->CloneArgs[Index]));
527 }
528
529 LxtCheckErrno(CurrentData->ForkPid = fork());
530 if (CurrentData->ForkPid == 0)
531 {
532 WaitPidVariationParentChildFork(CurrentData);
533 }
534
535 WaitPidPrintData(CurrentData, "Parent");
536 ParentIndex = LXT_COUNT_OF(CurrentData->CloneArgs) + 1;
537 for (Index = 0; Index < LXT_COUNT_OF(CurrentData->Pipes) - 1; ++Index)
538 {
539 LxtCheckErrno(write(CurrentData->Pipes[Index].Write, &WaitPipe, sizeof(WaitPipe)));
540 LxtCheckErrno(read(CurrentData->Pipes[ParentIndex].Read, &WaitPipe, sizeof(WaitPipe)));
541 }
542
543 //
544 // Release the waiters
545 //
546
547 for (Index = 0; Index < LXT_COUNT_OF(CurrentData->Pipes) - 1; ++Index)
548 {
549 LxtCheckErrno(write(CurrentData->Pipes[Index].Write, &WaitPipe, sizeof(WaitPipe)));
550 }
551
552 ErrorExit:
553 for (Index = 0; Index < LXT_COUNT_OF(CurrentData->Pipes); ++Index)
554 {
555 LxtClosePipe(&CurrentData->Pipes[Index]);
556 }
557
558 return Result;
559 }
560
561 int WaitPidVariationParentChild(PLXT_ARGS Args)
562
563 /*++
564 --*/
565
566 {
567
568 WAIT_PID_PARENT_DATA CurrentData;
569 int Result;
570
571 memset(&CurrentData, 0, sizeof(CurrentData));
572 LxtCheckResult(WaitPidVariationCreateParentData(&CurrentData));
573
574 ErrorExit:
575 return Result;
576 }
577
578 int WaitPidVariationProcessGroup(PLXT_ARGS Args)
579
580 /*++
581
582 Description:
583
584 This routine tests waiting on all children in the same process group.
585
586 Arguments:
587
588 Args - Supplies the command line arguments.
589
590 Return Value:
591
592 Returns 0 on success, -1 on failure.
593
594 --*/
595
596 {
597
598 const int OtherGroupChildCount = 2;
599 pid_t OtherGroupChild[OtherGroupChildCount];
600 int Result;
601 pid_t SameGroupChild;
602 int Status;
603 int WaitResult;
604
605 LxtCheckResult(LxtSignalBlock(SIGUSR1));
606 for (int Child = 0; Child < OtherGroupChildCount; Child++)
607 {
608 LxtCheckErrno(OtherGroupChild[Child] = fork());
609 if (OtherGroupChild[Child] == 0)
610 {
611
612 //
613 // Change process group, then signal the parent.
614 //
615
616 LxtCheckErrnoZeroSuccess(setpgid(0, 0));
617 LxtCheckErrnoZeroSuccess(kill(getppid(), SIGUSR1));
618 _exit(0);
619 }
620
621 //
622 // Wait to make sure the child changed its process group.
623 //
624
625 LxtCheckResult(LxtSignalWaitBlocked(SIGUSR1, OtherGroupChild[Child], 2));
626 }
627
628 LxtCheckErrno(SameGroupChild = fork());
629 if (SameGroupChild == 0)
630 {
631 _exit(0);
632 }
633
634 //
635 // Wait for the same process group, which should return the status of the
636 // second child.
637 //
638
639 LxtCheckResult(WaitResult = LxtWaitPidPoll(0, 0));
640 LxtCheckEqual(WaitResult, SameGroupChild, "%d");
641
642 //
643 // Wait again, which should fail because there are no more children in this
644 // process group.
645 //
646
647 LxtCheckErrnoFailure(waitpid(0, &Status, WNOHANG), ECHILD);
648
649 //
650 // Wait on the specific process group of one of the remaining children.
651 //
652
653 LxtCheckResult(WaitResult = LxtWaitPidPoll(-OtherGroupChild[0], 0));
654 LxtCheckEqual(WaitResult, OtherGroupChild[0], "%d");
655
656 //
657 // Wait on all children, which should return the child in the other process
658 // group.
659 //
660
661 LxtCheckResult(WaitResult = LxtWaitPidPoll(-1, 0));
662 LxtCheckEqual(WaitResult, OtherGroupChild[1], "%d");
663
664 ErrorExit:
665 return Result;
666 }
667
668 int WaitPidVariationInvalidParameter(PLXT_ARGS Args)
669
670 /*++
671
672 Description:
673
674 This routine tests invalid parameter handling for the waitpid system call.
675
676 Arguments:
677
678 Args - Supplies the command line arguments.
679
680 Return Value:
681
682 Returns 0 on success, -1 on failure.
683
684 --*/
685
686 {
687
688 int Result;
689 int Status;
690
691 LxtCheckErrnoFailure(waitpid(0, &Status, WEXITED), EINVAL);
692 LxtCheckErrnoFailure(waitpid(0, &Status, WNOWAIT), EINVAL);
693 LxtCheckErrnoFailure(waitpid(0, NULL, WNOHANG), ECHILD);
694 LxtCheckErrnoFailure(waitpid(0, (void*)-1, WNOHANG), ECHILD);
695
696 ErrorExit:
697 return Result;
698 }
699
700 void* WaitPidVariationWaitIdThread(void* Parameter)
701
702 /*++
703
704 Description:
705
706 This routine is the thread handler for the waitid test.
707
708 Arguments:
709
710 Parameter - Supplies the thread parameter.
711
712 Return Value:
713
714 Returns the thread id on success, -1 on failure.
715
716 --*/
717
718 {
719
720 int Result;
721 LxtLogInfo("WaitPid child tid %d", gettid());
722 LxtCheckErrno(LxtSetUid(WAITPID_PTHREAD_UID));
723
724 //
725 // Enter a very long sleep, this will be interrupted when the threadgroup
726 // leader dies.
727 //
728
729 sleep(-1);
730 Result = 0;
731
732 ErrorExit:
733
734 #pragma GCC diagnostic push
735 #pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
736
737 return (void*)Result;
738
739 #pragma GCC diagnostic pop
740 }
741
742 int WaitPidVariationWaitId(PLXT_ARGS Args)
743
744 /*++
745
746 Description:
747
748 This routine tests the waitid system call.
749
750 Arguments:
751
752 Args - Supplies the command line arguments.
753
754 Return Value:
755
756 Returns 0 on success, -1 on failure.
757
758 --*/
759
760 {
761
762 int ChildPid;
763 int ExpectedStatus;
764 int Result;
765 siginfo_t SigInfo;
766 pthread_t Thread;
767 struct rusage Usage;
768
769 ExpectedStatus = 44;
770 LxtCheckErrno(ChildPid = fork());
771 if (ChildPid == 0)
772 {
773
774 //
775 // Create a child thread, set the uid of the threadgroup leader,
776 // and exit.
777 //
778
779 LxtCheckResultError(pthread_create(&Thread, NULL, WaitPidVariationWaitIdThread, NULL));
780
781 LxtLogInfo("Waitid parent tid %d", gettid());
782
783 //
784 // Briefly sleep to allow the pthread to run.
785 //
786
787 sleep(1);
788 LxtCheckErrno(LxtSetUid(WAITPID_THREADGROUP_LEADER_UID));
789 _exit(ExpectedStatus);
790 }
791
792 LxtCheckErrnoZeroSuccess(Result = LxtWaitId(P_ALL, 0, &SigInfo, WEXITED, &Usage));
793 LxtCheckEqual(Result, 0, "%d");
794 LxtCheckEqual(SigInfo.si_code, CLD_EXITED, "%d");
795 LxtCheckEqual(SigInfo.si_status, ExpectedStatus, "%d");
796 LxtCheckEqual(SigInfo.si_pid, ChildPid, "%d");
797 LxtCheckEqual(SigInfo.si_uid, WAITPID_THREADGROUP_LEADER_UID, "%d");
798
799 //
800 // Wait for a specific child.
801 //
802
803 LxtCheckErrno(ChildPid = fork());
804 if (ChildPid == 0)
805 {
806 _exit(ExpectedStatus);
807 }
808
809 LxtCheckErrnoZeroSuccess(Result = LxtWaitId(P_PID, ChildPid, &SigInfo, WEXITED, &Usage));
810 LxtCheckEqual(Result, 0, "%d");
811 LxtCheckEqual(SigInfo.si_code, CLD_EXITED, "%d");
812 LxtCheckEqual(SigInfo.si_status, ExpectedStatus, "%d");
813 LxtCheckEqual(SigInfo.si_pid, ChildPid, "%d");
814
815 //
816 // Wait with WNOHANG specified.
817 //
818 // N.B. Parent must sleep to allow the child to exit before waiting.
819 //
820
821 LxtCheckErrno(ChildPid = fork());
822 if (ChildPid == 0)
823 {
824 _exit(ExpectedStatus);
825 }
826
827 sleep(1);
828 LxtCheckErrnoZeroSuccess(Result = LxtWaitId(P_PID, ChildPid, &SigInfo, (WEXITED | WNOHANG), &Usage));
829 LxtCheckEqual(Result, 0, "%d");
830 LxtCheckEqual(SigInfo.si_code, CLD_EXITED, "%d");
831 LxtCheckEqual(SigInfo.si_status, ExpectedStatus, "%d");
832 LxtCheckEqual(SigInfo.si_pid, ChildPid, "%d");
833
834 //
835 // Wait with a null siginfo structure.
836 //
837 // N.B. The man page states that the pid of the child should be returned but
838 // this is not the case. The wait should still be consumed so the
839 // second wait should fail with ECHILD.
840 //
841
842 LxtCheckErrno(ChildPid = fork());
843 if (ChildPid == 0)
844 {
845 _exit(0);
846 }
847
848 LxtCheckErrnoZeroSuccess(Result = LxtWaitId(P_ALL, 0, NULL, WEXITED, NULL));
849 LxtCheckErrnoFailure(LxtWaitId(P_ALL, 0, NULL, WEXITED, NULL), ECHILD);
850
851 //
852 // Wait with the WNOWAIT option supplied which means the wait is not
853 // consumed. Wait again to consume the wait and verify it was not consumed
854 // by the first call.
855 //
856
857 LxtCheckErrno(ChildPid = fork());
858 if (ChildPid == 0)
859 {
860 _exit(ExpectedStatus);
861 }
862
863 LxtCheckErrnoZeroSuccess(Result = LxtWaitId(P_PID, ChildPid, &SigInfo, (WEXITED | WNOWAIT), &Usage));
864 LxtCheckEqual(Result, 0, "%d");
865 LxtCheckEqual(SigInfo.si_code, CLD_EXITED, "%d");
866 LxtCheckEqual(SigInfo.si_status, ExpectedStatus, "%d");
867 LxtCheckEqual(SigInfo.si_pid, ChildPid, "%d");
868 LxtCheckErrnoZeroSuccess(Result = LxtWaitId(P_PID, ChildPid, &SigInfo, WEXITED, &Usage));
869 LxtCheckEqual(Result, 0, "%d");
870 LxtCheckEqual(SigInfo.si_code, CLD_EXITED, "%d");
871 LxtCheckEqual(SigInfo.si_status, ExpectedStatus, "%d");
872 LxtCheckEqual(SigInfo.si_pid, ChildPid, "%d");
873
874 //
875 // Call getrusage with the supported values.
876 //
877
878 LxtCheckErrno(getrusage(RUSAGE_SELF, &Usage));
879 LxtCheckErrno(getrusage(RUSAGE_THREAD, &Usage));
880 LxtCheckErrno(getrusage(RUSAGE_CHILDREN, &Usage));
881
882 //
883 // Invalid parameter variations.
884 //
885
886 LxtCheckErrno(ChildPid = fork());
887 if (ChildPid == 0)
888 {
889 _exit(0);
890 }
891
892 LxtCheckErrnoFailure(LxtWaitId(P_ALL, 0, NULL, WNOHANG, NULL), EINVAL);
893 LxtCheckErrnoFailure(LxtWaitId(-1, 0, NULL, WEXITED, NULL), EINVAL);
894 LxtCheckErrnoFailure(LxtWaitId(P_PGID + 5, 0, NULL, WEXITED, NULL), EINVAL);
895 LxtCheckErrnoFailure(LxtWaitId(P_ALL, 0, NULL, 0x10, NULL), EINVAL);
896
897 //
898 // N.B. Providing an invalid pointer to a siginfo structure returns efault
899 // but consumes the wait.
900 //
901
902 LxtCheckErrnoFailure(LxtWaitId(P_ALL, 0, (void*)-1, WEXITED, NULL), EFAULT);
903 LxtCheckErrnoFailure(LxtWaitId(P_ALL, 0, NULL, WEXITED, NULL), ECHILD);
904
905 LxtCheckErrno(ChildPid = fork());
906 if (ChildPid == 0)
907 {
908 _exit(0);
909 }
910
911 //
912 // N.B. Providing an invalid pointer to a rusage structure returns efault
913 // but consumes the wait.
914 //
915
916 LxtCheckErrnoFailure(LxtWaitId(P_ALL, 0, NULL, WEXITED, (void*)-1), EFAULT);
917 LxtCheckErrnoFailure(LxtWaitId(P_ALL, 0, NULL, WEXITED, NULL), ECHILD);
918
919 ErrorExit:
920 if (ChildPid == 0)
921 {
922 _exit(Result);
923 }
924
925 return Result;
926 }
927
928 int WaitPidVariationCloneParentChild(void)
929
930 /*++
931
932 Description:
933
934 This routine is the child process for WaitPidVariationCloneParent.
935
936 Arguments:
937
938 None..
939
940 Return Value:
941
942 Returns 0 on success, -1 on failure.
943
944 --*/
945
946 {
947
948 pid_t ChildPid;
949 pid_t GrandChildParent;
950 pid_t ChildParent;
951 int Result;
952 int WaitPidStatus;
953
954 Result = 0;
955
956 //
957 // Create a child process with the CLONE_PARENT flag.
958 //
959 // The new process should not be reported as a child.
960 //
961
962 ChildParent = getppid();
963 LxtLogInfo("ChildParent %d", ChildParent);
964 LxtCheckResult(ChildPid = LxtCloneSyscall(CLONE_PARENT | SIGCHLD, NULL, NULL, NULL, NULL));
965 if (ChildPid == 0)
966 {
967 GrandChildParent = getppid();
968 LxtCheckEqual(ChildParent, GrandChildParent, "%d");
969 LxtLogInfo("Grand child %d exiting", LxtGetTid());
970 }
971 else
972 {
973 LxtCheckErrnoFailure(waitpid(ChildPid, &WaitPidStatus, 0), ECHILD);
974 LxtLogInfo("Child %d exiting", LxtGetTid());
975 }
976
977 ErrorExit:
978 _exit(Result);
979 }
980
981 int WaitPidVariationCloneParent(PLXT_ARGS Args)
982
983 /*++
984
985 Description:
986
987 This routine tests invalid parameter handling for the waitpid system call.
988
989 Arguments:
990
991 Args - Supplies the command line arguments.
992
993 Return Value:
994
995 Returns 0 on success, -1 on failure.
996
997 --*/
998
999 {
1000
1001 pid_t ChildPid;
1002 pid_t GrandChildPid;
1003 int Result;
1004 int Status;
1005
1006 ChildPid = -1;
1007
1008 //
1009 // Create a child process, that in turn creates a grandchild process
1010 // with CLONE_PARENT.
1011 //
1012
1013 LxtCheckErrno(ChildPid = fork());
1014 if (ChildPid == 0)
1015 {
1016 WaitPidVariationCloneParentChild();
1017 }
1018
1019 //
1020 // Wait for the child and the grandchild.
1021 //
1022
1023 LxtCheckResult(LxtWaitPidPoll(ChildPid, 0));
1024 LxtCheckResult(GrandChildPid = LxtWaitPidPoll(0, 0));
1025 LxtLogInfo("Waited on grandchild %d", GrandChildPid);
1026
1027 //
1028 // Check that the same scenario works when parent dies before
1029 // CLONE_PARENT.
1030 //
1031
1032 LxtCheckErrno(ChildPid = fork());
1033 if (ChildPid == 0)
1034 {
1035 LxtCheckErrno(ChildPid = fork());
1036 if (ChildPid == 0)
1037 {
1038 sleep(1);
1039 WaitPidVariationCloneParentChild();
1040 }
1041
1042 _exit(0);
1043 }
1044
1045 //
1046 // Wait for the child and give the grandchild time to finish.
1047 //
1048
1049 LxtCheckResult(LxtWaitPidPoll(ChildPid, 0));
1050 LxtLogInfo("Waited on child %d", ChildPid);
1051 sleep(2);
1052
1053 ErrorExit:
1054 if (ChildPid == 0)
1055 {
1056 _exit(Result);
1057 }
1058
1059 return Result;
1060 }
1061
1062 typedef struct _WAITPID_THREAD_PARAMETERS
1063 {
1064 pid_t ChildPid;
1065 pid_t GrandChildPid1;
1066 pid_t GrandChildPid2;
1067 LXT_SYNCHRONIZATION_POINT_DECLARE_FOR(ChildPid);
1068 LXT_SYNCHRONIZATION_POINT_DECLARE_FOR(GrandChildPid2);
1069 LXT_PIPE Pipe;
1070 int ChildLevel;
1071 int Variation;
1072 } WAITPID_THREAD_PARAMETERS, *PWAITPID_THREAD_PARAMETERS;
1073
1074 int ThreadZombieThread(void* Context)
1075
1076 /*++
1077
1078 Description:
1079
1080 This routine is the thread proc used by WaitPidVariationThreadZombie.
1081
1082 Arguments:
1083
1084 Context - Supplies the thread context.
1085
1086 Return Value:
1087
1088 Returns 0 on success, -1 on failure.
1089
1090 --*/
1091
1092 {
1093
1094 int ChildLevel;
1095 pid_t ChildPid;
1096 int Flags;
1097 pid_t GrandChildPid1;
1098 pid_t GrandChildPid2;
1099 LXT_CLONE_ARGS CloneArgs;
1100 WAITPID_THREAD_PARAMETERS LocalParameter;
1101 PWAITPID_THREAD_PARAMETERS Parameter;
1102 int Result;
1103 int Status;
1104 LXT_SYNCHRONIZATION_POINT_DECLARE_FOR(ChildPid);
1105 LXT_SYNCHRONIZATION_POINT_DECLARE_FOR(GrandChildPid2);
1106
1107 memcpy(&LocalParameter, Context, sizeof(LocalParameter));
1108 ChildPid = 0;
1109 ChildLevel = LocalParameter.ChildLevel;
1110 if (ChildLevel != 0)
1111 {
1112 free(Context);
1113 }
1114
1115 LxtSyncChildPidParent = LocalParameter.LxtSyncChildPidParent;
1116 LxtSyncChildPidChild = LocalParameter.LxtSyncChildPidChild;
1117 GrandChildPid1 = -1;
1118 GrandChildPid2 = -1;
1119 LxtSyncGrandChildPid2Parent = LocalParameter.LxtSyncGrandChildPid2Parent;
1120 LxtSyncGrandChildPid2Child = LocalParameter.LxtSyncGrandChildPid2Child;
1121 Parameter = NULL;
1122
1123 LxtSignalInitializeThread();
1124
1125 if (ChildLevel == 0)
1126 {
1127 LxtLogInfo("Child %d starting, variation = %d...", getpid(), LocalParameter.Variation);
1128
1129 LxtCheckResult(LxtSignalInitialize());
1130 LxtCheckResult(LxtSignalSetupHandler(SIGCHLD, SA_SIGINFO));
1131 LxtCheckErrno(setsid());
1132 switch (LocalParameter.Variation)
1133 {
1134 case 0:
1135 Flags = SIGCHLD;
1136 break;
1137
1138 case 1:
1139 Flags = CLONE_FS | CLONE_FILES | SIGCHLD;
1140 break;
1141
1142 case 2:
1143 Flags = CLONE_FS | CLONE_FILES;
1144 break;
1145
1146 case 3:
1147 Flags = CLONE_THREAD | CLONE_VM | CLONE_SIGHAND | CLONE_FS | CLONE_FILES;
1148 break;
1149 };
1150
1151 Parameter = malloc(sizeof(*Parameter));
1152 if (Parameter != NULL)
1153 {
1154 memcpy(Parameter, &LocalParameter, sizeof(*Parameter));
1155 }
1156
1157 LxtCheckNotEqual(Parameter, NULL, "%p");
1158 Parameter->ChildLevel = 1;
1159
1160 //
1161 // The clone stack is leaked but the current process will exit shortly.
1162 //
1163
1164 LxtCheckErrno(LxtClone(ThreadZombieThread, Parameter, Flags, &CloneArgs));
1165
1166 Parameter = NULL;
1167 GrandChildPid1 = CloneArgs.CloneId;
1168 LocalParameter.GrandChildPid1 = GrandChildPid1;
1169 Parameter = malloc(sizeof(*Parameter));
1170 if (Parameter != NULL)
1171 {
1172 memcpy(Parameter, &LocalParameter, sizeof(*Parameter));
1173 }
1174
1175 LxtCheckNotEqual(Parameter, NULL, "%p");
1176 Parameter->ChildLevel = 2;
1177
1178 //
1179 // The clone stack is leaked but the current process will exit shortly.
1180 //
1181
1182 LxtCheckErrno(LxtClone(ThreadZombieThread, Parameter, Flags, &CloneArgs));
1183
1184 Parameter = NULL;
1185 LocalParameter.GrandChildPid2 = CloneArgs.CloneId;
1186
1187 LxtSignalWait();
1188 if (LocalParameter.Variation < 2)
1189 {
1190 LxtCheckResult(LxtSignalCheckSigChldReceived(CLD_EXITED, GrandChildPid1, getuid(), 0));
1191 }
1192 else if (LocalParameter.Variation != 3)
1193 {
1194 LxtCheckResult(LxtSignalCheckNoSignal());
1195 }
1196
1197 LXT_SYNCHRONIZATION_POINT_CHILD();
1198 LxtCheckErrno(write(LocalParameter.Pipe.Write, &LocalParameter, sizeof(LocalParameter)));
1199
1200 LXT_SYNCHRONIZATION_POINT_CHILD();
1201
1202 //
1203 // Exiting with one zombie child, and one child waiting for an exit
1204 // signal.
1205 //
1206
1207 LxtLogInfo("Exiting pid = %d", getpid());
1208 Result = 0;
1209 goto ErrorExit;
1210 }
1211 else if (ChildLevel == 1)
1212 {
1213
1214 //
1215 // First child created via this thread, grandchild of the original.
1216 //
1217
1218 GrandChildPid1 = 0;
1219 LxtLogInfo("Grandchild %d starting...", getpid());
1220 LxtLogInfo("Exiting pid = %d", getpid());
1221 Result = 0;
1222 goto ErrorExit;
1223 }
1224 else
1225 {
1226
1227 //
1228 // Second child created via this thread, second grandchild of the
1229 // original.
1230 //
1231
1232 GrandChildPid2 = 0;
1233 LxtLogInfo("Grandchild %d starting...", getpid());
1234 LxtCheckResult(LxtSignalInitialize());
1235 LxtCheckResult(LxtSignalSetupHandler(SIGHUP, SA_SIGINFO));
1236 LXT_SYNCHRONIZATION_POINT_CHILD_FOR(GrandChildPid2);
1237 LxtCheckResult(LxtSignalCheckNoSignal());
1238 LxtLogInfo("Exiting pid = %d", getpid());
1239 Result = 0;
1240 goto ErrorExit;
1241 }
1242
1243 ErrorExit:
1244 if (Result != 0)
1245 {
1246
1247 //
1248 // Intentionally orphaning the thread unless there was an error.
1249 //
1250
1251 LXT_SYNCHRONIZATION_POINT_END_FOR(GrandChildPid2, FALSE);
1252 }
1253
1254 if (ChildLevel == 0)
1255 {
1256 if (LocalParameter.Variation != 3)
1257 {
1258 LXT_SYNCHRONIZATION_POINT_END();
1259 }
1260 else
1261 {
1262 LXT_SYNCHRONIZATION_POINT_PTHREAD_END_THREAD();
1263 }
1264 }
1265
1266 if (Parameter != NULL)
1267 {
1268 free(Parameter);
1269 }
1270
1271 syscall(SYS_exit, Result);
1272 }
1273
1274 int WaitPidVariationZombie(PLXT_ARGS Args)
1275
1276 /*++
1277
1278 Description:
1279
1280 This routine tests zombie handling with waitpid system call.
1281
1282 Arguments:
1283
1284 Args - Supplies the command line arguments.
1285
1286 Return Value:
1287
1288 Returns 0 on success, -1 on failure.
1289
1290 --*/
1291
1292 {
1293
1294 char Buffer[50];
1295 LXT_CLONE_ARGS ChildClone;
1296 int ChildDir;
1297 pid_t ChildPid;
1298 FILE* ChildStatusFile;
1299 pthread_t ChildThread;
1300 int GrandChildDir;
1301 pid_t GrandChildPid1;
1302 pid_t GrandChildPid2;
1303 FILE* GrandChildStatusFile;
1304 int Index;
1305 bool IsFork;
1306 char Path[32];
1307 LXT_PIPE Pipe = {-1, -1};
1308 void* PointerResult;
1309 int Result;
1310 struct stat StatBuffer;
1311 int Status;
1312 char StatusDescription[25];
1313 char* StatusFileEntry;
1314 size_t StatusFileEntryLength;
1315 char StatusToken;
1316 WAITPID_THREAD_PARAMETERS ThreadParam;
1317 LXT_SYNCHRONIZATION_POINT_DECLARE_FOR(GrandChildPid2);
1318
1319 ChildDir = -1;
1320 ChildPid = -1;
1321 ChildStatusFile = NULL;
1322 ChildThread = 0;
1323 GrandChildDir = -1;
1324 GrandChildPid1 = -1;
1325 GrandChildPid2 = -1;
1326 GrandChildStatusFile = NULL;
1327 IsFork = true;
1328 StatusFileEntry = NULL;
1329 LXT_SYNCHRONIZATION_POINT_INIT_FOR(GrandChildPid2);
1330
1331 //
1332 // TODO: test needs to be debugged for WSL2.
1333 //
1334
1335 if (g_VmMode != false)
1336 {
1337 Result = 0;
1338 goto ErrorExit;
1339 }
1340
1341 LxtCheckResult(LxtSignalInitialize());
1342 LxtCheckResult(LxtSignalSetupHandler(SIGCHLD, SA_SIGINFO));
1343 LxtCheckResult(LxtSignalIgnore(SIGPIPE));
1344
1345 memset(&ThreadParam, 0, sizeof(ThreadParam));
1346 ThreadParam.LxtSyncChildPidParent = LxtSyncChildPidParent;
1347 ThreadParam.LxtSyncChildPidChild = LxtSyncChildPidChild;
1348 ThreadParam.LxtSyncGrandChildPid2Parent = LxtSyncGrandChildPid2Parent;
1349 ThreadParam.LxtSyncGrandChildPid2Child = LxtSyncGrandChildPid2Child;
1350 for (Index = 0; Index < 4; Index += 1)
1351 {
1352 ChildPid = -1;
1353 GrandChildPid1 = -1;
1354 GrandChildPid2 = -1;
1355 LXT_SYNCHRONIZATION_POINT_START();
1356 LXT_SYNCHRONIZATION_POINT_START_FOR(GrandChildPid2);
1357 ThreadParam.ChildPid = -1;
1358 ThreadParam.GrandChildPid2 = -1;
1359 ThreadParam.GrandChildPid2 = -1;
1360 LxtCheckResult(LxtCreatePipe(&Pipe));
1361 memcpy(&ThreadParam.Pipe, &Pipe, sizeof(Pipe));
1362 ThreadParam.Variation = Index;
1363 LxtCheckErrno(ChildPid = fork());
1364 if (ChildPid == 0)
1365 {
1366 return ThreadZombieThread(&ThreadParam);
1367 }
1368
1369 ThreadParam.ChildPid = ChildPid;
1370
1371 LXT_SYNCHRONIZATION_POINT();
1372 LxtCheckErrno(read(Pipe.Read, &ThreadParam, sizeof(ThreadParam)));
1373 GrandChildPid1 = ThreadParam.GrandChildPid1;
1374 GrandChildPid2 = ThreadParam.GrandChildPid2;
1375
1376 //
1377 // Check basic info of child after one of its children has entered
1378 // zombie state.
1379 //
1380
1381 LxtCheckErrno(sprintf(Path, "/proc/%d", ChildPid));
1382 LxtCheckErrno(ChildDir = open(Path, O_RDONLY));
1383 LxtCheckErrno(fstat(ChildDir, &StatBuffer));
1384 LxtCheckErrno(sprintf(Path, "/proc/%d/status", ChildPid));
1385 LxtCheckNullErrno(ChildStatusFile = fopen(Path, "r"));
1386 while ((Result = getline(&StatusFileEntry, &StatusFileEntryLength, ChildStatusFile)) >= 0)
1387 {
1388
1389 if (strncmp(StatusFileEntry, "State:\t", 7) == 0)
1390 {
1391 break;
1392 }
1393
1394 free(StatusFileEntry);
1395 StatusFileEntry = NULL;
1396 }
1397
1398 LxtCheckErrno(Result);
1399 Result = sscanf(StatusFileEntry, "State: %c (%s)", &StatusToken, StatusDescription);
1400
1401 LxtCheckEqual(Result, 2, "%d");
1402 if (StatusToken == 'R')
1403 {
1404 LxtCheckStringEqual(StatusDescription, "running)");
1405 }
1406 else if (StatusToken == 'S')
1407 {
1408 LxtCheckStringEqual(StatusDescription, "sleeping)");
1409 }
1410 else
1411 {
1412 LxtLogError("Unexpected status: %c (%s)", StatusToken, StatusDescription);
1413 Result = -1;
1414 goto ErrorExit;
1415 }
1416
1417 LxtCheckErrno(getpgid(ChildPid));
1418 LxtCheckErrno(kill(ChildPid, SIGWINCH));
1419 LxtCheckErrno(sprintf(Path, "/proc/%d/ns/mnt", ChildPid));
1420 LxtCheckErrno(readlink(Path, Buffer, sizeof(Buffer)));
1421 LxtCheckErrno(sprintf(Path, "/proc/%d/fd/0", ChildPid));
1422 LxtCheckErrno(stat(Path, &StatBuffer));
1423
1424 //
1425 // Check basic info of first zombie.
1426 //
1427
1428 LxtCheckErrno(sprintf(Path, "/proc/%d", GrandChildPid1));
1429 if (Index != 3)
1430 {
1431 LxtCheckErrno(getpgid(GrandChildPid1));
1432 LxtCheckErrno(kill(GrandChildPid1, SIGWINCH));
1433 LxtCheckErrno(GrandChildDir = open(Path, O_RDONLY));
1434 LxtCheckErrno(fstat(GrandChildDir, &StatBuffer));
1435 LxtCheckErrno(sprintf(Path, "/proc/%d/fd/0", GrandChildPid1));
1436
1437 //
1438 // TODO_LX: Zombied procfs "fd" entry should be accessible but
1439 // empty.
1440 //
1441 // LxtCheckErrnoFailure(stat(Path, &StatBuffer), ENOENT);
1442 //
1443
1444 LxtCheckErrno(sprintf(Path, "/proc/%d/status", GrandChildPid1));
1445 LxtCheckNullErrno(GrandChildStatusFile = fopen(Path, "r"));
1446 free(StatusFileEntry);
1447 StatusFileEntry = NULL;
1448 while ((Result = getline(&StatusFileEntry, &StatusFileEntryLength, GrandChildStatusFile)) >= 0)
1449 {
1450
1451 if (strncmp(StatusFileEntry, "State:\t", 7) == 0)
1452 {
1453 break;
1454 }
1455
1456 free(StatusFileEntry);
1457 StatusFileEntry = NULL;
1458 }
1459
1460 LxtCheckErrno(Result);
1461 Result = sscanf(StatusFileEntry, "State: %c (%s)", &StatusToken, StatusDescription);
1462
1463 LxtCheckEqual(Result, 2, "%d");
1464 LxtCheckEqual(StatusToken, 'Z', "%c");
1465 LxtCheckStringEqual(StatusDescription, "zombie)");
1466
1467 LxtCheckErrno(sprintf(Path, "/proc/%d/fd/0", GrandChildPid1));
1468
1469 //
1470 // TODO_LX: Zombied procfs "fd" entry should be accessible but
1471 // empty.
1472 //
1473 // LxtCheckErrnoFailure(open(Path, O_RDONLY), ENOENT);
1474 //
1475 }
1476 else
1477 {
1478 LxtCheckErrnoFailure(GrandChildDir = open(Path, O_RDONLY), ENOENT);
1479 }
1480
1481 //
1482 // Close the read end of the pipe.
1483 //
1484
1485 close(Pipe.Read);
1486 Pipe.Read = -1;
1487 LxtCheckErrno(write(Pipe.Write, &Result, sizeof(Result)));
1488
1489 //
1490 // Allow the child to exit.
1491 //
1492
1493 LXT_SYNCHRONIZATION_POINT();
1494 LxtSignalWait();
1495 if (Index != 3)
1496 {
1497 LxtCheckResult(LxtSignalCheckSigChldReceived(CLD_EXITED, ChildPid, getuid(), 0));
1498
1499 LxtSignalResetReceived();
1500 }
1501 else
1502 {
1503
1504 //
1505 // The threadgroup leader should have exited but there is still a
1506 // thread running so the signal will not yet be sent.
1507 //
1508
1509 LxtCheckResult(LxtSignalCheckNoSignal());
1510 }
1511
1512 //
1513 // Check basic info of running grandchild after child exit.
1514 //
1515
1516 if (Index != 3)
1517 {
1518
1519 //
1520 // TODO_LX: These calls fail due to lack of proper thread support.
1521 //
1522
1523 LxtCheckErrno(getpgid(GrandChildPid2));
1524 LxtCheckErrno(kill(GrandChildPid2, SIGWINCH));
1525 }
1526
1527 LxtCheckErrno(sprintf(Path, "/proc/%d/ns/mnt", GrandChildPid2));
1528 LxtCheckErrno(readlink(Path, Buffer, sizeof(Buffer)));
1529 LxtCheckErrno(sprintf(Path, "/proc/%d/fd/0", GrandChildPid2));
1530 LxtCheckErrno(stat(Path, &StatBuffer));
1531
1532 //
1533 // Signal last grandchild to exit.
1534 //
1535
1536 LXT_SYNCHRONIZATION_POINT_PARENT_FOR(GrandChildPid2);
1537 LxtSignalWait();
1538 if (Index == 3)
1539 {
1540 LxtCheckResult(LxtSignalCheckSigChldReceived(CLD_EXITED, ChildPid, getuid(), 0));
1541
1542 LxtSignalResetReceived();
1543 }
1544
1545 //
1546 // Check the child information after it is a zombie.
1547 //
1548
1549 LxtCheckErrno(fstat(ChildDir, &StatBuffer));
1550 rewind(ChildStatusFile);
1551 free(StatusFileEntry);
1552 StatusFileEntry = NULL;
1553 while ((Result = getline(&StatusFileEntry, &StatusFileEntryLength, ChildStatusFile)) >= 0)
1554 {
1555
1556 if (strncmp(StatusFileEntry, "State:\t", 7) == 0)
1557 {
1558 break;
1559 }
1560
1561 free(StatusFileEntry);
1562 StatusFileEntry = NULL;
1563 }
1564
1565 LxtCheckErrno(Result);
1566 Result = sscanf(StatusFileEntry, "State: %c (%s)", &StatusToken, StatusDescription);
1567
1568 LxtCheckEqual(Result, 2, "%d");
1569 LxtCheckEqual(StatusToken, 'Z', "%c");
1570 LxtCheckStringEqual(StatusDescription, "zombie)");
1571 LxtCheckErrno(getpgid(ChildPid));
1572 LxtCheckErrno(kill(ChildPid, SIGWINCH));
1573 LxtCheckErrno(sprintf(Path, "/proc/%d/ns/mnt", ChildPid));
1574 LxtCheckErrnoFailure(readlink(Path, Buffer, sizeof(Buffer)), ENOENT);
1575 sleep(2);
1576 LxtCheckErrnoFailure(write(Pipe.Write, &Result, sizeof(Result)), EPIPE);
1577
1578 LXT_SYNCHRONIZATION_POINT_END();
1579 ChildPid = -1;
1580 LxtCheckErrnoFailure(waitpid(-1, &Status, WNOHANG), ECHILD);
1581 LxtCheckEqual(Result, 0, "%d");
1582 LxtClosePipe(&Pipe);
1583 }
1584
1585 ErrorExit:
1586 free(StatusFileEntry);
1587 LXT_SYNCHRONIZATION_POINT_END();
1588 if (GrandChildPid2 > 0)
1589 {
1590 LXT_SYNCHRONIZATION_POINT_PTHREAD_END_THREAD_FOR(GrandChildPid2);
1591 }
1592
1593 LXT_SYNCHRONIZATION_POINT_DESTROY_FOR(GrandChildPid2);
1594 if (GrandChildStatusFile != NULL)
1595 {
1596 fclose(GrandChildStatusFile);
1597 }
1598
1599 if (GrandChildDir >= 0)
1600 {
1601 close(GrandChildDir);
1602 }
1603
1604 if (ChildStatusFile != NULL)
1605 {
1606 fclose(ChildStatusFile);
1607 }
1608
1609 if (ChildDir >= 0)
1610 {
1611 close(ChildDir);
1612 }
1613
1614 //
1615 // Intentionally leaking pipes from children / grandchildren to test
1616 // file descriptor cleanup on exit in the fork case.
1617 //
1618
1619 LxtClosePipe(&Pipe);
1620
1621 LxtSignalDefault(SIGPIPE);
1622 LxtSignalDefault(SIGCHLD);
1623 return Result;
1624 }
1625
1626 int WaitPidVariationZombieStress(PLXT_ARGS Args)
1627
1628 /*++
1629
1630 Description:
1631
1632 This routine stress tests zombie handling.
1633
1634 Arguments:
1635
1636 Args - Supplies the command line arguments.
1637
1638 Return Value:
1639
1640 Returns 0 on success, -1 on failure.
1641
1642 --*/
1643
1644 {
1645
1646 pid_t ChildPid;
1647 pid_t GrandChildPid;
1648 pid_t GreatGrandChildPid;
1649 int Iterations;
1650 int Result;
1651 int Status;
1652
1653 GrandChildPid = -1;
1654 GreatGrandChildPid = -1;
1655 for (Iterations = 0; Iterations < 100; Iterations += 1)
1656 {
1657 ChildPid = -1;
1658 LxtCheckErrno(ChildPid = fork());
1659 if (ChildPid == 0)
1660 {
1661 LxtCheckErrno(setsid());
1662 LxtCheckErrno(prctl(PR_SET_CHILD_SUBREAPER, 1));
1663 for (Iterations = 0; Iterations < 3; Iterations += 1)
1664 {
1665 LxtCheckErrno(GrandChildPid = fork());
1666 if (GrandChildPid == 0)
1667 {
1668 ChildPid = -1;
1669 LxtCheckErrno(GreatGrandChildPid = fork());
1670 if (GreatGrandChildPid == 0)
1671 {
1672 usleep(random() % 100);
1673 goto ErrorExit;
1674 }
1675
1676 usleep(random() % 100);
1677 (void)waitpid(GreatGrandChildPid, &Status, WNOHANG);
1678 goto ErrorExit;
1679 }
1680
1681 (void)waitpid(GrandChildPid, &Status, WNOHANG);
1682 }
1683
1684 usleep(random() % 100);
1685 (void)waitpid(GrandChildPid, &Status, WNOHANG);
1686 goto ErrorExit;
1687 }
1688
1689 LXT_SYNCHRONIZATION_POINT_END();
1690 ChildPid = -1;
1691 }
1692
1693 ErrorExit:
1694 if ((GreatGrandChildPid == 0) || (GrandChildPid == 0))
1695 {
1696 _exit(Result);
1697 }
1698
1699 LXT_SYNCHRONIZATION_POINT_END();
1700 return Result;
1701 }