Using sigtrap within a perl module, how do I get the trap received back in the object context?
Have the following in my m开发者_StackOverflowodule's BEGIN section:
use sigtrap qw(handler shutdown normal-signals);
use sigtrap qw(die untrapped normal-signals stack-trace any error-signals);
But when sigtrap catches INT,etc.. what I get in my shutdown sub only contains the trap and not the object handle. No $self.
sub shutdown {
my $sig = shift || 'Nothing';
print "Got signal: $sig\n";
exit;
}
simply returns
Got signal: INT
My DESTROY get's called right on time after this and has access to the object handle, but because I didn't have access to the handle in my shutdown, I couldn't store it and have no idea what the signal was.
I need to know what trap I got so my DESTROY method can log what caused the shutdown.
Perhaps sigtrap isn't the best choice here. Opinions welcome.
I checked sigtrap
, it's not specifically an OO module, if you want to use it as one, you may need to use a closure instead of an object method.
So you might define your class like so:
package SigHandler;
sub new {
my $class = shift;
return bless { @_ }, $class;
}
sub on_signal_int {
my $self = shift;
...
}
sub get_handler {
my $self = shift;
my @other_args = shift;
...
return sub {
my $sig = shift;
if ( $sig == INT ) {
return $self->on_signal_int();
}
};
}
And then call it like so:
use handler => SigHandler->new->get_handler, 'normal-signals';
Perl's signal handlers, including those set with sigtrap
are program level, and not object level. So when perl calls the handler, it does not have any object to pass you.
If you want to clean up a bunch of objects when you receive a signal, you will need to code your module to keep track of the objects it has created. Then when you receive a signal, you can go through those objects and perform any destroy methods.
Something like this should get you started:
{package Test;
use Scalar::Util 'weaken';
use sigtrap handler => \&cleanup, 'normal-signals';
my %objects;
sub new {
my ($class, $msg) = @_;
my $self = [$msg];
bless $self, $class;
weaken($objects{$self} = $self); # prevent memory leak
$self
}
sub cleanup {
my ($sig) = @_;
say "cleanup on $sig";
defined and $_->DESTROY for values %objects;
exit;
}
sub DESTROY {
my ($self) = @_;
if (@$self) {
say "DESTROY $self @$self";
@$self = ();
delete $objects{$self}
}
}
}
{my $obj1 = Test->new('out of scope')}
my $obj2 = Test->new('in scope');
1 while 1;
And when run:
$ perl so.pl
DESTROY Test=ARRAY(0x899150) out of scope
^Ccleanup on INT
DESTROY Test=ARRAY(0x824810) in scope
Thank you for your insights, but I ended up cheating by using global to track it. All the exports and common stuff removed for brevity
Package Blah;
our $SIG_CAUGHT = '';
BEGIN {
use sigtrap qw(handler shutdown normal-signals);
use sigtrap qw(die untrapped normal-signals stack-trace any error-signals);
}
sub shutdown {
$SIG_CAUGHT = shift;
exit;
}
sub DESTROY {
my $self = shift;
my $message = 'Daemon shutting down';
$message .= '. Caught signal: SIG' . $SIG_CAUGHT if ( $SIG_CAUGHT ne '' );
$message .= ' with error: ' . $! if $!;
$self->logger({severity => 5, message => $message});
$self->{_dbh} = undef;
}
1;
Tested.. correctly handles INT,KILL,DIE, propagating errors when fatal.
One nice side effect is triggering INT is now one keystroke.
Had the issue in the past where I repeatedly had to Control-C my programs to get them to go down.
精彩评论