Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

signal handling in exec()'d code

by jliv (Initiate)
on Jan 25, 2010 at 11:22 UTC ( [id://819456]=perlquestion: print w/replies, xml ) Need Help??

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

I apologize in advance if this topic has been answered here or elsewhere already, but several Google searches haven't given me the info I'm looking for, so here we go...

I have a high-level deamon-like program that runs a suite of other programs and scripts and handles logging and such. The code has signal handling implemented (only for SIGINT) to close several processess, open files, etc., and all of that works great... for the most part. The issue is that this code has to exec itself after it has updated itself or its runtime configuration. Very early in the top-level code, the signal handler is (re)defined, so even in the cases where the code exec()s itself, it should re-establish the signal handler, but it isn't working as I think it should.

To summarize: If I run the code before it exec()s itself, the signal handling works fine...a Ctrl-C terminates everything cleanly. If I hit Ctrl-C after the code has exec()d itself, I get nothing. Here is how the signal handler is invoked:

$SIG{INT} = \&int_handler;

and here is the start of the function:

sub int_handler { print "\n\n\t\t\tWe caught SIGINT; we are shutting down now...\n"; $SIG{INT} = \&int_handler; ### OTHER STUFF ### exit(1); }

I even have the signal handler re-establish itself in the signal handling function in case there is any funny/weird behavior.

Any ideas on what I am missing or what I should be doing differently?

Replies are listed 'Best First'.
Re: signal handling in exec()'d code
by moritz (Cardinal) on Jan 25, 2010 at 11:43 UTC

    You may be doing something wrong in the code you're not showing us. This works on my machine:

    use strict; use warnings; $SIG{INT} = sub { print "caught SIGINT\n"; exit }; sleep 1; exec $^X, $0;

    When I run this, wait a few seconds and send press Ctrl+C I get the "caught SIGINT" message, so the re-installing of the signal handler worked.

    Perl 6 - links to (nearly) everything that is Perl 6.

      I can confirm that your example above works for me here on my local machine as well (Fedora 12). Here's some more info about my setup:

      The top-level program sets its own process group (0) and invokes setsid so that it can take down all subprocesses if and when an INT is received. Depending on the code being run, it makes use of backticks, system() and fork(), so there will always be some sort of process tree at any given moment. Other than setting the signal handler I mentioned above, there is no other signal modification anywhere in the code.

      Here is an example. The top-level program is called client.pl. Here is the output of pstree -p:

      bash(1274)---client.pl(16775)---client.pl(7703)---sh(7704)---binary_release_12(7705)

      In this case, the code has forked itself and invoked an external binary. The terminal in which process 16775 was launched doesn't respond to a Ctrl-C since that process exec()d itself about 20 mins ago.

      If you guys have any other ideas of what could be fouling me up, let me know.

      Thanks in advance for the help!

        The man page of setsid: "The calling process... has no controlling tty". Wouldn't that defeat a Ctrl-C signal getting through?

Re: signal handling in exec()'d code
by rubasov (Friar) on Jan 25, 2010 at 11:46 UTC
    Your code works for me on a recent Linux (even after exec), but it is possible that your platform has broken signal handling, so you may try to use POSIX-conformant signal handling, like in this node. I hope this helps.
Re: signal handling in exec()'d code
by afoken (Chancellor) on Jan 26, 2010 at 16:44 UTC

    Quite unrelated: Are you sure you want to do that much in a signal handler?

    sub int_handler { print "\n\n\t\t\tWe caught SIGINT; we are shutting down now...\n"; $SIG{INT} = \&int_handler; ### OTHER STUFF ### exit(1); }

    The "better safe than sorry" approach towards signal handlers is to do as LESS as possible inside the signal handler and let the main program handle the situation. Remember that signals may interrupt EVERY system call. Typically, you would only set a flag inside the signal handler (e.g. $caughtSigInt=1 or just $stop=1), and check that flag inside the main loop (e.g. while (!$stop) { .... }).

    Why do you setup int_handler as handler for SIGINT again inside int_handler? Is it cargo cult or intentionally? You would need that if you wanted to handle multiple SIGINTs (i.e. Ctrl-Cs) inside the same program, e.g because you want to (ab)use the SIGINT for something completely different (like updating a status line or terminating just a subroutine instead of the whole program). But if you want to exit the program, this makes no sense. Every SIGINT following the first one will effectively restart the routine.

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

      The "better safe than sorry" approach towards signal handlers is to do as LESS as possible inside the signal handler and let the main program handle the situation.

      That would be true if the signal handler was called from the actual signal handler Perl gives the system. This hasn't been the case since 5.8.0 (See "Safe Signals" in perl58delta.) Perl signal handlers don't even interrupt Perl opcodes, much less OS system calls.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://819456]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others about the Monastery: (6)
As of 2024-04-26 09:03 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found