Subject: Re: Sane exit from a program on receipt of a signal
To: None <tech-userlevel@netbsd.org>
From: Christos Zoulas <christos@astron.com>
List: tech-userlevel
Date: 07/18/2007 20:27:35
In article <20070718020949.GD958@mewburn.net>,
Luke Mewburn <lukem@NetBSD.org> wrote:
>-=-=-=-=-=-
>-=-=-=-=-=-
>
>A lot of the code in our tree installs signal handlers
>for various reasons, and then uses exit(3) (or a variant)
>to exit the application.
>
>The problem with this is that it doesn't allow the parent
>process (usually a shell) to determine if a program
>exit was caused by a (probably user initiated) signal.
>
>This is documented in more detail at:
> http://www.cons.org/cracauer/sigint.html
>
>Rather than using exit(3) to terminate because of a user-initiated
>signal, the recommended solution is to reset to the default
>signal handler (SIG_DFL) and raise the signal.
>E.g.;
> signal(sig, SIG_DFL);
> raise(sig);
>
>The problem with that solution is if the signal mask for the
>process is currently blocking sig (see sigprocmask(3)), which
>is often the case within the currently executing signal handler,
>then the raise(3) will be blocked. Therefore, you have to
>unblock sig in the signal mask before the raise(3).
>
>(I noticed this during a sweep of the tree for user-code
>to solve the original problem.)
>
>I've written a helper function to encapsulate this extra
>complexity, and attached it to this message.
>It attempts to reset the signal handler for 'sig' to
>the default, remove 'sig' from the sigprocmask(3), and
>raise(3) 'sig'. If the function returns, the caller
>knows that the raise(3) didn't terminate the process.
>
>Is it worth adding this "raise_default()" function to
>the tree, say in util(3), to simplify re-use ?
>
>If so, is the name acceptable?
>
>
>cheers,
>Luke.
>
>-=-=-=-=-=-
>
>void
>raise_default(int sig)
>{
> struct sigaction act;
> sigset_t mask;
>
> /* Reset to default signal handler, clear mask, raise signal */
> memset(&act, 0, sizeof(act));
> act.sa_handler = SIG_DFL;
> if ((sigemptyset(&act.sa_mask) == 0) &&
> (sigemptyset(&mask) == 0) &&
> (sigaddset(&mask, sig) == 0) &&
> (sigaction(sig, &act, NULL) == 0) &&
> (sigprocmask(SIG_UNBLOCK, &mask, 0) == 0))
> raise(sig);
>}
- It should return int with an error.
- I think that you want to make sure that you exit with that signal and
not another. See: /usr/src/lib/libc/sys/stack_protector.c
- call it raise4sure() :-) or raise_default_unblock()?
christos