Question

I intend the following code to fork and exec "sleep 3" as a child while the parent process sleeps for 10s. I expect the parent process to receive SIGCHLD after 3s, when the "sleep 3" sompletes.

This does not happen, instead I get:

main
parent process
parent sleeping for 10s
child process
child start, command: /bin/sleep, args: 0x7fffc68c8000, env: 0x7fffc68c8020

ps -ef shows a

chris    10578 10577  0 10:35 pts/25   00:00:00 /bin/sleep 3

followed by a:

chris    10578 10577  0 10:35 pts/25   00:00:00 [sleep] <defunct>

for the next seven seconds (at which point the parent process exits).

The issue is that clean_up_child_process is never called.

What mistake have I made?

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;
}
Was it helpful?

Solution

You're telling the child to wait for a child process to finish, and then the child process is calling execve which doesn't create a child process, but instead replaces the current program with the one you're execing

You probably want the parent to intercept the child (i.e. have the signal call before you execute the fork call).

OTHER TIPS

Found it: the call to signal should not be in the pid == 0 branch, as that process is entirely replaced when execve is called.

Moving the signal call to above the if solves the problem.

this line: signal(SIGCHLD, clean_up_child_process); should write in in (pid>0) instead of (pid == 0)

See from SIGCHLD :

The SIGCHLD signal is sent to the parent of a child process when it exits, is interrupted, or resumes after being interrupted. By default the signal is simply ignored.

So , the parent received the SIGCHLD , the parent process call the clean_up_child_process .

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top