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