dreeves
dreeves

Reputation: 26952

Which signals should a wrapper script pass along to a subprogram?

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](http://en.wikipedia.org/wiki/Signal_(computing) 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...

Upvotes: 1

Views: 1512

Answers (4)

Schwern
Schwern

Reputation: 165396

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.

Upvotes: 1

Leon Timmermans
Leon Timmermans

Reputation: 30235

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.

Upvotes: 2

Jonathan Leffler
Jonathan Leffler

Reputation: 754710

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.

Upvotes: 2

slacy
slacy

Reputation: 11773

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.

Upvotes: 2

Related Questions