Great! It's always nice to have multiple solutions to a problem. I believe Stas Bekman also pointed to the POSIX sigaction solution when he first pointed me in the right direction in solving this problem, but setting $ENV{PERL_SIGNALS} = "unsafe"; got me going with perl 5.8 very quickly.

I might give the POSIX sigaction solution a try myself since I too wasn't incredibly comfortable with resorting to old signal handling for my entire httpd servers. My guess is that your POSIX sigaction solution would work with perl5.8.0 unlike the $ENV{PERL_SIGNALS} solution which is not supported until perl5.8.1.

Assuming your solution also solves this problem, it should also be included in any documentation regarding "safe signals" and apache/mod_perl.

Eric wrote:

Jim,

Thank you! This was a big help to me in that I ran into this problem from two directions recently, with a perl daemon and with Apache::SIG.. I did find some info about fixing this for real rather than using unsafe signals. They mostly seemed to point to using the POSIX sigaction methods rather Perl's.

I did end up getting my daemon to work without either dying after the first command or spawning endless children that would not die, those were my two choices before :) Only a part of this was related to the signal problem, but it was the hard part for a while.

The child signal was what was causing me big problems. I know this is far from a complete answer, but I hope it might send someone off on the right path if they don't want to set the ENV var. I was worried about doing it that way, because what happens a year from now when I upgrade my server and we somehow forget about that little detail? I know me and I will manage to mess it up if I can :)

Below are some examples from the POSIX module, it should work :). I found most of this 
somewhere when doing research on perl daemons but the child one I added on and I am 
currently using all of the below, I just did some cutting of other things.

use POSIX ();
use POSIX 'WNOHANG';
use FindBin ();
use File::Basename ();
use File::Spec::Functions;

my $script = File::Basename::basename($0);
my $SELF = catfile $FindBin::Bin, $script;


my $sigset = POSIX::SigSet->new();
my $action = POSIX::SigAction->new('sigHUP_handler',
$sigset,
&POSIX::SA_NODEFER);
my $action_alrm = POSIX::SigAction->new('sigALRM_handler',
$sigset,
&POSIX::SA_NODEFER); my $action_child = POSIX::SigAction->new('sigCHLD_handler',
$sigset,
&POSIX::SA_NODEFER); POSIX::sigaction(&POSIX::SIGHUP, $action);
POSIX::sigaction(&POSIX::SIGALRM, $action_alrm);
POSIX::sigaction(&POSIX::SIGCHLD, $action_child);
sub sigHUP_handler {
print "got SIGHUP\n";
exec($SELF, @ARGV) or die "Couldn't restart: $!\n";
}
sub sigALRM_handler {
print "got ALARM timeout\n";
}
sub sigCHLD_handler {
while (my $reaperpid = waitpid(-1,WNOHANG)>0) {
}
}



## do your while (1) and fork etc...




I wish I could paste in my whole daemon thing, but it is too far along with to many things specific to my bosses application..

Thanks,

Eric

At 02:55 PM 6/15/2004, Jim Albert wrote:

Last week I had a problem where I could not get my Apache2/mod_perl2/perl5.8.3 web 
server to catch a SIGPIPE signal in a timely manner.  I was asked to post a 
description of this problem and solution to this list so that it might be included in 
future mod_perl documentation.

Feel free to adjust this description as necessary when integrating it into the 
appropriate documentation.

The Problem:
Use a PerlFixupHandler to catch when the pipe from browser to httpd server has been 
broken such as when the user presses the browser stop button.

In conf.d/perl.conf
PerlFixupHandler Apache::SIG2

where Apache::SIG2.pm is defined in this example as:

----------
package Apache::SIG2;

# This package adapted by Jim Albert from the original mod_perl1
# Apache::SIG.pm by Doug MacEachern and Doug Bagley
# This PerlHandler can be used to prevent httpd children from killing
# off non-mod-perled CGIs when the user presses the Stop button.

use strict;
use Apache::RequestRec;
use ModPerl::Util;
use Apache::Const;

sub handler {
  my $r = shift;
  if (!$r->main) {
      $SIG{PIPE} = \&PIPE;
  }

 return OK;
}

sub PIPE {
 my($signal) = @_;
 print STDERR ("User pressed stop button.\n");
 # Kill off the httpd child before it can kill any running CGIs.
 # Or do whatever other cleanup is appropriate.
 CORE::exit();
}

1;
----------

With the introduction of perl 5.8.0, this handler no longer works as expected because 
of the introduction of perl safe signals.
See:
http://www.perldoc.com/perl5.8.4/pod/perlipc.html#Deferred-Signals-(Safe-Signals)

What happens with perl 5.8 and safe signals is that the apache httpd child does 
receive the SIGPIPE, but it is delayed and the perl CGI program has already been 
killed.  The httpd child does not act on the SIGPIPE until it receives the next httpd 
request.

The Solution:
An Apache server_startup.pl script can be used to turn off perl safe signals with the 
following line:
$ENV{PERL_SIGNALS} = "unsafe";
The server_startup.pl script can be included via the following line in perl.conf:
PerlRequire conf/server_startup.pl
The ability to revert back to "unsafe" signals is available as of perl 5.8.1.

--
Jim Albert



--
Report problems: http://perl.apache.org/bugs/
Mail list info: http://perl.apache.org/maillist/modperl.html
List etiquette: http://perl.apache.org/maillist/email-etiquette.html






--
Report problems: http://perl.apache.org/bugs/
Mail list info: http://perl.apache.org/maillist/modperl.html
List etiquette: http://perl.apache.org/maillist/email-etiquette.html



Reply via email to