NetServer-Generic
view release on metacpan or search on metacpan
689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757my
$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
&&
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
&&
STDERR
"busyvec: ["
,
join
(
"]["
,
@busyvec
),
"]\n"
;
$loopcnt
++;
$NetServer::Debug
&&
STDERR
"$n: in pipe read loop $loopcnt\n"
;
$buffer
=~
tr
/ //;
chomp
$buffer
;
$NetServer::Debug
&&
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
&&
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
&&
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
&&
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
&&
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
&&
STDERR
"spawned child\n"
;
$self
->_do_preforked_child();
768769770771772773774775776777778779780781782783784785786787788789
&&
STDERR
"$n: scoreboard: \n"
, Dumper
$scoreboard
;
}
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;
826827828829830831832833834835836837838839840841842843844845846847
$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
&&
STDERR
"$n: print WRITE_PIPE ($$:busy)\n"
;
WRITE_PIPE
"$$:busy\n"
;
$NetServer::Debug
&&
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.243 second using v1.01-cache-2.11-cpan-8d75d55dd25 )