DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Snippets has posted 5883 posts at DZone. View Full User Profile

Experiment To See Whether Child Processes Die When The Parent Does

10.08.2008
| 5817 views |
  • submit to reddit
        
/*
 * Program to demonstrate how grandchild processes are cleaned up (killed)
 * or not when a process with children is killed on UNIX systems.
 */

#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

void handle_signal(int signum)
{
  fprintf(stderr, "Process pid=%d received signal %d, exiting.\n", getpid(), signum);
  exit(1);
}

void setup_signals()
{
  signal(SIGTERM, handle_signal);
  signal(SIGHUP, handle_signal);

  /* We don't intend to explicitly wait on children, so we ignore SIGCHLD. */
  signal(SIGCHLD, SIG_IGN);
}

void spin()
{
  while(1)
    ;
}

void spawn_and_kill_children(int (*independence_func)(), char *independence_func_name)
{
  /* Create the child. */
  pid_t child_pid;

  int fds[2];
  int success = pipe(fds);
  if(success < 0)
  {
    perror("pipe()");
    exit(1);
  }

  child_pid = fork();
  if(child_pid == 0)
  {
    /* Child. */
    if(close(fds[0]) != 0)
      perror("child close()");

    setup_signals();
    fprintf(stderr, "+-> Child started with pid=%d.\n", getpid());

    /* Declare independence. */
    if(independence_func)
    {
      fprintf(stderr, "Child declaring independence with function %s.\n",
              independence_func_name);
      (*independence_func)();
    }

    /* Spawn grandchild. */
    pid_t grandchild_pid = fork();
    if(grandchild_pid == 0)
    {
      /* Grandchild. */
      setup_signals();
      fprintf(stderr, "  +-> Grandchild started with pid=%d.\n", getpid());
      spin();
    }
    else if(grandchild_pid > 0)
    {
      /* Still child.  Send the pid of the grandchild to the parent. */
      char pid_str[1024];
      int len = sprintf(pid_str, "%d", grandchild_pid);
      success = write(fds[1], pid_str, len);
      if(success < 0)
        perror("child write()");

      if(close(fds[1]) != 0)
        perror("child close()");

      spin();
    }
    else if(grandchild_pid < 0)
    {
      perror("fork()");
      exit(1);
    }
  }
  else if(child_pid < 0)
  {
    perror("fork()");
    exit(1);
  }

  sleep(1);

  if(close(fds[1]) != 0)
    perror("parent close()");

  /* Get the grandchild pid from the child. */
  char buf[1024];
  int bytes_read = read(fds[0], buf, sizeof(buf));
  buf[bytes_read] = '\0';
  pid_t grandchild_pid = atoi(buf);
  fprintf(stderr, "Parent got grandchild pid=%d.\n", grandchild_pid);
  if(close(fds[0]) != 0)
    perror("parent close()");

  /* Parent.  Kill child, see if grandchild dies also. */
  if(independence_func)
  {
    fprintf(stderr, "Killing child process group (pid=-%d) with SIGTERM.\n", child_pid);
    kill(-child_pid, SIGTERM);
  }
  else
  {
    fprintf(stderr, "Killing child (pid=%d) with SIGTERM.\n", child_pid);
    kill(child_pid, SIGTERM);
  }

  /* Give the death time to propagate. */
  sleep(2);

  success = kill(grandchild_pid, SIGTERM);
  if(success == -1 && errno == ESRCH)
    fprintf(stderr, "Grandchild died too.\n");
  else if(success == 0)
    fprintf(stderr, "Grandchild did not die on its own, so we sent it SIGTERM.\n");
  else
  {
    perror("kill()");
    exit(1);
  }

  sleep(2);

  fprintf(stderr, "\n");
}


int main()
{
  setup_signals();
  fprintf(stderr, "I am the parent, pid=%d\n", getpid());

  spawn_and_kill_children(NULL, NULL);
  spawn_and_kill_children(setpgrp, "setpgrp()");
  spawn_and_kill_children(setsid, "setsid()");

  return 0;
}