Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

signals after exec

by tdlewis77 (Sexton)
on Aug 26, 2017 at 02:17 UTC ( [id://1198044]=perlquestion: print w/replies, xml ) Need Help??

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

I use exec to transfer control from one instance of my program to a fresh one (so, for example, code changes get applied). However, the signals don't seem to work right in the new process. $SIG{INT} is set to run my interrupt handler, but it doesn't. I see "^C" on the screen, but my code does not run. Is there something I need to do in the new process to ensure my signals work correctly. Or, is there a better way to reload my program?

Replies are listed 'Best First'.
Re: signals after exec
by soonix (Canon) on Aug 26, 2017 at 06:51 UTC
    exec is a wrapper around the corresponding system call (actually, a whole family of functions). Their man pages, e.g. execve(2) and signal(7) say that "the dispositions of handled signals are reset to the default; the dispositions of ignored signals are left unchanged."
      "the dispositions of handled signals are reset to the default; the dispositions of ignored signals are left unchanged."

      ... and if you think about it, it makes sense. Ignoring a signal just sets a flag somewhere in the process structure managed by the kernel. The same is true for the other default actions terminate, terminate and dump core, stop and continue. Custom signal handlers, i.e. every signal handler somewhere in the code of the process, are overwritten by exec() (Remember: exec() replaces the executable in the current process with a different one), and so the signal handler pointers would point to some nonsense. If exec() would not reset the signal handlers, invoking the first custom signal handler would crash the executable (by executing unrelated code).

      Alexander

      --
      Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
Re: signals after exec
by stevieb (Canon) on Aug 26, 2017 at 02:46 UTC

    Please show what you've got now, as minimalistic as possible.

      ./sigfail.pl
      test> sig
      INT: sigInt
      test> loop
      ^CCaught
      Reloading sigfail.pl
      test> sig
      INT: sigInt
      test> loop
      ^C^C^C^C^C
      use B; use Term::ReadLine; $SIG{INT} = \&sigInt; $term = Term::ReadLine->new("sigfail"); while ($resp = $term->readline("test> ")) { if ($resp =~ m/^exit/) { last; } elsif ($resp =~ m/^loop/) { loop: goto loop; } elsif ($resp =~ m/^reload/) { reload() } elsif ($resp =~ m/sig/) { sig() } else { print "What?\n"; } } sub codeToName { my ($coderef) = @_; my $cv = B::svref_2object($coderef); return "" unless defined($cv) && defined($cv->GV); return $cv->GV->NAME; } sub reload { print "Reloading sigfail.pl\n"; exec("./sigfail.pl") } sub sigInt { print "Caught\n"; reload() } sub sig { map { print "$_: ",codeToName($SIG{$_}),"\n" if defined($SIG{$_}) && ref($SIG{$_}) eq "CODE" } sort { $a cmp $b } keys %SIG; }

        I decided to go with using fork to invoke the reloadable code. In my final implementation the child will use require to load a bunch of code that the parent doesn't need so that when the child process terminates, that code gets unloaded. I wanted a simple way for the child to send a message on its deathbed to the parent. I considered various IPC options, but in the end decided it would be simplest to just write a message to a file. The sample code below includes verbose messaging to easily follow what's happening:

        ./sigsuccess.pl
        test> sig
        INT: sigInt
        test> loop
        ^C
        child 38021: INT
        child 38021: Reloading sigsuccess.pl
        parent 38020: ignore INT
        parent 38020: CHLD (reload)
        parent 38020: Reloading...
        test> loop
        ^C
        child 38023: INT
        child 38023: Reloading sigsuccess.pl
        parent 38020: ignore INT
        parent 38020: CHLD (reload)
        parent 38020: Reloading...
        test> exit
        child 38024: Child exiting
        parent 38020: CHLD ()
        parent 38020: exiting after waitpid

        use B; use Term::ReadLine; $SIG{INT} = sub { print "parent $$: ignore INT\n" }; my $comm = "message.$$"; reload: if ($pid = fork()) { my $reload = 0; local $SIG{CHLD} = sub { my $request = ""; if (open(my $fh,$comm)) { $request = <$fh>; chomp $request; close $fh; unlink $comm; $reload = 1 if $request =~ m/^reload$/; } print "parent $$: CHLD ($request)\n"; }; waitpid($pid,0); if ($reload) { print "parent $$: Reloading...\n"; goto reload; } print "parent $$: exiting after waitpid\n"; } else { $SIG{INT} = \&sigInt; $term = Term::ReadLine->new("sigsuccess"); while ($resp = $term->readline("test> ")) { if ($resp =~ m/^exit/) { last; } elsif ($resp =~ m/^loop/) { loop: goto loop; } elsif ($resp =~ m/^reload/) { reload(); last; } elsif ($resp =~ m/sig/) { sig() } else { print "What?\n"; } } print "child $$: Child exiting\n"; exit; } sub codeToName { my ($coderef) = @_; my $cv = B::svref_2object($coderef); return "" unless defined($cv) && defined($cv->GV); return $cv->GV->NAME; } sub reload { print "child $$: Reloading sigsuccess.pl\n"; open my $fh, ">$comm"; print $fh "reload\n"; close $fh; exit(0); } sub sigInt { print "\nchild $$: INT\n"; reload() } sub sig { map { print "$_: ",codeToName($SIG{$_}),"\n" if defined($SIG{$_}) && ref($SIG{$_}) eq "CODE" } sort { $a cmp $b } keys %SIG; }

        For what it's worth, this fails the same way on all of the following platforms:

        • linux 3.10.0-229.14.1.el7.x86_64
        • darwin 15.6.0
        • cygwin 2.0.4(0.28753)

        Except that CygWin doesn't print the ^C.

Re: signals after exec
by zakame (Pilgrim) on Aug 26, 2017 at 16:48 UTC
    Is there something I need to do in the new process to ensure my signals work correctly. Or, is there a better way to reload my program?

    I think this sounds like you need a process manager to handle reloads of your program. Maybe something like Proc::Daemon could help?

Re: signals after exec
by Anonymous Monk on Aug 28, 2017 at 02:23 UTC

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others browsing the Monastery: (3)
As of 2024-04-19 00:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found