Mailing List Archive

svn commit: r185098 - /spamassassin/trunk/lib/Mail/SpamAssassin/SpamdForkScaling.pm /spamassassin/trunk/lib/Mail/SpamAssassin/SubProcBackChannel.pm
Author: jm
Date: Mon Jun 6 16:41:55 2005
New Revision: 185098

URL: http://svn.apache.org/viewcvs?rev=185098&view=rev
Log:
fix spamd prefork race condition; if the lowest idle child died or exited while still in the I state, the master spamd would still attempt to assign it tasks and get stuck in an infinite loop trying to write the 'accept' order to the dead child. avoid this by recomputing the lowest idle child in the signal handler. also, add some error-handling code to remove out-of-control children from the backchannel's list of kids, on prefork state error.

Modified:
spamassassin/trunk/lib/Mail/SpamAssassin/SpamdForkScaling.pm
spamassassin/trunk/lib/Mail/SpamAssassin/SubProcBackChannel.pm

Modified: spamassassin/trunk/lib/Mail/SpamAssassin/SpamdForkScaling.pm
URL: http://svn.apache.org/viewcvs/spamassassin/trunk/lib/Mail/SpamAssassin/SpamdForkScaling.pm?rev=185098&r1=185097&r2=185098&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/SpamdForkScaling.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/SpamdForkScaling.pm Mon Jun 6 16:41:55 2005
@@ -82,7 +82,12 @@

sub child_exited {
my ($self, $pid) = @_;
+
delete $self->{kids}->{$pid};
+
+ # ensure we recompute, so that we don't try to tell that child to
+ # accept a request, only to find that it's died in the meantime.
+ $self->compute_lowest_child_pid();
}

sub child_error_kill {
@@ -94,7 +99,10 @@
# close the socket and remove the child from our list
$self->set_child_state ($pid, PFSTATE_KILLED);

- kill 'INT' => $pid;
+ kill 'INT' => $pid
+ or warn "prefork: kill of failed child $pid failed: $!\n";
+
+ $self->{backchannel}->delete_socket_for_child($pid);
if ($sock) {
$sock->close;
}
@@ -105,13 +113,17 @@
sub set_child_state {
my ($self, $pid, $state) = @_;

- if ($state == PFSTATE_STARTING || exists $self->{kids}->{$pid}) {
+ # I keep misreading this -- so: this says, if the child is starting, or is
+ # dying, or it has an entry in the {kids} hash, then allow the state to be
+ # set. otherwise the update can be ignored.
+ if ($state == PFSTATE_STARTING || $state == PFSTATE_KILLED || exists $self->{kids}->{$pid})
+ {
$self->{kids}->{$pid} = $state;
dbg("prefork: child $pid: entering state $state");
$self->compute_lowest_child_pid();

} else {
- dbg("prefork: child $pid: ignored new state $state, starting or already exited");
+ dbg("prefork: child $pid: ignored new state $state, already exited?");
}
}


Modified: spamassassin/trunk/lib/Mail/SpamAssassin/SubProcBackChannel.pm
URL: http://svn.apache.org/viewcvs/spamassassin/trunk/lib/Mail/SpamAssassin/SubProcBackChannel.pm?rev=185098&r1=185097&r2=185098&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/SubProcBackChannel.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/SubProcBackChannel.pm Mon Jun 6 16:41:55 2005
@@ -126,6 +126,11 @@
return $self->{kids}->{$pid};
}

+sub delete_socket_for_child {
+ my ($self, $pid) = @_;
+ delete $self->{kids}->{$pid};
+}
+
###########################################################################

sub setup_backchannel_child_post_fork {