Question

My question is I can't undertand why those code still generate zombie process. how can I fixed it? thanks.

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>


int count = 0;

/**
 * signal  callback
 * @param signo
 */
void sigcallback(int signo) {
    short stime = 5;
    int status;
    wait(&status);
    while (1) {

        printf("wake up,%d\n", getpid());
        sleep((stime + 1) - (short) (time(NULL) % stime));

    }
}

int call_cmd(void) {
    count++;

    int i;
    pid_t pid;
    signal(SIGCHLD, sigcallback);
    for (i = 0; i < 3; i++) {
        if ((pid = fork()) < 0) {
            printf("error with fork\n");
            exit(1);
        } else if (pid > 0) {
            waitpid(pid, NULL, WNOHANG);
        } else {
            printf("\t\t\tsid is %d,count is %d,pid is %d\n", getsid(getpid()), count, getpid());
        }
    }
    return 1;
}

void notice_root(int signo) {
    printf("execut root signal\n");
    waitpid(0, NULL, 0);
}

int main(void) {
    pid_t pid;

    int i;
    signal(SIGCHLD, notice_root);
    for (i = 0; i < 2; i++) {
        if ((pid = fork()) < 0) {
            printf("error with fork\n");
            exit(1);
        } else if (pid > 0) {
            exit(0);
        } else {
            setsid();
            call_cmd();
        }
    }
    return 0;
}
Was it helpful?

Solution

You have an infinite sleep loop in your signal handler sigcallback. Once a signal has been handled by that function, the process will never handle another SIGCHLD signal again, since the signal handler never returns. This is likely the cause of your zombies.

You do not get one signal delivered for every exited child. If two children exit "simultaneously", you will only get a single SIGCHLD delivered. So, when you wait in your signal handler (either of them), you should wait in a loop to reap all the children that have exited. Something along the lines of:

for (;;) {
    pid_t p = waitpid(-1, 0, WNOHANG);
    if (p <= 0) break;
    /* ... */
}

When your process exits, the children of that process will be inherited by the init process, so they will be reaped properly. However, your infinite loop prevented 3 things:

  • It would not reap simultaneously exited children.
  • It would not reap any more children after reaping the first.
  • It would not allow the process to exit, so the children could not be reaped by the init process.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top