Perl 5.8.0 signals and sockets

Matts on 2003-02-07T11:48:37

This week I've been dreading the approach of a co-worker because he's had problems with a socket server on perl 5.8.0 that works fine on 5.6.1 and below. The problem was that the CHLD signal handler was causing the program to exit, rather than just reaping the child.

The problem looks something like this:

$SIG{CHLD} = \&REAPER;
my $server = _mk_sock();

while (my $client = $server->accept) { my $pid = fork(); die "fork failed" unless defined $pid; if ($pid) { # parent next; } # child ... }
Now this works beautifully under perls before 5.8.0, but with 5.8.0's safe signals it breaks.

Unfortunately it appears that very few people have experienced this problem on google groups or elsewhere, so we had to figure it out for ourselves...

What's happening is that safe signals break out of the accept() call and execute the REAPER, but they don't go back into the accept() call like non-safe signals would - they make the accept() call return false. This is logical if you think about it, but took us many brane stroking hours to figure out.

Anyway, the solution is:
sub REAPER {
   ...
   $CHILDEXIT = 1;
}
...
while (1) {
  my $client = $server->accept;
  if ($CHILDEXIT) {
    $CHILDEXIT = 0;
    next;
  }
  elsif (!$client) {
    die "accept failed";
  }
  ...
}
There was something mentioned on usenet about EINTR but the above works fine.

(The main point of writing this journal entry is so that google indexes it to help others with similar problems).


Good Practice

Dom2 on 2003-02-07T12:28:48

It's probably always good practice to set a flag in a signal handler to let the main flow of code know that something has happened...

-Dom

Re:Good Practice

Matts on 2003-02-07T13:06:27

Yes, but normally you'd do that like this:
while (my $client = $server->accept()) {
   if ($SOMEFLAG) {
     ...
   }
   ...
}
Which doesn't work any more.

Re:Good Practice

Dom2 on 2003-02-07T13:18:45

That's very true, and a subtle point for people who are used to looking at things one particular way; I quite glossed over that.

Basically, you're saying that EINTR won't get reported properly and the system call won't get restarted either. Yuck.

-Dom

Re:Good Practice

Matts on 2003-02-07T13:54:42

Mostly it's for people reading the Perl Cookbook, which has the code the original way. I guess this'll all be fixed in Cookbook2, but until then I wanted to get something in google.