NetServer-Generic
view release on metacpan or search on metacpan
my $n = "_do_preforked_adult($$)"; # for reporting status
my $start_servers = ( $self->start_servers() or 5 );
my $spare_servers = ( $self->min_spare_servers() or 1 );
my $max_servers = ( $self->max_servers() or 10 );
my $scoreboard = ( $self->scoreboard() or {} );
$SIG{CHLD} = \&reap_child;
my @buffer = ();
my $buffer = "";
$NetServer::Debug && print STDERR "$n: About to loop on scoreboard file\n";
my $loopcnt = 0;
my $busycnt = 0;
my @busyvec = ();
#while(@buffer = $self->_read_fifo()) {
*READ_PIPE = $self->read_pipe();
while($buffer = <READ_PIPE>) {
$NetServer::Debug
&& print STDERR "busyvec: [", join("][", @busyvec), "]\n";
$loopcnt++;
$NetServer::Debug
&& print STDERR "$n: in pipe read loop $loopcnt\n";
$buffer =~ tr/ //;
chomp $buffer;
$NetServer::Debug
&& print STDERR "$n: buffer: $buffer\n";
my ($child_pid, $status) = split(/:/, $buffer);
# kids write $$:busy or $$:idle into the pipe whenever
# they change state.
if ($status eq "exit") {
# a child just exited on us
$NetServer::Debug
&& print STDERR "$n: child $child_pid just died\n";
delete($scoreboard->{$child_pid});
} elsif ($status eq "busy") {
$scoreboard->{$child_pid} = "busy";
push(@busyvec, $child_pid);
$busycnt++;
} elsif ($status eq "idle") {
$scoreboard->{$child_pid} = "idle";
@busyvec = grep(!/$child_pid/, @busyvec);
$busycnt--;
} elsif ($status eq "start") {
$scoreboard->{$child_pid} = "idle";
}
$NetServer::Debug && print STDERR "$n: $child_pid has status [",
$scoreboard->{$child_pid}, "]\n",
"$n: got ", scalar(@busyvec), " busy kids\n";
$busycnt = scalar(@busyvec);
my $all_kids = scalar keys %$scoreboard;
$NetServer::Debug &&
print STDERR "$n: $busycnt children busy of $all_kids total\n";
# busy_kids is number of kids currently busy; all_kids is number of kids
if ((($all_kids - $busycnt) < $spare_servers) and
($all_kids <= $max_servers)) {
my $kids_to_launch = ($spare_servers - ($all_kids - $busycnt)) +1;
$NetServer::Debug &&
print STDERR "spare servers: $spare_servers, ",
"all kids: $all_kids, ",
"busycnt: $busycnt\n",
"kids to launch = spares - (all - busy) +1 ",
" => $kids_to_launch\n";
# launch new children
for (my ($i) = 0; $i < $kids_to_launch; $i++) {
my $pid = fork();
if ($pid == 0) {
# new child
$NetServer::Debug &&
print STDERR "spawned child\n";
$self->_do_preforked_child();
&& print STDERR "$n: scoreboard: \n", Dumper $scoreboard;
}
print STDERR "exited getline loop\n";
}
sub _do_preforked_child {
my $self = shift;
# we are a preforked child process. We have an IO::Pipe called
# $self->writer() that we write strange things to. Each "strange thing"
# consists of a line containing our PID, a colon, and one of three strings:
# busy, idle, or exit. We run like a run_select server, except that we
# write a busy line whenever we accept a connection, an idle line whenever
# we finish handling a connection, and an exit line when our age exceeds
# $self->server_lifespan() and we suicide.
#
my $n = "_do_preforked_child($$)"; # for reporting status
my $server_lifespan = ( $self->server_lifespan() or 1000 );
my $my_age = ( $self->my_age() or 0 );
my $main_sock = $self->sock();
my $LOCK_SH = 1;
my $LOCK_EX = 2;
my $LOCK_NB = 4;
$new_sock->autoflush(1);
$rh->add($new_sock);
if (! $self->ok_to_serve($new_sock)) {
$rh->remove($sock);
close($sock);
}
} else {
if (! eof($sock)) {
$my_age++;
$NetServer::Debug
&& print STDERR "$n: print WRITE_PIPE ($$:busy)\n";
print WRITE_PIPE "$$:busy\n";
$NetServer::Debug
&& print STDERR "$n: serving connection\n";
$sock->autoflush(1);
my ($in_port, $in_addr) = sockaddr_in($sock->sockname());
$self->servername([$in_port, $in_addr]);
my ($code) = $self->callback();
$self->sock($sock);
*OLD_STDIN = *STDIN;
*OLD_STDOUT = *STDOUT;
*STDIN = $sock;
( run in 0.241 second using v1.01-cache-2.11-cpan-8d75d55dd25 )