views:

454

answers:

4

If I have a script that is a wrapper for another program (e.g., a daemonizer wrapper or a wrapper for mathematica), it is sometimes useful to trap signals in the wrapper program and pass them along to the subprogram. For example, here's some Perl code to deal with the INT (interrupt) signal so that if you do ctrl-C after launching the wrapper the subprogram also gets interrupted:

my $subprogram = "foo args";
my $pid = open(F, "$subprogram |") or die "Can't open pipe from $subprogram: $!";
$SIG{INT} = sub { kill('INT', $pid); 
                  close(F); 
                  die "Passed along INT signal and now aborting.\n"; };
print while(<F>);
close(F);

Of all the possible signals that a program might handle, which ones should a wrapper script pass along?
Is there anything else that a good wrapper should do?

EDIT: Originally this question was asking how to pass along all possible signals. Thanks to the initial answers I learned that was not the right question.

EDIT: I figured out what threw me for a loop here. Mathematica apparently detaches itself from its parent process. So I have to pass along various termination signals explicitly:

$SIG{INT} =  sub { kill('INT', $pid); };  # pass along SIGINT (eg, ctrl-C)
$SIG{TERM} = sub { kill('TERM', $pid); }; # pass along SIGTERM (kill's default)
$SIG{QUIT} = sub { kill('QUIT', $pid); }; # pass along SIGQUIT
$SIG{ABRT} = sub { kill('ABRT', $pid); }; # pass along SIGABRT
$SIG{HUP} =  sub { kill('HUP', $pid); };  # pass along SIGHUP

Normally this would not be necessary as child processes automatically get these signals passed along (thanks for the answers that set me straight on this!). So now I'm wondering why (and how) mathematica detaches itself...

+2  A: 

There are many signals that would be dangerous to just "pass through" in this way. "man 7 signal" and look at things like SIGPIPE, SIGILL, SIGCHILD, etc. It's very likely that you just don't want to touch those guys.

So, the real question becomes: What is the behavior you're looking for? I bet all you really want is SIGINT & SIGCONT to be passed through to the child. Does the subprogram do anything fancy with other signals, like HUP, USR1, or USR2?

I presume you're really just interested in SIGINT & SIGCONT, and the rest (i.e. SIGSEGV, SIGKILL, etc.) will take care of themselves, as the parent process termination will clean up the child as well.

Oh, and by the way, your example of:

print while(<F>);

Is fine, and if the parent perl process is suspended, it won't continue reading from F, once that pipe fills up, your subprogram will block writing into stdout, which is probably pretty much the behavior you want as well.

For some more interesting thoughts, take a look at "man bash" and the "trap" builtin to see what the shell developers have done to help this problem.

slacy
Cool, thanks! I don't want to assume anything about the subprogram -- it may well do fancy things with signals. So should the list include INT, CONT, HUP, USR1, USR2? Anything else?
dreeves
So, surprisingly, in the case of mathematica, parent process termination by TERM, QUIT, ABRT, or HUP does *not* cause mathematica to terminate unless I explicitly pass them along. Now I'm curious how mathematica manages that!
dreeves
+2  A: 

I really don't see why you would want to do that. For that matter, I don't see why you would want to send signals to the wrapper script.

ETA: Stop and restart signals are sent to the whole process group. If that's what you're after: just make sure your child process is part of that process group (it is by default AFAIK).

ETA2: If mathematica really detaches itself (which can be done using setsid() and setpgid()), that means it explicitly does not want to receive such signals, so you shouldn't send them: it probably won't handle them anyway.

Leon Timmermans
For example, if I run "wrapper.pl foo arg1 arg2" on the cmd line which runs "foo arg1 arg2" as a subprogram and then do ctrl-C I want foo to get interrupted exactly as if I had run "foo arg1 arg2" directly. (I'll try to edit the question to be clearer, or let me know if I'm thinking of this wrong.)
dreeves
Unless you take steps to detach the process you're wrapping, signals sent at the terminal will be sent to the child process anyway.
Jonathan Leffler
That's what I said ;-). The signal is sent to the process group, not any specific process.
Leon Timmermans
See my second addendum to this question. I guess mathematica must be taking steps to detach itself then? I'm curious now what those steps are. (Really appreciate all the help with this despite the question turning out to be totally wrong-headed!)
dreeves
I understand now, thanks Leon! I disagree about not passing along signals though (and it does handle them properly when I pass them). This has to do with why I need to wrap mathematica in the first place. I want the wrapped mathematica to behave like the real mathematica as much as possible.
dreeves
+1  A: 

You can get a list of all signals with keys %SIG. So, to pass them all through, you set handlers to send the signal the child process ID:

for my $signal (keys %SIG) {
    $SIG{$signal} = sub { kill($signal, $child_pid); };
}

You'll probably want to localize %SIG.

Not that I'm saying it's a good idea, but that's how to do it.

Schwern
Thanks! Any advice on which I should pass along and which I shouldn't? See my comment on Leon's answer. Perhaps there's not actually anything besides ctrl-C that I want to or need to pass along.
dreeves
You'd have to figure out what the sub-program really needs and what the user expects to happen when they signal the parent. SIGINT is the real one users will care about so that they can kill the sub-process without killing the parent, like the CPAN shell does.
Schwern
+2  A: 

None.

The signals that you might generate at the keyboard are sent to the child process anyway, unless the child takes steps to avoid that (in which case, who are you to interfere).

The other signals that might kill the parent process would normally cause the child to disappear when it next writes to the pipe that was closed when the parent died.

So, unless you have reason to think that the child process mismanages signals, I would not worry about relaying any signals to the child. And if the child mismanages signals, maybe you should fix the child rather than hack the parent.

Jonathan Leffler
Thanks Jonathan. I guess in this case I do want to interfere. See the 2nd addendum to question. Since the child (mathematica) is, annoyingly, closed-source, I guess I have to worry about relaying signals. What I didn't realize initially was that this was the child's fault. Thanks again for the help!
dreeves