2.9BSD/usr/man/cat3/jobs.3j


JOBS(3J)            UNIX Programmer's Manual             JOBS(3J)

NAME
     jobs - summary of job control facilities

SYNOPSIS
     #include <sys/ioctl.h>
     #include <signal.h>
     #include <sys/vtimes.h>  (_V_a_x _o_n_l_y)
     #include <wait.h>

     int fildes, signo;
     short pid, pgrp;
     union wait status;
     struct vtimes vt;   (_V_a_x _o_n_l_y)

     ioctl(fildes, TIOCSPGRP, &pgrp)
     ioctl(fildes, TIOCGPGRP, &pgrp)

     setpgrp(pid, pgrp)
     getpgrp(pid)
     killpg(pgrp, signo)

     sigset(signo, action)
     sighold(signo)
     sigrelse(signo)
     sigpause(signo)
     sigsys(signo, action)

     wait2(&status, options)  (_P_D_P_1_1 _o_n_l_y)
     wait3(&status, options, &vt)  (_V_a_x _o_n_l_y)

     cc ... -ljobs

DESCRIPTION
     The facilities described here are used to support the job
     control implemented in _c_s_h(1), and may be used in other pro-
     grams to provide similar facilities.  Because these facili-
     ties are not standard in UNIX and because the signal mechan-
     isms are also slightly different, the associated routines
     are not in the standard C library, but rather in the -ljobs
     library.

     For descriptions of the individual routines see the various
     sections listed in SEE ALSO below.  This section attempt
     only to place these facilities in context, not to explain
     the semantics of the individual calls.

     Terminal arbitration mechanisms.

     The job control mechanism works by associating with each
     process a number called a _p_r_o_c_e_s_s _g_r_o_u_p ; related processes
     (e.g. in a pipeline) are given the same process group.  The
     system assigns a single process group number to each

Printed 12/7/82                                                 1

JOBS(3J)            UNIX Programmer's Manual             JOBS(3J)

     terminal.  Processes running on a terminal are given read
     access to that terminal only if they are in the same process
     group as that terminal.

     Thus a command interpreter may start several jobs running in
     different process groups and arbitrate access to the termi-
     nal by controlling which, if any, of these processes is in
     the same process group as the terminal.  When a process
     which is not in the process group of the terminal tries to
     read from the terminal, all members of the process group of
     the process receive a SIGTTIN signal, which normally then
     causes them to stop until they are continued with a SIGCONT
     signal.  (See _s_i_g_s_y_s(2) for a description of these signals;
     _t_t_y(4) for a description of process groups.)

     If a process which is not in the process group of the termi-
     nal attempts to change the terminals mode, the process group
     of that process is sent a SIGTTOU signal, causing the pro-
     cess group to stop.  A similar mechanism is (optionally)
     available for output, causing processes to block with
     SIGTTOU when they attempt to write to the terminal while not
     in its process group; this is controlled by the LTOSTOP bit
     in the tty mode word, enabled by stty tostop and disabled
     (the default) by stty -tostop.  (The LTOSTOP bit is
     described in _t_t_y(4)).

     How the shell manipulates process groups.

     A shell which is interactive first establishes its own pro-
     cess group and a process group for the terminal; this
     prevents other processes from being inadvertantly stopped
     while the terminal is under its control.  The shell then
     assigns each job it creates a distinct process group.  When
     a job is to be run in the foreground, the shell gives the
     terminal to the process group of the job using the TIOCSPGRP
     ioctl (See _i_o_c_t_l(2) and _t_t_y(4)).  When a job stops or com-
     pletes, the shell reclaims the terminal by resetting the
     terminals process group to that of the shell using TIOCSPGRP
     again.

     Shells which are running shell scripts or running non-
     interactively do not manipulate process groups of jobs they
     create.  Instead, they leave the process group of sub-
     processes and the terminal unchanged.  This assures that if
     any sub-process they create blocks for terminal i/o, the
     shell and all its sub-processes will be blocked (since they
     are a single process group).  The first interactive parent
     of the non-interactive shell can then be used to deal with
     the stoppage.

     Processes which are orphans (whose parents have exited), and
     descendants of these processes are protected by the system

Printed 12/7/82                                                 2

