Beefy Boxes and Bandwidth Generously Provided by pair Networks Frank
Perl-Sensitive Sunglasses

How to catch 'die' signal - CONVERSE case of #811295

by puterboy (Scribe)
on Dec 06, 2009 at 19:21 UTC ( #811358=perlquestion: print w/ replies, xml ) Need Help??
puterboy has asked for the wisdom of the Perl Monks concerning the following question:

Last night in id//811295, I asked about the best way to catch 'die' signals in embedded modules to convert them to 'warn' and prevent my script from exiting. The answer revolved around the best way to use 'eval' to "try" rather than execute the die signal.

I now have pretty much the converse question. I have a script that I daemonize and which creates a lock file. I would like the script to remove the lock file on signals INT, TERM, and __DIE__ just before actually dieing (in particular, this time I am *not* trying to prevent the process from exiting, I just want to prepend an action before exit). Of course, I only want to remove the lock if the __DIE__ signal is actually going to kill the process.

To do this, I added a handler of form:
$SIG{INT} = $SIG{TERM} = $SIG{__DIE__} = \&signal_handler; sub signal_handler { unlink($lockfile) if -w $lockfile; } Now this works just fine for INT and TERM but adding __DIE__ causes pr +oblem since some of the indirectly called modules use "eval" to test +for conditions that don't result in a real exit.<br><br> Specifically, one of my routines indirectly calls XML::Simple which us +es the following "eval" block to test if XML::SAX is available: <code> eval { require XML::SAX; }; # We didn't need it until now if($@) { # No XML::SAX - fall back to XML::P +arser if($preferred_parser) { # unless a SAX parser was expressly + requested croak "XMLin() could not load XML::SAX"; } return($self->build_tree_xml_parser($filename, $string)); }
The problem is that my new handler catches the error caused by non-existent XML/ (i.e., "Can't locate XML/ in @INC...) and removes the lock file even though the eval block protects it from actually exiting.

So, I am looking for a method of *only* trapping the 'die' signals that actually are about to lead to the process dieing while avoiding trapping (or at least acting upon) "clever" eval tricks that are used only to "try" or test what happens. Specifically, is there a way to write the signal handler so it only does something (i.e. only removes the lock file) if the process is truly about to die?

Comment on How to catch 'die' signal - CONVERSE case of #811295
Download Code
Re: How to catch 'die' signal - CONVERSE case of #811295
by Corion (Pope) on Dec 06, 2009 at 19:27 UTC

    Why not release your resources in an END block?

    perl -le "END{print 'uhoh, bye'} die 'Feh'"
by ikegami (Pope) on Dec 06, 2009 at 20:28 UTC

    Object::Destroyer can create destructors for resources that don't have one.

    my $lock_file; my $lock_file_destroyer = Object::Destroyer->new(sub{ unlink($lock_file) if defined($lock_file); }); ...
    But since this resources is global to your program, END will do.
    my $lock_file; END { unlink($lock_file) if defined($lock_file); } ...
      Thanks to the two previous posters for suggesting an END block. As a long-time perl dilettance, I was not aware of such usage.

      I then noticed though that END block doesn't capture things like SIGINT/SIGTERM.

      To capture those, I had to add the following line of code:
      $SIG{INT} = $SIG{TERM} = $SIG{HUP} = sub { exit; };
      Is this the correct way to do it?
        By default, the OS unloads the program in response to those signals. That looks like a good solution to me.
by keszler (Priest) on Dec 06, 2009 at 21:24 UTC

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://811358]
Approved by Corion
Front-paged by Corion
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others meditating upon the Monastery: (6)
As of 2014-03-15 17:44 GMT
Find Nodes?
    Voting Booth?

    Have you used a cryptocurrency?

    Results (320 votes), past polls