Этот код полон ошибок.Вы должны начать с включения предупреждений на вашем компиляторе.На GCC и clang это делается путем передачи флагов -pedantic
и уровня предупреждения.Я предлагаю использовать -Wall -Wextra -Werror
- это дает довольно строгие предупреждения, не мешая.
Первые две ошибки, как отмечено в комментарии, заключаются в том, что объявления прототипов являются неправильными, и что функция main
подпись неверна.
Вторая ошибка заключается в том, что вы не можете безопасно вызывать printf
внутри обработчика сигнала (вы встретите это относительно часто в коде, но это неправильно ).Фактически, набор действий, которые вы можете безопасно выполнить внутри обработчика сигнала, строго ограничен - внимательно прочитайте документацию .
В-третьих, попытка кода сброситьобработчики не работают (и в любом случае не нужны). Если вы хотите сбросить обработчик, вам нужно передать SIG_DFL
в качестве второго аргумента, а не пользовательский обратный вызов.Это также объясняется в документации.
И, наконец, нет никакой гарантии, что код в дочернем процессе будет выполнен перед кодом в родительском процессе - в частности, не гарантируется, что сигнал обработчики будут настроены.В моем тестировании дочерний код заканчивается тем, что никогда не выполняется, несмотря на операторы sleep
в родительском коде.Это может показаться странным, но это совершенно законно и требует предвидения.
Соединение этих частей оставляет нам следующее, что, как вы можете заметить, намного сложнее, чем неработающий код, который вы пробовали.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
static volatile sig_atomic_t child_signal;
static volatile sig_atomic_t setup_done = 0;
void child_signal_handler(int);
void parent_signal_handler(int);
int main() {
const int parent_pid = getpid();
int pid;
// Set up BEFORE calling `fork`
signal(SIGCHLD, parent_signal_handler);
if ((pid = fork()) < 0) {
perror("fork");
exit(1);
}
if (pid == 0) {
signal(SIGHUP, child_signal_handler);
signal(SIGINT, child_signal_handler);
signal(SIGQUIT, child_signal_handler);
kill(parent_pid, SIGCHLD);
for (;;) {
if (child_signal != 0) {
switch ((int) child_signal) {
case SIGHUP:
fprintf(stderr, "CHILD: I have received a SIGHUP\n");
break;
case SIGINT:
fprintf(stderr, "CHILD: I have received a SIGINT\n");
break;
case SIGQUIT:
fprintf(stderr, "My parent has killed me");
exit(1);
}
child_signal = 0;
}
}
} else {
while (! setup_done) { sleep(1); }
printf("\nPARENT: sending SIGUP\n");
kill(pid, SIGHUP);
sleep(1);
printf("\nPARENT: sending SIGINT\n");
kill(pid, SIGINT);
sleep(1);
printf("\nPARENT: sending SIGQUIT\n");
kill(pid, SIGQUIT);
}
}
void child_signal_handler(int signo) {
child_signal = signo;
}
void parent_signal_handler(int signo) {
if (signo == SIGCHLD) setup_done = 1;
}