Chapter Contents

Previous

Next
setpgid

setpgid



Specify Process Group ID for Job Control

Portability: POSIX.1 conforming


SYNOPSIS
DESCRIPTION
RETURN VALUE
EXAMPLE
RELATED FUNCTIONS


SYNOPSIS

#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");
     
     /* ignore SIGTTOU during tcsetpgrp                            */
   signal(SIGTTOU, SIG_IGN);
     /* ignore SIGTTOU during tcsetpgrp */
   signal(SIGTTOU, SIG_IGN);
     /* become foreground process group */
   if (tcsetpgrp(STDIN_FILENO, getpid()))
         erreport("tcsetpgrp");
     /* restore normal SIGTTOU handling */
   signal(SIGTTOU, SIG_DFL);
     /* restore normal SIGTTOU handling                            */
   signal(SIGTTOU, SIG_DFL);
   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


Chapter Contents

Previous

Next

Top of Page

Copyright © 2001 by SAS Institute Inc., Cary, NC, USA. All rights reserved.