#include <sys/types.h> #include <unistd.h> int setpgid(pid_t pid, pid_t pgid);
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.
setpgid
returns a 0
if successful and
a - 1
if not successful.
A / \ / \ B C / \ / \ D EProcess 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 */ }
getpgrp
, setsid
, tcsetpgrp