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