Tim
Tim

Reputation: 2843

Fork / exec leaving zombie processes even with signal

I have a daemon program forks itself, then has an infinite loop checking system conditions, and when certain conditions are met, it runs a command. These commands can be long running which means they need to be asynchronous, so I'm using fork and execvp to run the commands. My code looks like this:

int main(int argc, char *argv[])
{
  signal(SIGCHLD, SIG_IGN);
  pid_t pid, sid;
  pid = fork();
  if (pid < 0)
  {
    exit(EXIT_FAILURE);
  }
  if (pid > 0)
  {
    exit(EXIT_SUCCESS);
  }
  umask(0);
  sid = setsid();
  if (sid < 0)
  {
    exit(EXIT_FAILURE);
  }
  if ((chdir("/")) < 0)
  {
    exit(EXIT_FAILURE);
  }
  while (1)
  {
    // Check conditions
    ...
    if (conditions_met)
    {
      pid_t pid2, sid2;
      pid2 = fork();
      if (pid2 == 0)
      {
        sid2 = setsid();
        // Define command_argv
        ...
        execvp(command_argv[0], command_argv);
      }
    }
  sleep(60);
  }
exit(EXIT_SUCCESS);
}

This all works, and my commands are running fine - however, it's leaving zombie processes. This is my first time trying to use fork and exec asynchronously, but I thought that signal(SIGCHLD, SIG_IGN) should ignore the child and let the init processes reap them. Why are these zombies still lingering?

Upvotes: 0

Views: 531

Answers (1)

Barmar
Barmar

Reputation: 781741

The SIG_IGN setting is not retained across fork(), so you need to call signal(SIGCHLD, SIG_IGN); in the child process with the loop that spawns all the commands, not the original parent process.

#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>
#include <sys/stat.h>
int main(int argc, char *argv[])
{
    pid_t pid, sid;
    pid = fork();
    if (pid < 0)
    {
        perror("fork");
        exit(EXIT_FAILURE);
    }
    if (pid > 0)
    {
        exit(EXIT_SUCCESS);
    }
    signal(SIGCHLD, SIG_IGN);
    umask(0);
    sid = setsid();
    if (sid < 0)
    {
        perror("setsid");
        exit(EXIT_FAILURE);
    }
    if ((chdir("/")) < 0)
    {
        perror("chdir");
        exit(EXIT_FAILURE);
    }
    while (1)
    {
        // Check conditions
        if (true)
        {
            pid_t pid2, sid2;
            pid2 = fork();
            if (pid2 == 0)
            {
                sid2 = setsid();
                // Define command_argv
                execlp("sleep", "sleep", "1", (char*)0);
            }
        }
        sleep(60);
    }
    exit(EXIT_SUCCESS);
}

Upvotes: 3

Related Questions