i have this program, which forks-off worker processes, and then runs in them various tasks.
one of the tasks is to execute some command via system(), but since we need to get stdout and stderr (separately), we used ipc::run module.
simple example of such code would be:
#!/usr/bin/perl
use strict;
use Time::HiRes qw( usleep );
use IPC::Run qw( run );
use POSIX ":sys_wait_h";
sub REAPER {
my $child;
while (($child = waitpid(-1,WNOHANG)) > 0) {
}
$SIG{CHLD} = \&REAPER;
}
$SIG{CHLD} = \&REAPER;
for (1..100) {
my $x = fork;
die "cannot fork?!: $!\n" unless defined $x;
if ($x) {
usleep(10000);
next;
}
my @cmd = qw(ls -lad .);
my ($in, $out, $err);
my $status = run \@cmd, \$in, \$out, \$err or die "ls: $?";
printf ("%u\n", $status);
exit;
}
what it does:
- defines REAPER function, and sets it as sigchld handler – for details, please check perldoc perlipc. this is basically to avoid creation of zombie processes in case we have long-running parent process, which forks relatively short-lived child-processes.
- forks off new process
- after forking, master sleeps for 0.01 second (not to put to much pressure on testing system)
- child process runs sample command (ls -ald .) via ipc::run, with empty stdin, and catching stdout and stderr.
- child then exits
- whole forking/ls-ald. thing is repeated 100 times to show that it's effect is not random.
what's wrong? here is output from it on my machine:
=> perl test.pl
ls: -1 at test.pl line 24.
...
...
...
which basically means ls failed – which is far from true, as this ls succeeds, simple check:
=> perl -e 'use IPC::Run qw(run);my @cmd = qw(ls -lad .);my ($in, $out, $err);my $status = run \@cmd, \$in, \$out, \$err or die "ls: $?";printf ("%u\n", $status);'
1
now, the riddle is: why it fails? (yes, i now know the answer, but it took me some time).