hisycg@gmail.com has asked for the wisdom of the Perl Monks concerning the following question:

Hi, Trying to use sigtrap with Moose Mypackage.pm
package Mypackage; use Moose; use Exporter qw(import); use sigtrap 'handler' => \&signal_handler_kill, 'INT', 'ABRT', 'QUIT', + 'TERM'; has status => ( isa => 'Str', is => 'rw' ); sub signal_handler_kill{ my $self_term=shift; my $self=shift; $self->status("killed"); $self->end; } sub end{ #do some clean up $self=shift; print $self->status."\n"; } 1;
then I have a test script to test it. test_Mypackage.pl
use Mypackage; my $obj = Mypackage->new({status=>"start"}); sleep 20;
I run the test script and kill it, but it returns

Can't call method "status" on an undefined value at Mypackage.pm line 10.

It seems the object is already destroyed beofre the signal caught, any idea? Thanks //Aaron

Replies are listed 'Best First'.
Re: Any one know how to use sigtrap with moose?
by Corion (Patriarch) on Jul 24, 2012 at 09:59 UTC

    How does Perl (or Moose) know what to pass in for $self to your sigtrap_handler_kill?

    Update: Also think about on which object(s) to set the new status.

    If you have a callback that you want to use to call a method on a specific object, use a closure:

    sub { $obj->status("foo"); };
      Should this code put in sigtrap_handler_kill or in the test script?
Re: Any one know how to use sigtrap with moose?
by tobyink (Canon) on Jul 24, 2012 at 10:20 UTC

    This bit:

    my $self_term=shift; my $self=shift;

    ... seems to be assuming that your handler will be called with two arguments, the second of which is an object.

    But if you read sigtrap which refers you to perlvar you'll see that for real signals (not Perl's internal __DIE__ and __WARN__ signals) the handler gets passed just one parameter: the name of the signal (e.g. "INT", "QUIT", etc).

    The fact that you're using Moose makes no difference here.

    What are you actually hoping to achieve? What's the overall reason you're installing a signal handler? If you explain that, then perhaps somebody can give you some advice about how to go about doing it.

    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
      Hi, Thanks for the reply, I would like to put all the signal handling code in Mypackage.pm. Not sure if it's possible. If I run
      $ perl test_mypackage.pl
      then run
      $ ps -ef |grep perl |grep -v grep |awk '{print $2}' |xargs kill
      Then end{} should print it's status.

        If you want some code to run at the end of your program, consider using an END block or an object destructor instead of using signal handlers. See perlsyn and/or perlobj.

        You could try something along the lines of:

        use MyPackage; my $newest_instance; after BUILD => sub { $newest_instance = shift; };

        And then in your signal handler, call:

        if ($newest_instance) { $newest_instance->status("killed"); $newest_instance->end; }

        Note that if there is more than one object of class MyPackage knocking around, this will only set the status on the newest (i.e. most recently constructed) object.

        Depending on exactly what you're doing, and how many instances of MyPackage you expect to exist in the lifetime of a process, you may need something else.

        perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'