Mail-SpamAssassin
view release on metacpan or search on metacpan
lib/Mail/SpamAssassin/SpamdForkScaling.pm view on Meta::CPAN
my $ret = $self->wait_for_child_to_accept($kid, $sock);
if ($ret) {
return $ret;
} else {
# retry with another child
return $self->order_idle_child_to_accept();
}
}
else {
dbg("prefork: no spare children to accept, waiting for one to complete");
return;
}
}
sub wait_for_child_to_accept {
my ($self, $kid, $sock) = @_;
while (1) {
my $state = $self->read_one_message_from_child_socket($sock);
if ($state == PFSTATE_BUSY) {
return 1; # 1 == success
}
if ($state == PFSTATE_ERROR) {
return;
}
else {
if( Scalar::Util::blessed($self->{server_fh}[0]) eq 'IO::Socket::SSL' ) {
warn "prefork: SSL connection protocol error";
}
warn "prefork: ordered child $kid to accept, but they reported state '$state', killing rogue";
$self->child_error_kill($kid, $sock);
$self->adapt_num_children();
sleep 1;
return;
}
}
}
sub child_now_ready_to_accept {
my ($self, $kid) = @_;
if ($self->{waiting_for_idle_child}) {
my $sock = $self->{backchannel}->get_socket_for_child($kid);
$self->syswrite_with_retry($sock, PF_ACCEPT_ORDER, $kid)
or die "prefork: $kid claimed it was ready, but write failed on fd ".
$sock->fileno.": ".$!;
$self->{waiting_for_idle_child} = 0;
}
}
###########################################################################
# Child methods
sub set_my_pid {
my ($self, $pid) = @_;
$self->{pid} = $pid; # save calling $$ all the time
}
sub update_child_status_idle {
my ($self) = @_;
# "I b1 b2 b3 b4 \n "
$self->report_backchannel_socket("I".pack("l",$self->{pid})."\n");
}
sub update_child_status_busy {
my ($self) = @_;
# "B b1 b2 b3 b4 \n "
$self->report_backchannel_socket("B".pack("l",$self->{pid})."\n");
}
sub report_backchannel_socket {
my ($self, $str) = @_;
my $sock = $self->{backchannel}->get_parent_socket();
$self->syswrite_with_retry($sock, $str, 'parent')
or die "syswrite() to parent failed: $!";
}
sub wait_for_orders {
my ($self) = @_;
my $sock = $self->{backchannel}->get_parent_socket();
while (1) {
# "A . . . . \n "
my $line;
my $nbytes = $self->sysread_with_timeout($sock, \$line, 6, TOUT_READ_MAX);
if (!defined $nbytes || $nbytes == 0) {
if ($sock->eof()) {
dbg("prefork: parent closed, exiting");
exit;
}
die "prefork: empty order from parent";
}
if ($nbytes < 6) {
warn("prefork: parent gave short message: len=$nbytes bytes=".
join(" ", unpack "C*", $line));
}
chomp $line;
if (index ($line, "P") == 0) { # string starts with "P" = ping
dbg("prefork: periodic ping from spamd parent");
if (am_running_on_windows()) {
sleep 2; # need this on win32 so that a child can get a signal
}
next;
}
if (index ($line, "A") == 0) { # string starts with "A" = accept
return PFORDER_ACCEPT;
}
else {
die "prefork: unknown order from parent: '$line'";
}
}
}
###########################################################################
sub sysread_with_timeout {
my ($self, $sock, $lineref, $toread, $timeout) = @_;
$$lineref = ''; # clear the output buffer
my $readsofar = 0;
my $deadline; # we only set this if the first read fails
my $buf;
retry_read:
( run in 2.493 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )