SIGCHLD не пойман
Я намереваюсь следующий код для форка и исполнения "сна 3" как ребенка, в то время как родительский процесс спит в течение 10 секунд. Я ожидаю, что родительский процесс получит SIGCHLD через 3 с, когда "сон 3" закончится.
Этого не происходит, вместо этого я получаю:
main
parent process
parent sleeping for 10s
child process
child start, command: /bin/sleep, args: 0x7fffc68c8000, env: 0x7fffc68c8020
ps -ef
показывает
chris 10578 10577 0 10:35 pts/25 00:00:00 /bin/sleep 3
сопровождаемый:
chris 10578 10577 0 10:35 pts/25 00:00:00 [sleep] <defunct>
в течение следующих семи секунд (после чего родительский процесс завершается).
Проблема в том, что clean_up_child_process
никогда не называется.
Какую ошибку я совершил?
zombietest.c:
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <strings.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
pid_t child_pid;
sig_atomic_t child_exit_status;
void clean_up_child_process (int signal_number) {
printf("signal received\n");
/* Clean up the child process. */
int status;
wait (&status);
/* Store its exit status in a global variable. */
child_exit_status = status;
printf("child_exit_status %i\n", status);
}
int main(int argc, char **argv) {
printf("main\n");
int pid = fork();
if (pid == 0) {
printf("child process\n");
signal(SIGCHLD, clean_up_child_process);
char *args[] = { "/bin/sleep", "3", NULL };
char *env[] = { NULL };
printf("child start, command: %s, args: %p, env: %p\n", args[0], args, env);
int ret = execve(args[0], args, env);
// if we get here, then the execve has failed
printf("exec of the child process failed %i\n", ret);
} else if (pid > 0) {
printf("parent process\n");
child_pid = pid;
} else {
perror("fork failed\n");
}
printf("parent sleeping for 10s\n");
sleep(10);
return 0;
}
3 ответа
Вы говорите ребенку дождаться завершения дочернего процесса, а затем дочерний процесс вызывает execve, который не создает дочерний процесс, а вместо этого заменяет текущую программу той, которую вы выполняете.
Вы, вероятно, хотите, чтобы родитель перехватил ребенка (т.е. signal
позвоните, прежде чем выполнить fork
вызов).
Нашел его: звонок на сигнал не должен быть в pid == 0
ветвь, так как этот процесс полностью заменяется при вызове execve.
Перемещение сигнала вызова выше if
решает проблему.
Эта строка: signal(SIGCHLD, clean_up_child_process);
следует написать в (pid>0)
вместо (pid == 0)
Смотрите из SIGCHLD:
Сигнал SIGCHLD отправляется родительскому элементу дочернего процесса, когда он завершается, прерывается или возобновляет работу после прерывания. По умолчанию сигнал просто игнорируется.
Итак, родитель получил SIGCHLD, родительский процесс вызвал clean_up_child_process .