setpgid -- Specify Process Group ID for Job Control

SYNOPSIS

 #include <sys/types.h>
 #include <unistd.h>

 int setpgid(pid_t pid, pid_t pgid);
 

DESCRIPTION

setpgid is used either to join an existing process group or to create a new process group. The process specified by pid (or the calling process if pid is 0) is joined to the process group whose ID is pgid. If pgid is not an existing process group ID, then pgid must equal pid or be 0, in which case a new process group with ID pid is created.

RETURN VALUE

setpgid returns a 0 if successful and a - 1 if not successful.

EXAMPLE

This example creates a number of processes, to illustrate the behavior of process groups and sessions. The process tree looks like:
                            A
                           / \
                          /   \
                         B     C
                        /       \
                       /         \
                      D           E
 
Process D uses setsid to define itself as a new session. The other processes remain in the session of A. The processes A and B comprise one process group, while C and E comprise another. The tcsetpgrp function is used to cause C's process group to become the foreground process group.
  #include <sys/types.h>
  #include <unistd.h>
  #include <stdio.h>
  #include <signal.h>

  char process = 'A';       /* the process ID of the running process */

  void status(void) {
       /* display interesting process IDs                            */
     printf("process %c: pid=%d, ppid=%d, pgid=%d, fg pgid=%dn",
             process, (int) getpid(), (int) getppid(),
             (int) getpgrp(), (int) tcgetpgrp(STDIN_FILENO));
  }

  void erreport(char *func) {  /* report an error and abort          */
     fprintf(stderr, "process %c ", process);
     perror(func);
     abort();
  }

  void timeout(void) {         /* wait up to 10 seconds, then quit   */
     unsigned waitfor = 20;

     while(waitfor)
        waitfor = sleep(waitfor);
          /* wait quietly ignoring signals for 20 seconds            */
        printf("process %c: Terminating after 20 seconds.n", process);
        exit(0);
  }

  void ttinhdlr(int signum) {
     printf("process %c: SIGTTIN detected.n", process);
  }

  void usr1hdlr(int signum) {
    /* null handler - allows parent to wait for init of child        */
  }

  void termhdlr(int signum) {
     printf("process %c: SIGTERM detected, terminating.n", process);
     exit(0);
  }

  void catchsig(void) {
     struct sigaction action;
     action.sa_handler = &ttinhdlr;
     sigemptyset(&action.sa_mask);
     action.sa_flags = 0;
     if (sigaction(SIGTTIN, &action, 0)) erreport("sigaction");
     action.sa_handler = &termhdlr;
     if (sigaction(SIGTERM, &action, 0)) erreport("sigaction");
     action.sa_handler = &usr1hdlr;
     if (sigaction(SIGUSR1, &action, 0)) erreport("sigaction");
  }

  pid_t createE(void) {
       /* fork and run process E - called by process C               */
     pid_t child;

     if ((child = fork()) != 0) return child;
       /* if running in parent, return child pid                     */
     process = 'E';
     catchsig();
     status();
     kill(getppid(), SIGUSR1); /* inform parent child is ready       */
     timeout();
     return -1;                /* should not occur                   */
  }

  pid_t createC(void) {
       /* fork and run process C - called by process A               */
     pid_t child;
     sigset_t newmask, oldmask;

     if ((child = fork()) != 0) return child;
       /* if running in parent, return child pid                     */
     process = 'C';
     catchsig();
     if (setpgid(0, 0) < 0)    /* create new process group           */
        erreport("setpgid");
     if (tcsetpgrp(STDIN_FILENO, getpid()))
                               /* become forgeground process group   */
        erreport("tcsetpgrp");
     status();
     if (createE() < 0) erreport("fork");
     pause();                  /* wait for SIGUSR1 from child        */
     sigemptyset(&newmask);
     sigaddset(&newmask, SIGTERM);
     sigprocmask(SIG_BLOCK, &newmask, &oldmask);
                               /* block SIGTERM until input read     */
     kill(getppid(), SIGUSR1); /* inform parent child is ready       */
     (void) getc(stdin);    /* attempt to read from stdin (terminal) */
     sigprocmask(SIG_SETMASK, &oldmask, 0);
                               /* allow SIGTERM to interrupt now     */
     timeout();
     return -1;                /* should not occur                   */
  }

  pid_t createD(void) {
       /* fork and run process D - called by process B               */
     pid_t child;

     if ((child = fork()) != 0) return child;
          /* if running in parent, return child pid                  */
     process = 'D';
     catchsig();
     setsid();                 /* start new session                  */
     status();
     kill(getppid(), SIGUSR1); /* inform parent child is ready       */
     timeout();
     return -1;                /* should not occur                   */
  }

  pid_t createB(void) {
       /* fork and run process B - called by process A               */
     pid_t child;

     if ((child = fork()) != 0) return child;
        /* if running in parent, return child pid                    */
     process = 'B';
     catchsig();
     status();
     if (createD() < 0) erreport("fork");
     pause();                  /* wait for SIGUSR1 from child        */
     kill(getppid(), SIGUSR1); /* inform parent child is ready       */
     timeout();
     return -1;                /* should not occur                   */
  }

  int main(void) {
     pid_t Cpid;               /* process id for C                   */
     pid_t Apid;               /* process id for A                   */

     Apid = getpid();
     status();
     printf("Enter carriage return to satisfy terminal read.n");
     catchsig();
     if (createB() < 0) erreport("fork");
     pause();                  /* wait for SIGUSR1 from child        */
     if ((Cpid = createC()) < 0) erreport("fork");
     pause();                  /* wait for SIGUSR1 from child        */
     while (tcgetpgrp(STDIN_FILENO) == getpid())
        sleep(5);     /* wait for foreground process group to change */
     (void) getc(stdin);  /* attempt to read from stdin (terminal)   */
                          /* should generate SIGTTIN                 */
     sleep(2);            /* allow other processes to do their thing */
     kill(-Cpid, SIGTERM);/* terminate processes C and E             */
     kill(0, SIGTERM);    /* terminate processes A and B             */
                          /* D will remain for some seconds          */
  }


 

RELATED FUNCTIONS

getpgrp, setsid, tcsetpgrp