SIGCHLD не пойман

Я намерен использовать следующий код для разветвления и выполнения «sleep 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 никогда не вызывается.

Какую ошибку я совершил?

зомбитест.с:

#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;
}

person fadedbee    schedule 14.08.2013    source источник


Ответы (3)


Вы говорите дочернему процессу дождаться завершения дочернего процесса, а затем дочерний процесс вызывает execve, который не создает дочерний процесс, а вместо этого заменяет текущую программу той, которую вы выполняете.

Вы, вероятно, хотите, чтобы родитель перехватил дочерний (т.е. имел вызов signal до выполнения вызова fork).

person Tom Tanner    schedule 14.08.2013

Нашел: вызов signal не должен находиться в ветке pid == 0, так как этот процесс полностью заменяется при вызове execve.

Перемещение вызова сигнала выше if решает проблему.

person fadedbee    schedule 14.08.2013
comment
Похоже, я писал это, когда Том Таннер отвечал на вопрос. - person fadedbee; 14.08.2013

эта строка: signal(SIGCHLD, clean_up_child_process); следует писать в (pid>0) вместо (pid == 0)

См. из SIGCHLD:

Сигнал SIGCHLD отправляется родительскому дочернему процессу, когда он завершается, прерывается или возобновляется после прерывания. По умолчанию сигнал просто игнорируется.

Итак, родитель получил SIGCHLD, родительский процесс вызывает clean_up_child_process.

person Lidong Guo    schedule 14.08.2013