一部の信号の信号処理をリセットすること(SPAWN_SETSIGDEFの動作)と、新しいプロセスのマスクを設定すること(SPAWN_SETSIGMASKの動作)の2つを実行する必要があります。
(投稿された例では実際には後者を実行していないことに注意してください。ただし、意図したことはもっともらしいです。)
SPAWN_SETSIGDEF
SPAWN_SETSIGDEFは、sigdefault
セット内のすべてのシグナルの処理をリセットします。これを実現するには、デフォルトの処理に設定する個々のシグナルに対してsigaction()を呼び出します。
int spawnlike_setsigdef(const sigset_t *s) { /* FIXME: assert(s != NULL) */
int signum;
struct sigaction sa = { 0 };
sa.sa_handler = SIG_DFL;
for (signum = 1; signum < NSIG; signum++) { /* You might have to use _NSIG or */
if (! sigismember(s, signum)) continue; /* SIGRTMAX or similar. */
switch (signum) {
case SIGKILL:
case SIGSTOP: /* Can't modify disposition of these */
break;
default:
if (sigaction(signum, &sa, NULL) == -1)
return -1; /* Yikes! What happened? */
}
}
return 0;
}
SPAWN_SETSIGMASK
SPAWN_SETSIGMASKは、新しいプロセスのシグナルマスクを設定するだけです。これは、pthread_sigmask()またはsigprocmask()のいずれかで実行できます。
ちなみに、 spawnp()スニペットでSPAWN_SETSIGMASKを指定していないため、実際には新しいプロセスのマスクを明示的に設定していません。(代わりに、通常どおりマスクを継承します。)
それを一緒に入れて
次のようなものが必要になります。
sigset_t all_signals;
sigset_t saved_mask;
sigfillset(&all_signals);
/* Now protect our child as best we can between resetting dispo to SIG_DFL
* and setting default sig mask. We'll also reuse 'all_signals' later in
* the newly fork()d child.
*/
pthread_sigmask(SIG_SETMASK, &all_signals, &saved_mask);
if (fork() == 0) {
/* am child */
spawnlike_setsigdef(all_signals);
sigprocmask(SIG_SETMASK, &some_default_sig_mask, NULL);
execv(...);
fatal_error("execv didn't work :(\n");
}
/* else I am parent, restore my original mask */
pthread_sigmask(SIG_SETMASK, &all_signals, &saved_mask);