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