xref: /openbsd-src/gnu/usr.bin/perl/t/op/fork.t (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1#!./perl
2
3# tests for both real and emulated fork()
4
5BEGIN {
6    chdir 't' if -d 't';
7    @INC = '../lib';
8    require Config; import Config;
9    unless ($Config{'d_fork'}
10	    or ($^O eq 'MSWin32' and $Config{useithreads}
11		and $Config{ccflags} =~ /-DPERL_IMPLICIT_SYS/))
12    {
13	print "1..0 # Skip: no fork\n";
14	exit 0;
15    }
16    $ENV{PERL5LIB} = "../lib";
17}
18
19if ($^O eq 'mpeix') {
20    print "1..0 # Skip: fork/status problems on MPE/iX\n";
21    exit 0;
22}
23
24$|=1;
25
26undef $/;
27@prgs = split "\n########\n", <DATA>;
28print "1..", scalar @prgs, "\n";
29
30$tmpfile = "forktmp000";
311 while -f ++$tmpfile;
32END { close TEST; unlink $tmpfile if $tmpfile; }
33
34$CAT = (($^O eq 'MSWin32') ? '.\perl -e "print <>"' : 'cat');
35
36for (@prgs){
37    my $switch;
38    if (s/^\s*(-\w.*)//){
39	$switch = $1;
40    }
41    my($prog,$expected) = split(/\nEXPECT\n/, $_);
42    $expected =~ s/\n+$//;
43    # results can be in any order, so sort 'em
44    my @expected = sort split /\n/, $expected;
45    open TEST, ">$tmpfile" or die "Cannot open $tmpfile: $!";
46    print TEST $prog, "\n";
47    close TEST or die "Cannot close $tmpfile: $!";
48    my $results;
49    if ($^O eq 'MSWin32') {
50      $results = `.\\perl -I../lib $switch $tmpfile 2>&1`;
51    }
52    else {
53      $results = `./perl $switch $tmpfile 2>&1`;
54    }
55    $status = $?;
56    $results =~ s/\n+$//;
57    $results =~ s/at\s+forktmp\d+\s+line/at - line/g;
58    $results =~ s/of\s+forktmp\d+\s+aborted/of - aborted/g;
59# bison says 'parse error' instead of 'syntax error',
60# various yaccs may or may not capitalize 'syntax'.
61    $results =~ s/^(syntax|parse) error/syntax error/mig;
62    $results =~ s/^\n*Process terminated by SIG\w+\n?//mg
63	if $^O eq 'os2';
64    my @results = sort split /\n/, $results;
65    if ( "@results" ne "@expected" ) {
66	print STDERR "PROG: $switch\n$prog\n";
67	print STDERR "EXPECTED:\n$expected\n";
68	print STDERR "GOT:\n$results\n";
69	print "not ";
70    }
71    print "ok ", ++$i, "\n";
72}
73
74__END__
75$| = 1;
76if ($cid = fork) {
77    sleep 1;
78    if ($result = (kill 9, $cid)) {
79	print "ok 2\n";
80    }
81    else {
82	print "not ok 2 $result\n";
83    }
84    sleep 1 if $^O eq 'MSWin32';	# avoid WinNT race bug
85}
86else {
87    print "ok 1\n";
88    sleep 10;
89}
90EXPECT
91ok 1
92ok 2
93########
94$| = 1;
95sub forkit {
96    print "iteration $i start\n";
97    my $x = fork;
98    if (defined $x) {
99	if ($x) {
100	    print "iteration $i parent\n";
101	}
102	else {
103	    print "iteration $i child\n";
104	}
105    }
106    else {
107	print "pid $$ failed to fork\n";
108    }
109}
110while ($i++ < 3) { do { forkit(); }; }
111EXPECT
112iteration 1 start
113iteration 1 parent
114iteration 1 child
115iteration 2 start
116iteration 2 parent
117iteration 2 child
118iteration 2 start
119iteration 2 parent
120iteration 2 child
121iteration 3 start
122iteration 3 parent
123iteration 3 child
124iteration 3 start
125iteration 3 parent
126iteration 3 child
127iteration 3 start
128iteration 3 parent
129iteration 3 child
130iteration 3 start
131iteration 3 parent
132iteration 3 child
133########
134$| = 1;
135fork()
136 ? (print("parent\n"),sleep(1))
137 : (print("child\n"),exit) ;
138EXPECT
139parent
140child
141########
142$| = 1;
143fork()
144 ? (print("parent\n"),exit)
145 : (print("child\n"),sleep(1)) ;
146EXPECT
147parent
148child
149########
150$| = 1;
151@a = (1..3);
152for (@a) {
153    if (fork) {
154	print "parent $_\n";
155	$_ = "[$_]";
156    }
157    else {
158	print "child $_\n";
159	$_ = "-$_-";
160    }
161}
162print "@a\n";
163EXPECT
164parent 1
165child 1
166parent 2
167child 2
168parent 2
169child 2
170parent 3
171child 3
172parent 3
173child 3
174parent 3
175child 3
176parent 3
177child 3
178[1] [2] [3]
179-1- [2] [3]
180[1] -2- [3]
181[1] [2] -3-
182-1- -2- [3]
183-1- [2] -3-
184[1] -2- -3-
185-1- -2- -3-
186########
187$| = 1;
188foreach my $c (1,2,3) {
189    if (fork) {
190	print "parent $c\n";
191    }
192    else {
193	print "child $c\n";
194	exit;
195    }
196}
197while (wait() != -1) { print "waited\n" }
198EXPECT
199child 1
200child 2
201child 3
202parent 1
203parent 2
204parent 3
205waited
206waited
207waited
208########
209use Config;
210$| = 1;
211$\ = "\n";
212fork()
213 ? print($Config{osname} eq $^O)
214 : print($Config{osname} eq $^O) ;
215EXPECT
2161
2171
218########
219$| = 1;
220$\ = "\n";
221fork()
222 ? do { require Config; print($Config::Config{osname} eq $^O); }
223 : do { require Config; print($Config::Config{osname} eq $^O); }
224EXPECT
2251
2261
227########
228$| = 1;
229use Cwd;
230$\ = "\n";
231my $dir;
232if (fork) {
233    $dir = "f$$.tst";
234    mkdir $dir, 0755;
235    chdir $dir;
236    print cwd() =~ /\Q$dir/i ? "ok 1 parent" : "not ok 1 parent";
237    chdir "..";
238    rmdir $dir;
239}
240else {
241    sleep 2;
242    $dir = "f$$.tst";
243    mkdir $dir, 0755;
244    chdir $dir;
245    print cwd() =~ /\Q$dir/i ? "ok 1 child" : "not ok 1 child";
246    chdir "..";
247    rmdir $dir;
248}
249EXPECT
250ok 1 parent
251ok 1 child
252########
253$| = 1;
254$\ = "\n";
255my $getenv;
256if ($^O eq 'MSWin32') {
257    $getenv = qq[$^X -e "print \$ENV{TST}"];
258}
259else {
260    $getenv = qq[$^X -e 'print \$ENV{TST}'];
261}
262$ENV{TST} = 'foo';
263if (fork) {
264    sleep 1;
265    print "parent before: " . `$getenv`;
266    $ENV{TST} = 'bar';
267    print "parent after: " . `$getenv`;
268}
269else {
270    print "child before: " . `$getenv`;
271    $ENV{TST} = 'baz';
272    print "child after: " . `$getenv`;
273}
274EXPECT
275child before: foo
276child after: baz
277parent before: foo
278parent after: bar
279########
280$| = 1;
281$\ = "\n";
282if ($pid = fork) {
283    waitpid($pid,0);
284    print "parent got $?"
285}
286else {
287    exit(42);
288}
289EXPECT
290parent got 10752
291########
292$| = 1;
293$\ = "\n";
294my $echo = 'echo';
295if ($pid = fork) {
296    waitpid($pid,0);
297    print "parent got $?"
298}
299else {
300    exec("$echo foo");
301}
302EXPECT
303foo
304parent got 0
305########
306if (fork) {
307    die "parent died";
308}
309else {
310    die "child died";
311}
312EXPECT
313parent died at - line 2.
314child died at - line 5.
315########
316if ($pid = fork) {
317    eval { die "parent died" };
318    print $@;
319}
320else {
321    eval { die "child died" };
322    print $@;
323}
324EXPECT
325parent died at - line 2.
326child died at - line 6.
327########
328if (eval q{$pid = fork}) {
329    eval q{ die "parent died" };
330    print $@;
331}
332else {
333    eval q{ die "child died" };
334    print $@;
335}
336EXPECT
337parent died at (eval 2) line 1.
338child died at (eval 2) line 1.
339########
340BEGIN {
341    $| = 1;
342    fork and exit;
343    print "inner\n";
344}
345# XXX In emulated fork(), the child will not execute anything after
346# the BEGIN block, due to difficulties in recreating the parse stacks
347# and restarting yyparse() midstream in the child.  This can potentially
348# be overcome by treating what's after the BEGIN{} as a brand new parse.
349#print "outer\n"
350EXPECT
351inner
352########
353sub pipe_to_fork ($$) {
354    my $parent = shift;
355    my $child = shift;
356    pipe($child, $parent) or die;
357    my $pid = fork();
358    die "fork() failed: $!" unless defined $pid;
359    close($pid ? $child : $parent);
360    $pid;
361}
362
363if (pipe_to_fork('PARENT','CHILD')) {
364    # parent
365    print PARENT "pipe_to_fork\n";
366    close PARENT;
367}
368else {
369    # child
370    while (<CHILD>) { print; }
371    close CHILD;
372    exit;
373}
374
375sub pipe_from_fork ($$) {
376    my $parent = shift;
377    my $child = shift;
378    pipe($parent, $child) or die;
379    my $pid = fork();
380    die "fork() failed: $!" unless defined $pid;
381    close($pid ? $child : $parent);
382    $pid;
383}
384
385if (pipe_from_fork('PARENT','CHILD')) {
386    # parent
387    while (<PARENT>) { print; }
388    close PARENT;
389}
390else {
391    # child
392    print CHILD "pipe_from_fork\n";
393    close CHILD;
394    exit;
395}
396EXPECT
397pipe_from_fork
398pipe_to_fork
399########
400$|=1;
401if ($pid = fork()) {
402    print "forked first kid\n";
403    print "waitpid() returned ok\n" if waitpid($pid,0) == $pid;
404}
405else {
406    print "first child\n";
407    exit(0);
408}
409if ($pid = fork()) {
410    print "forked second kid\n";
411    print "wait() returned ok\n" if wait() == $pid;
412}
413else {
414    print "second child\n";
415    exit(0);
416}
417EXPECT
418forked first kid
419first child
420waitpid() returned ok
421forked second kid
422second child
423wait() returned ok
424