#./prefork.pl & # ps -ef | grep prefork.pl root 22626 947 0 15:34 pts/3 ./prefork.pl root 22627 22626 0 15:34 pts/3 ./prefork.pl root 22628 22626 0 15:34 pts/3 ./prefork.pl #kill 22626 #ps -ef | grep prefork root 22627 1 0 15:34 pts/3 ./prefork.pl root 22628 1 0 15:34 pts/3 ./prefork.pl #### =for nobody sub REAPER { # takes care of dead children my $pid = wait; $children--; delete $children{$pid}; $SIG{CHLD} = \&REAPER; # reset as necessary, should be at end } sub HUNTSMAN { # signal handler for SIGINT local ( $SIG{CHLD} ) = 'IGNORE'; # we're going to kill our children kill 'INT' => keys %children; exit 0; # clean up with dignity } =cut # Install signal handlers. #$SIG{CHLD} = \&REAPER; #$SIG{INT} = \&HUNTSMAN; #### #!/usr/bin/perl # preforker - server who forks first use strict; use warnings; use IO::Socket; use Symbol; use POSIX; # establish SERVER socket, bind and listen. my $server = IO::Socket::INET->new( LocalPort => 6969, Type => SOCK_STREAM, Proto => 'tcp', Reuse => 1, Listen => 10 ) or die "making socket: $@\n"; # global variables my $PREFORK = 2; # number of children to maintain my $MAX_CLIENTS_PER_CHILD = 5; # number of clients each child should process my %children = (); # keys are current child process IDs my $children = 0; # current number of children my $client; sub REAPER { # takes care of dead children my $pid = wait; $children--; delete $children{$pid}; $SIG{CHLD} = \&REAPER;# reset as necessary, should be at end } sub HUNTSMAN { # signal handler for SIGINT local ( $SIG{CHLD} ) = 'IGNORE'; # we're going to kill our children kill 'INT' => keys %children; exit 0; # clean up with dignity } # Fork off our children. for ( 1 .. $PREFORK ) { make_new_child(); } # Install signal handlers. $SIG{CHLD} = \&REAPER; $SIG{INT} = \&HUNTSMAN; # And maintain the population. while (1) { sleep; # wait for a signal (i.e., child's death) my $i; for ( $i = $children ; $i < $PREFORK ; $i++ ) { make_new_child(); # top up the child pool } } sub make_new_child { my $pid; my $sigset; my $i; # block signal for fork $sigset = POSIX::SigSet->new(SIGINT); sigprocmask( SIG_BLOCK, $sigset ) or die "Can't block SIGINT for fork: $!\n"; die "fork: $!" unless defined( $pid = fork ); if ($pid) { # Parent records the child's birth and returns. sigprocmask( SIG_UNBLOCK, $sigset ) or die "Can't unblock SIGINT for fork: $!\n"; $children{$pid} = 1; $children++; return; } else { # Child can *not* return from this subroutine. $SIG{INT} = 'DEFAULT'; # make SIGINT kill us as it did before # unblock signals sigprocmask( SIG_UNBLOCK, $sigset ) or die "Can't unblock SIGINT for fork: $!\n"; # handle connections until we've reached $MAX_CLIENTS_PER_CHILD for ( $i = 0 ; $i < $MAX_CLIENTS_PER_CHILD ; $i++ ) { $client = $server->accept() or last; # do something with the connection } # tidy up gracefully and finish # this exit is VERY important, otherwise the child will become # a producer of more and more children, forking yourself into # process death. exit; } }