in reply to forking through a subroutine

You might want different behavior if the parent is just done, or if you've gone and SIGINTed (control-c) the parent. For This is wrote a little set that had some useful code in it: The code follows:
use POSIX qw(:sys_wait_h); use IO::Handle; my %scythe; # a scythe for the REAPER (see FAQ); $SIG{CHLD} = \&REAPER; # set handling of zombie child process +es. STDOUT->autoflush; # make sure output is flushed before f +orking # setup an interupt handler # kills every pid used as a key in %scythe #################### $SIG{INT} = sub { print "\nCleaning: "; print join(", ", keys(%scythe)); print "\n"; kill('INT', keys %scythe); print "done with: "; print join(", ", keys(%scythe)); die "\n"; }; #### MAIN #### #### END MAIN, begin defs #### sub phork { # we will call fork and return a pid. The child will exec with all +args # and suppress the child's output; my $pid; if ($pid = fork) { # fork the process; #parent return $pid; }else { #child die "CANNOT FORK!!\n" unless defined $pid; close(STDOUT); # suppressing output close(STDERR); # suppressing output {exec(@_);}; # calls exec with current @_ exit(1); # exec may maybe fail... maybe +. } } sub baitKiller { # This functions is a dummy to be used to be added to %scythe for a $ +pid # This way when the interupt is called, the process with the $pid wil +l # be cleaned up (killed) so it doesn't keep running after its parent' +s # death. If you'd rather it did, just don't assign anything in %scyt +he # for the key of it's $pid. return "Come get some!"; } sub REAPER { # we reap child processes, and post process it. # note: this sub relies on a global %scythe # sort of... if a $scythe{$pid} is defined, it will assume that its + a # reference to a function that takes $pid and $exit_value as args # and presumably does something useful with that. Then it deletes + the # $scythe{$pid} hash entry. is it not nifty? # local vars my $pid; my $exit_value; $pid = waitpid(-1, &WNOHANG); if($pid == -1) { # no child waiting } elsif (WIFEXITED($?)) { # the process exited, get exit value. my $slot; my $state; $exit_value = $? >> 8; if (exists($scythe{$pid})) { $scythe{$pid}->( $pid, $exit_value ); delete($scythe{$pid}); } else { # we're reaping something we didn't sow or didn't care about; return; } } else { # false alarm on $pid } $SIG{CHLD} = \&REAPER; #reset signal handling. } #end sub REAPER

Replies are listed 'Best First'.
Re: Re: forking through a subroutine
by leons (Pilgrim) on Apr 10, 2001 at 12:41 UTC
    Hi,

    I'm writing something similar as well at this moment which
    might come in handy.

    You can pass a reference to a sub and it's parameters to the
    spawnChild sub, which will provide you with it's PID and
    a filehandler to the child.

    It's all still very basic and nothing fancy, that's because I'm
    doing lots of learning and testing right now ... but it works ;-)

    #!/usr/bin/perl -w use strict; # # Declaration of Subroutines # sub spawnChild(@); # # Main # my ($pid,$fh)=spawnChild(\&Count,10); print "$pid\n"; # # Subroutines # sub spawnChild(@) { my $childSub=shift; my @Parameters=@_; my ($Cnt,$pid)=0; do { $pid=open FH,'-|'; unless (defined $pid) { warn "Cannot fork: $!\n"; die "Could not fork\n" if $Cnt++ > 5; sleep 10; } } until defined $pid; if ($pid) { #Parent return($pid,*{FH}); } else { #Child; &$childSub(@Parameters); exit(0); } } sub Count($) { foreach(1..shift) { print "$_\n"; sleep(1); } }

    Bye, Leon