Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should processes in process group terminate together with their parent in Unix/Linux?

I have situation where one parent process may spawn many child processes. What I want to achieve is that if parent process is killed or if it exits, then all it's children should terminate together with parent.

In the post (link below) I have found suggestion to archive this by making parent process a group leader. If I understand it right this is also the main purpose of process groups. Am I right?
Post also mentions prctl(PR_SET_PDEATHSIG, SIGHUP); and some other methods, but they are ether OS specific or otherwise don't seam so elegant.

I have written a small demo to try to understand things better, but it doesn't work the way I expect. What am I doing wrong?

//https://www.andrew.cmu.edu/course/15-310/applications/homework/homework4/terminalgroups1.html
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <stddef.h>
#include <errno.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/termios.h>

int main()
{
    int status;
    int cpid;
    int ppid;

    ppid = getpid();
    printf("parent: %d\n", ppid);

    if (!(cpid=fork()))
    {
        printf("child: %d\n", getpid());
        if(setpgid(0,ppid) == -1)
           printf("child setpgid errno %s\n", strerror(errno));
        else
           printf("child gid %d\n", getpgid(0));
        pause();
        printf("child exited\n");
        exit (-1);
     }

     if (cpid < 0)
         exit(-1);

     setpgid(0, ppid);
     if(setpgid(0,0) == -1)
         printf("parent setpgid erno %s\n", strerror(errno));
     else
         printf("parrent gid %d\n", getpgid(0));


     sleep(7);
     printf("parent exit\n");
     exit(0);
}

This post relates to suggestion made in : * How to make child process die after parent exits?

like image 783
user2979375 Avatar asked May 13 '14 06:05

user2979375


People also ask

Does killing a parent process kill the child process Linux?

In Linux,When we kill parent process then child process will become Orphan and child process is adopt by init process so then ppid of child process will 1. On UNIX, there is no enforced relation between parent and child process's lifetimes.

How do you end a process group?

If it is a process group you want to kill, just use the kill(1) command but instead of giving it a process number, give it the negation of the group number. For example to kill every process in group 5112, use kill -TERM -- -5112 .

Does killing a process kill all child processes?

Killing a parent doesn't kill the child processes Every process has a parent. We can observe this with pstree or the ps utility. The ps command displays the PID (id of the process), and the PPID (parent ID of the process).

How do you end a process in Linux?

There are two commands used to kill a process: kill – Kill a process by ID. killall – Kill a process by name.


2 Answers

Note that a signal is sent to child processes only in a very limited set of circumstances. POSIX says:

  • If the process is a controlling process, the SIGHUP signal shall be sent to each process in the foreground process group of the controlling terminal belonging to the calling process.

  • If the process is a controlling process, the controlling terminal associated with the session shall be disassociated from the session, allowing it to be acquired by a new controlling process.

  • If the exit of the process causes a process group to become orphaned, and if any member of the newly-orphaned process group is stopped, then a SIGHUP signal followed by a SIGCONT signal shall be sent to each process in the newly-orphaned process group.

The definition of controlling process is:

The session leader that established the connection to the controlling terminal. If the terminal subsequently ceases to be a controlling terminal for this session, the session leader ceases to be the controlling process.

In general, your process is not going to be the session leader that established the connection to the controlling terminal (that will normally be your shell).

If there's another part of POSIX that applies, please inform me.

I did some testing with this adaptation of your code (termkids.c):

#include "posixver.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>

static void sigcatcher(int signum)
{

  printf("%d: Signal caught: %d\n", (int)getpid(), signum);
  exit(1);
}

int main(void)
{
    int cpid;
    int ppid;

    ppid = getpid();
    printf("Parent  PID:  %d\n", ppid);
    printf("Initial PGID: %d\n", (int)getpgid(0));
    if (setpgid(0, 0) != 0)
    {
      fprintf(stderr, "setpgid() failed (%d: %s)\n", errno, strerror(errno));
      return 1;
    }
    printf("Revised PGID: %d\n", (int)getpgid(0));

    if ((cpid=fork()) < 0)
    {
      fprintf(stderr, "fork() failed (%d: %s)\n", errno, strerror(errno));
      return 1;
    }
    else if (cpid == 0)
    {
        cpid = getpid();
        printf("Child PID:  %d\n", cpid);
        printf("Child PGID: %d\n", (int)getpgid(0));
        (void)signal(SIGTERM, sigcatcher);
        (void)signal(SIGHUP,  sigcatcher);

        pause();
        printf("%d: child exited\n", cpid);
        return(-1);
     }

     printf("Parent - sleeping\n");
     sleep(7);
     printf("Parent exits\n");
     return(0);
}

Sample output:

$ ./termkids
Parent  PID:  17701
Initial PGID: 17701
Revised PGID: 17701
Parent - sleeping
Child PID:  17702
Child PGID: 17701
Parent exits
$ ps
  PID TTY          TIME CMD
  388 pts/5    00:00:00 bash
17702 pts/5    00:00:00 termkids
17707 pts/5    00:00:00 ps
$ kill 17702
17702: Signal caught: 15
$

Note that the kill 17702 was sent some minutes after the parent process completed.

like image 106
Jonathan Leffler Avatar answered Sep 28 '22 01:09

Jonathan Leffler


You can use atexit to register a function that sends a SIGHUP signal to all the processes with the same process group id. That would have the desired effect of sending a signal to all the children when the parent exits. However, note that the SIGHUP signal handler in the children would cause the child to exit immediately, without returning from pause() and printing the child exited message.

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <stddef.h>
#include <errno.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/termios.h>
#include <sys/types.h>

void killall() 
{
    kill(0, SIGHUP);
}

int main()
{
    int status;
    int cpid;
    int ppid;

    if (atexit(killall) != 0)
    {
        fprintf(stderr, "atexit failed with %d", errno);
        exit(-1);
    }

    ppid = getpid();
    printf("parent: %d\n", ppid);

    if (!(cpid=fork()))
    {
       printf("child: %d\n", getpid());
       if(setpgid(0,ppid) == -1)
           printf("child setpgid errno %s\n", strerror(errno));
       else
           printf("child gid %d\n", getpgid(0));
       pause();
       printf("child exited\n");
       exit (-1);
     }

     if (cpid < 0)
         exit(-1);

     setpgid(0, ppid);
     if(setpgid(0,0) == -1)
         printf("parent setpgid erno %s\n", strerror(errno));
     else
         printf("parent gid %d\n", getpgid(0));


     sleep(7);
     printf("parent exit\n");
     exit(0);
}
like image 20
Patrick Mackinlay Avatar answered Sep 28 '22 02:09

Patrick Mackinlay