Как вы обнаружили, вы не можете вызывать SIG_DFL и SIG_IGN как таковые . Однако вы можете более или менее имитировать их поведение.
Вкратце, имитация нормального расположения сигнала будет:
- довольно легко для пользователя
sa_handler
s
- достаточно просто для SIG_IGN, с оговоркой, что вам нужно будет waitpid () в случае CHLD
- прямолинейно, но неприятно для SIG_DFL, ре-рейз, чтобы ядро могло творить чудеса.
Делает ли это то, что вы хотите?
#include <signal.h>
#include <stdlib.h>
/* Manually dispose of a signal, mimicking the behavior of current
* signal dispositions as best we can. We won't cause EINTR, for
* instance.
*
* FIXME: save and restore errno around the SIG_DFL logic and
* SIG_IGN/CHLD logic.
*/
void dispatch_signal(const int signo) {
int stop = 0;
sigset_t oset;
struct sigaction curact;
sigaction(signo, NULL, &curact);
/* SIG_IGN => noop or soak up child term/stop signals (for CHLD) */
if (SIG_IGN == curact.sa_handler) {
if (SIGCHLD == signo) {
int status;
while (waitpid(-1, &status, WNOHANG|WUNTRACED) > 0) {;}
}
return;
}
/* user defined => invoke it */
if (SIG_DFL != curact.sa_handler) {
curact.sa_handler(signo);
return;
}
/* SIG_DFL => let kernel handle it (mostly).
*
* We handle noop signals ourselves -- "Ign" and "Cont", which we
* can never intercept while stopped.
*/
if (SIGURG == signo || SIGWINCH == signo || SIGCONT == signo) return;
/* Unblock CONT if this is a "Stop" signal, so that we may later be
* woken up.
*/
stop = (SIGTSTP == signo || SIGTTIN == signo || SIGTTOU == signo);
if (stop) {
sigset_t sig_cont;
sigemptyset(&sig_cont);
sigaddset(&sig_cont, SIGCONT);
sigprocmask(SIG_UNBLOCK, &sig_cont, &oset);
}
/* Re-raise, letting the kernel do the work:
* - Set exit codes and corefiles for "Term" and "Core"
* - Halt us and signal WUNTRACED'ing parents for "Stop"
* - Do the right thing if we forgot to handle any special
* signals or signals yet to be introduced
*/
kill(getpid(), signo);
/* Re-block CONT, if needed */
if (stop) sigprocmask(SIG_SETMASK, &oset, NULL);
}
<Ч />
UPDATE
(в ответ на отличные вопросы ОП)
1: идет ли этот слот после sigwaitinfo?
Да. Что-то вроде:
... block signals ...
signo = sigwaitinfo(&set, &info);
dispatch_signal(signo);
2: Почему бы не поднять эти сигналы, обрабатываемые SIG_IGN, они все равно будут игнорироваться
Несколько более эффективно выполнять noop в пользовательском пространстве, чем с помощью трех системных вызовов (повторное повышение, снятие маски, повторная маска). Более того, CHLD имеет особую семантику, когда SIG_IGNored.
3: Зачем особенно обращаться с SIGCHLD?
Первоначально (проверьте редактирование ответа) я не сделал этого - повторно поднял его в случае SIG_IGN,
потому что сигналы IGNored CHLD сообщают ядру, чтобы оно автоматически получало дочерние элементы .
Однако я изменил его, потому что "естественные" сигналы CHLD несут информацию о
завершенный процесс (по крайней мере, PID, статус и реальный UID).
Сгенерированные пользователем сигналы CHLD не имеют той же семантики, и, в моем тестировании,
IGNoring их не заставляет 2.6 автоматически собирать в очередь зомби, чей SIGCHLD
был "пропущен". Итак, я делаю это сам.
4: Почему сигналы, связанные с остановкой, разблокируются. CONT. Не вызовет ли обработчик по умолчанию для CONT прерывание процесса?
Если мы остановлены (не выполняемся) и CONT заблокированы, мы никогда не получим
сигнал разбудить нас!
5: Почему бы не вызвать рейз вместо линии убийства, которую вы дали?
Личные предпочтения; raise()
тоже сработает.