rrwo has asked for the wisdom of the Perl Monks concerning the following question:

I'm working on a module which traps warning and fatal signals in the BEGIN block:

  $SIG{__WARN__} = \&foo;
  $SIG{__DIE__}  = \&bar;

All this works fine (well, I gotta work on trapping dies in `eval' but that's a separate issue). What doesn't work is when I use another module that also traps these, such as CGI::Carp.

If I `use' my module before CGI::Carp, my traps are lost. Likewise if I use mine after CGI::Carp, I kill its traps.

I've tried something like the following:

  if ($SIG{__WARN__}) {
    my $previous = $SIG{__WARN__};
    $SIG{__WARN__} = sub {
        # do my stuff
        goto &$previous;
    };
  }
  else
  # blah blah

but this doesn't work! It repeatedly calls my handler over and over, as if $previous contained a reference to my code (I've debugged it and found $previous only contains something when a module such as CGI::Carp has trapped the signal).

So what am I doing wrong here?

  • Comment on How can two modules latch onto $SIN{__WARN__} or $SIG{__DIE__}?

Replies are listed 'Best First'.
Re (tilly) 1: How can two modules latch onto $SIN{__WARN__} or $SIG{__DIE__}?
by tilly (Archbishop) on Jan 10, 2001 at 07:59 UTC
    Are they trying to rethrow the die? And then you catch it again. Try this:
    if ($SIG{__WARN__}) { my $previous = $SIG{__WARN__}; my $caught = 0; $SIG{__WARN__} = sub { return if $caught; $caught = 1; # do my stuff my $ret = $previous->(); $caught = 0; return $ret; }; } else
    If they catch the fact that you are in the call stack you might want to leave the goto in, but then you are limiting them to one warning in the entire script.

    UPDATE
    Oops. I forgot to call the ref. :-(

    Worse than that, the solution is too complex and misses the cause of the problem. See the response I have down below. Just drop the goto and the original code works.

      This is confusing: what's going on? The signal handler must return a subroutine/coderef to go to after it's done?

      Where is this documented?

        Oops, it is late and I am tired.

        I just wanted to call and then return the return from that handler. I didn't want to return the reference itself without calling it.

        Anyways your problem is that you are editing the fact that the signal has been handled out of the call stack, so when it is rethrown you are called again.

        Actually just drop the goto and your code should work.

Re: How can two modules latch onto $SIN{__WARN__} or $SIG{__DIE__}?
by Adam (Vicar) on Jan 10, 2001 at 09:43 UTC
    Playing with the __WARN__ and __DIE__ signals in Perl is lots of fun, but there are plenty of pitfalls. I address several of them here.