Commit | Line | Data |
---|---|---|
098f0b12 RGS |
1 | #!./perl |
2 | ||
3 | # Test that getppid() follows UNIX semantics: when the parent process | |
a428795d NC |
4 | # dies, the child is reparented to the init process |
5 | # The init process is usually 1, but doesn't have to be, and there's no | |
6 | # standard way to find out what it is, so the only portable way to go it so | |
7 | # attempt 2 reparentings and see if the PID both orphaned grandchildren get is | |
8 | # the same. (and not ours) | |
098f0b12 RGS |
9 | |
10 | BEGIN { | |
11 | chdir 't' if -d 't'; | |
12 | @INC = qw(../lib); | |
13 | } | |
14 | ||
15 | use strict; | |
098f0b12 RGS |
16 | |
17 | BEGIN { | |
a428795d | 18 | require './test.pl'; |
77ba2250 | 19 | skip_all_without_config(qw(d_pipe d_fork d_waitpid d_getppid)); |
bd5a473b | 20 | plan (8); |
098f0b12 RGS |
21 | } |
22 | ||
e5325a77 NC |
23 | # No, we don't want any zombies. kill 0, $ppid spots zombies :-( |
24 | $SIG{CHLD} = 'IGNORE'; | |
25 | ||
a428795d NC |
26 | sub fork_and_retrieve { |
27 | my $which = shift; | |
28 | pipe my ($r, $w) or die "pipe: $!\n"; | |
29 | my $pid = fork; defined $pid or die "fork: $!\n"; | |
098f0b12 | 30 | |
a428795d NC |
31 | if ($pid) { |
32 | # parent | |
a374d15c | 33 | close $w or die "close: $!\n"; |
a428795d NC |
34 | $_ = <$r>; |
35 | chomp; | |
36 | die "Garbled output '$_'" | |
e5325a77 | 37 | unless my ($how, $first, $second) = /^([a-z]+),(\d+),(\d+)\z/; |
a428795d | 38 | cmp_ok ($first, '>=', 1, "Parent of $which grandchild"); |
e5325a77 NC |
39 | my $message = "grandchild waited until '$how'"; |
40 | cmp_ok ($second, '>=', 1, "New parent of orphaned $which grandchild") | |
41 | ? note ($message) : diag ($message); | |
42 | ||
185a8799 MK |
43 | SKIP: { |
44 | skip("Orphan processes are not reparented on QNX", 1) | |
45 | if $^O eq 'nto'; | |
46 | isnt($first, $second, | |
47 | "Orphaned $which grandchild got a new parent"); | |
48 | } | |
a428795d | 49 | return $second; |
098f0b12 RGS |
50 | } |
51 | else { | |
a428795d NC |
52 | # child |
53 | # Prevent test.pl from thinking that we failed to run any tests. | |
54 | $::NO_ENDING = 1; | |
a374d15c | 55 | close $r or die "close: $!\n"; |
a428795d | 56 | |
7285a48a NC |
57 | pipe my ($r2, $w2) or die "pipe: $!\n"; |
58 | pipe my ($r3, $w3) or die "pipe: $!\n"; | |
a428795d NC |
59 | my $pid2 = fork; defined $pid2 or die "fork: $!\n"; |
60 | if ($pid2) { | |
a374d15c | 61 | close $w or die "close: $!\n"; |
7285a48a NC |
62 | close $w2 or die "close: $!\n"; |
63 | close $r3 or die "close: $!\n"; | |
64 | # Wait for our child to signal that it's read our PID: | |
65 | <$r2>; | |
66 | # Implicit close of $w3: | |
67 | exit 0; | |
a428795d NC |
68 | } |
69 | else { | |
70 | # grandchild | |
7285a48a NC |
71 | close $r2 or die "close: $!\n"; |
72 | close $w3 or die "close: $!\n"; | |
a428795d | 73 | my $ppid1 = getppid(); |
e5325a77 NC |
74 | # kill 0 isn't portable: |
75 | my $can_kill0 = eval { | |
76 | kill 0, $ppid1; | |
77 | }; | |
78 | my $how = $can_kill0 ? 'undead' : 'sleep'; | |
79 | ||
7285a48a NC |
80 | # Tell immediate parent to exit: |
81 | close $w2 or die "close: $!\n"; | |
82 | # Wait for it to (start to) exit: | |
83 | <$r3>; | |
84 | # Which sadly isn't enough to be sure that it has exited - often we | |
85 | # get switched in during its shutdown, after $w3 closes but before | |
e5325a77 NC |
86 | # it exits and we get reparented. |
87 | if ($can_kill0) { | |
88 | # use kill 0 where possible. Try 10 times, then give up: | |
89 | for (0..9) { | |
90 | my $got = kill 0, $ppid1; | |
91 | die "kill: $!" unless defined $got; | |
92 | if (!$got) { | |
93 | $how = 'kill'; | |
94 | last; | |
95 | } | |
96 | sleep 1; | |
97 | } | |
98 | } else { | |
99 | # Fudge it by waiting a bit more: | |
100 | sleep 2; | |
101 | } | |
a428795d | 102 | my $ppid2 = getppid(); |
e5325a77 | 103 | print $w "$how,$ppid1,$ppid2\n"; |
a428795d NC |
104 | } |
105 | exit 0; | |
098f0b12 | 106 | } |
098f0b12 | 107 | } |
a428795d NC |
108 | |
109 | my $first = fork_and_retrieve("first"); | |
110 | my $second = fork_and_retrieve("second"); | |
185a8799 MK |
111 | SKIP: { |
112 | skip ("Orphan processes are not reparented on QNX", 1) if $^O eq 'nto'; | |
113 | is ($first, $second, "Both orphaned grandchildren get the same new parent"); | |
114 | } | |
bd5a473b | 115 | isnt ($first, $$, "And that new parent isn't this process"); |