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

The semantics of $SIG{__DIE__} are fairly annoying.

The way it steps over previous signals, the way you can't do 'local $SIG{__DIE__}' at the top of your module and get what you want, etc.

After a brief discussion of this on the Minneapolis PM list, I mulled over a comment by Ken Williams. I can't remember what the comment was but it prompted me to write some weird code.

I'm not posting the code here. Rather I'll describe it.

If you want it, write to me at autarch@urth.org. If people actually find it useful I'll CPAN-ize it.

I myself can't figure out if its a neat hack or a useless neat hack.

There are two modules that I've written. First of all, I know the names are wrong. If this does go on CPAN then better names are welcome.

The first, Sig::Lexical, makes it possible to (sort of) have signal handlers that only apply to code in a given package. The problem with this code is that it requires all code that wants to set $SIG{__DIE__} or $SIG{__WARN__} to go through this module.

If some code just does a $SIG{__DIE__} = sub { foo } then its all over.

Anyway, the code lets you do this:

  Sig::Lexical::my_sig( __DIE__ => \&some_sub );

Now, if code dies in the package that made the call, then &some_sub is called. Otherwise it dies normally.

To turn this off you can call:

  Sig::Lexical::unmy_sig( __DIE__ => 1 );

Ok, that function name sucks, I know.

Now for the really weird stuff. The other module is called Sig::Lexical::Paranoid.

If you use this module before any others, than _all_ assignments to $SIG{__DIE__} and $SIG{__WARN__} are treated as if they were done via Sig::Lexical::my_sig

This means that if some rude module just blindly assigns to $SIG{__DIE__}, this doesn't overwrite existing signal handlers, except in the rude module.

One thing I could add to this would be an option to make the signals more like 'local'. This means that when a die occurs, the module would travel back the stack in caller until either:

A) it finds a handler set via Sig::Lexical::my_sig for a calling package
or
B) it runs out of stack and does a normal die/warn.

This would work with the paranoid code too.

I could also make it so that you could say that certain signal handlers _always_ took precedence (at least in the paranoid version), no matter what else was set.

So is this useful or am I just a wacko?

-dave

  • Comment on Weirdness with $SIG{__DIE__} (and __WARN__)

Replies are listed 'Best First'.
Re: Weirdness with $SIG{__DIE__} (and __WARN__)
by Adam (Vicar) on Jan 12, 2001 at 00:30 UTC
    I'm not sure I understand what you mean by:
    The way it steps over previous signals, the way you can't do 'local $SIG{__DIE__}' at the top of your module and get what you want, etc.
    You can use local with $SIG{__DIE__}, you just need to assign the local %SIG value to 'DEFAULT' or some handler.

      Actually, I'm not sure I should have mentioned local. I think 5.6's our declaration is actually closer. But anyway, try this:

      in A.pl
      
      package A;
      
      use Z;
      
      $SIG{__DIE__} = sub { die 'in ' . __PACKAGE__ };
      
      eval { die };
      print "$@";
      eval { Z::Zdie };
      print "$@";
      

      and in a separate file (Z.pm):

      package Z;
      
      $SIG{__DIE__} = sub { die 'in ' . __PACKAGE__ };
      
      sub Zdie { die }
      

      You'll get this output:

      in A at A.pl line 5.
      in A at A.pl line 5.
      

      A's signal handler is the one that is used for both deaths.

      The reason I mentioned local is that some people try using local to 'fix' this (I know its not a bug) so that the each package could declare signal handlers.

      Now change the top of A.pl to this:

      package A;
      
      use Sig::Lexical::Paranoid;
      
      use Z;
      
      $SIG{__DIE__} = sub { die 'in ' . __PACKAGE__ };
      

      You'll get this:

      in A at A.pl line 7.
      in Z at Z.pm line 3.
      

      Note that despite the fact that A assigned directly to $SIG{__DIE__}, it did not overwrite Z's signal handler

      This may be useful.

      - dave

        Some consider $SIG{__DIE__} to be broken in design. Certainly, if you want nested 'die catchers' I think you would be better off using eval than $SIG{__DIE__}.

        The p5p e-mail list archives have several discussions regarding this.

                - tye (but my friends call me "Tye")