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