JOBS(3J)            UNIX Programmer's Manual             JOBS(3J)

     from stopping, since there can be no interactive parent.
     Rather than blocking, reads from the control terminal return
     end-of-file and writes to the control terminal are permitted
     (i.e. LTOSTOP has no effect for these processes.) Similarly
     processes which ignore or hold the SIGTTIN or SIGTTOU signal
     are not sent these signals when accessing their control ter-
     minal; if they are not in the process group of the control
     terminal reads simply return end-of-file.  Output and mode
     setting are also allowed.

     Before a shell _s_u_s_p_e_n_d_s itself, it places itself back in the
     process group in which it was created, and then sends this
     original group a stopping signal, stopping the shell and any
     other intermediate processes back to an interactive parent.
     The shell also restores the process group of the terminal
     when it finishes, as the process which then resumes would
     not necessarily be in control of the terminal otherwise.

     Naive processes.

     A process which does not alter the state of the terminal,
     and which does no job control can invoke subprocesses nor-
     mally without worry.  If such a process issues a _s_y_s_t_e_m(3)
     call and this command is then stopped, both of the processes
     will stop together.  Thus simple processes need not worry
     about job control, even if they have shell escapes or invoke
     other processes.

     Processes which modify the terminal state.

     When first setting the terminal into an unusual mode, the
     process should check, with the stopping signals held, that
     it is in the foreground.  It should then change the state of
     the terminal, and set the catches for SIGTTIN, SIGTTOU and
     SIGTSTP.  The following is a sample of the code that will be
     needed, assuming that unit 2 is known to be a terminal.

          short     tpgrp;
          ...

     retry:
          sigset(SIGTSTP, SIG_HOLD);
          sigset(SIGTTIN, SIG_HOLD);
          sigset(SIGTTOU, SIG_HOLD);
          if (ioctl(2, TIOCGPGRP, &tpgrp) != 0)
               goto nottty;
          if (tpgrp != getpgrp(0)) { /* not in foreground */
               sigset(SIGTTOU, SIG_DFL);
               kill(0, SIGTTOU);
               /* job stops here waiting for SIGCONT */
               goto retry;
          }

Printed 12/7/82                                                 3

JOBS(3J)            UNIX Programmer's Manual             JOBS(3J)

          ..._s_a_v_e _o_l_d _t_e_r_m_i_n_a_l _m_o_d_e_s _a_n_d _s_e_t _n_e_w _m_o_d_e_s...
          sigset(SIGTTIN, onstop);
          sigset(SIGTTOU, onstop);
          sigset(SIGTSTP, onstop);

     It is necessary to ignore SIGTSTP in this code because oth-
     erwise our process could be moved from the foreground to the
     background in the middle of checking if it is in the fore-
     ground.  The process holds all the stopping signals in this
     critical section so no other process in our process group
     can mess us up by blocking us on one of these signals in the
     middle of our check.  (This code assumes that the command
     interpreter will not move a process from foreground to back-
     ground without stopping it; if it did we would have no way
     of making the check correctly.)

     The routine which handles the signal should clear the catch
     for the stop signal and _k_i_l_l(2) the processes in its process
     group with the same signal.  The statement after this _k_i_l_l
     will be executed when the process is later continued with
     SIGCONT.

     Thus the code for the catch routine might look like:

          ...
          sigset(SIGTSTP, onstop);
          sigset(SIGTTIN, onstop);
          sigset(SIGTTOU, onstop);
          ...

     onstop(signo)
          int signo;
     {
          ... _r_e_s_t_o_r_e _o_l_d _t_e_r_m_i_n_a_l _s_t_a_t_e ...
          sigset(signo, SIG_DFL);
          kill(0, signo);
          /* stop here until continued */
          sigset(signo, onstop);
          ... _r_e_s_t_o_r_e _o_u_r _s_p_e_c_i_a_l _t_e_r_m_i_n_a_l _s_t_a_t_e ...
     }

     This routine can also be used to simulate a stop signal.

     If a process does not need to save and restore state when it
     is stopped, but wishes to be notified when it is continued
     after a stop it can catch the SIGCONT signal; the SIGCONT
     handler will be run when the process is continued.

     Processes which lock data bases such as the password file
     should ignore SIGTTIN, SIGTTOU, and SIGTSTP signals while
     the data bases are being manipulated.  While a process is
     ignoring SIGTTIN signals, reads which would normally have

Printed 12/7/82                                                 4

JOBS(3J)            UNIX Programmer's Manual             JOBS(3J)

     hung will return end-of-file; writes which would normally
     have caused SIGTTOU signals are instead permitted while
     SIGTTOU is ignored.

     Interrupt-level process handling.

     Using the mechanisms of _s_i_g_s_e_t(3) it is possible to handle
     process state changes as they occur by providing an
     interrupt-handling routine for the SIGCHLD signal which
     occurs whenever the status of a child process changes.  A
     signal handler for this signal is established by:

          sigset(SIGCHLD, onchild);

     The shell or other process would then await a change in
     child status with code of the form:

     recheck:
          sighold(SIGCHLD);        /* start critical section */
          if (_n_o _c_h_i_l_d_r_e_n _t_o _p_r_o_c_e_s_s) {
               sigpause(SIGCHLD);  /* release SIGCHLD and pause */
               goto recheck;
          }
          sigrelse(SIGCHLD);       /* end critical region */
          /* now have a child to process */

     Here we are using _s_i_g_h_o_l_d to temporarily block the SIGCHLD
     signal during the checking of the data structures telling us
     whether we have a child to process.  If we didn't block the
     signal we would have a race condition since the signal might
     corrupt our decision by arriving shortly after we had fin-
     ished checking the condition but before we paused.

     If we need to wait for something to happen, we call _s_i_g_p_a_u_s_e
     which automically releases the hold on the SIGCHLD signal
     and waits for a signal to occur by starting a _p_a_u_s_e(2).
     Otherwise we simply release the SIGCHLD signal and process
     the child.  _S_i_g_p_a_u_s_e is similar to the PDP-11 _w_a_i_t instruc-
     tion, which returns the priority of the processor to the
     base level and idles waiting for an interrupt.

     It is important to note that the long-standing bug in the
     signal mechanism which would have lost a SIGCHLD signal
     which occurred while the signal was blocked has been fixed.
     This is because _s_i_g_h_o_l_d uses the SIG_HOLD signal set of _s_i_g_-
     _s_y_s(2) to prevent the signal action from being taken without
     losing the signal if it occurs.  Similarly, a signal action
     set with _s_i_g_s_e_t has the signal held while the action routine
     is running, much as a the interrupt priority of the proces-
     sor is raised when a device interrupt is taken.

Printed 12/7/82                                                 5

JOBS(3J)            UNIX Programmer's Manual             JOBS(3J)

     In this interrupt driven style of termination processing it
     is necessary that the _w_a_i_t calls used to retrieve status in
     the SIGCHLD signal handler not block.  This is because a
     single invocation of the SIGCHLD handler may indicate an
     arbitrary number of process status changes: signals are not
     queued.  This is similar to the case in a disk driver where
     several drives on a single controller may report status at
     once, while there is only one interrupt taken.  It is even
     possible for no children to be ready to report status when
     the SIGCHLD handler is invoked, if the signal was posted
     while the SIGCHLD handler was active, and the child was
     noticed due to a SIGCHLD initially sent for another process.
     This causes no problem, since the handler will be called
     whenever there is work to do; the handler just has to col-
     lect all information by calling _w_a_i_t_3 until it says no more
     information is available.  Further status changes are
     guaranteed to be reflected in another SIGCHLD handler call.

     Restarting system calls.

     In older versions of UNIX slow system calls were interrupted
     when signals occurred, returning EINTR.  The new signal
     mechanism _s_i_g_s_e_t(3) normally restarts such calls rather than
     interrupting them.  To summarize: _p_a_u_s_e and _w_a_i_t return
     error EINTR (as before), _i_o_c_t_l and _w_a_i_t_3 restart, and _r_e_a_d
     and _w_r_i_t_e restart unless some data was read or written in
     which case they return indicating how much data was read or
     written.  In programs which use the older _s_i_g_n_a_l(2) mechan-
     isms, all of these calls return EINTR if a signal occurs
     during the call.

SEE ALSO
     csh(1), ioctl(2), killpg(2), setpgrp(2), sigsys(2),
     wait3(2), signal(3), tty(4)

BUGS
     The job control facilities are not available in standard
     version 7 UNIX.  These facilities are still under develop-
     ment and may change in future releases of the system as
     better inter-process communication facilities and support
     for virtual terminals become available.  The options and
     specifications of these system calls and even the calls
     themselves are thus subject to change.

Printed 12/7/82                                                 6