Museum

Home

Lab Overview

Retrotechnology Articles

Online Manuals

⇒ jobs(3) — DG/UX 4.00

Media Vault

Software Library

Restoration Projects

Artifacts Sought



                                                                  jobs(3)



        _________________________________________________________________
        jobs                                                   Subroutine
        summary of job control facilities in DG/UX
        _________________________________________________________________


        SYNTAX

        #include <sys/sgtty.h>
        #include <signal.h>
        #include <sys/vtimes.h>
        #include <wait.h>

        int fildes, signo;
        short pid, pgrp;
        union wait status;
        struct vtimes vt;

        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)

        wait3(&status, options, &vt)

        DESCRIPTION

        The facilities described here to support the job control
        implemented in csh(1), and may be used in other programs to
        provide similar facilities.

        For descriptions of the individual routines, see SEE ALSO below.
        This section describes the facilities in general.

        Terminal arbitration mechanisms

        The job control mechanism works by associating with each process
        a number called a process group; related processes (e.g. in a
        pipeline) are given the same process group.  The system assigns a
        single process group number to each 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.




        DG/UX 4.00                                                 Page 1
               Licensed material--property of copyright holder(s)





                                                                  jobs(3)



        Thus, a command interpreter may start several jobs running in
        different process groups and arbitrate access to the terminal by
        controlling which, if any, of these processes is in the same
        process group as the terminal.  When a process outside 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.  This usually stops them  until they are continued with a
        SIGCONT signal.  (See sigsys(2) for a description of these
        signals; see tty(4) for a description of process groups.)

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

        How the shell manipulates process groups

        An interactive shell first establishes its own process group and
        a process group for the terminal; this keeps other processes from
        being stopped while the terminal is under its control.  The shell
        then assigns a distinct process group to each job it creates.
        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 ioctl(2) and tty(4)).  When a job stops or completes,
        the shell reclaims the terminal by resetting the terminal's
        process group to that of the shell, using TIOCSPGRP again.

        Shells 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 whose parents have exited, and descendants of these
        processes, are protected by the system 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 that ignore or hold the SIGTTIN
        or SIGTTOU signal are not sent these signals when accessing their
        control terminal; 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.



        DG/UX 4.00                                                 Page 2
               Licensed material--property of copyright holder(s)





                                                                  jobs(3)



        Before a shell suspends itself, it places itself back in the
        process group in which it was created. It then sends this
        original group a stopping signal, stopping the shell, and any
        other intermediate processes, back up to an interactive parent.
        The shell also restores the process group of the terminal when it
        finishes; the process that resumes might not have control of the
        terminal otherwise.

        Naive processes

        A naive process does not alter the state of the terminal, and
        does no job control. It can usually invoke subprocesses safely,
        even if it has shell escapes or invokes other processes.  If such
        a process issues a system(3) call and this command is then
        stopped, both of the processes will stop together.  Thus simple
        processes need not worry about job control.

        Processes that 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, SIGHOLD);
             sigset(SIGTTIN, SIGHOLD);
             sigset(SIGTTOU, SIGHOLD);
             if (ioctl(2, TIOCGPGRP, &tpgrp) != 0)
                  goto nottty;
             if (tpgrp != getpgrp(0)) { /* not in foreground */
                  sigset(SIGTTOU, SIGDFL);
                  kill(0, SIGTTOU);
                  /* job stops here waiting for SIGCONT */
                  goto retry;
             }
             ...save old terminal modes and set new modes...
             sigset(SIGTTIN, onstop);
             sigset(SIGTTOU, onstop);
             sigset(SIGTSTP, onstop);

        SIGTSTP is ignored in this code to prevent our process from being
        moved from the foreground to the background while checking if it
        is in the foreground.  The process holds all the stopping signals
        in this critical section so that no other process in our process
        group can block us on one of these signals in the middle of our



        DG/UX 4.00                                                 Page 3
               Licensed material--property of copyright holder(s)





                                                                  jobs(3)



        check.  (This code assumes that the command interpreter will not
        move a process from foreground to background without stopping it;
        if it did, we could not make the check correctly.)

        The signal-handling routine should clear the catch for the stop
        signal and kill(2) the processes in its process group with the
        same signal.  The statement after this kill will be executed when
        the process is 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;
        {
             ... restore old terminal state ...
             sigset(signo, SIGDFL);
             kill(0, signo);
             /* stop here until continued */
             sigset(signo, onstop);
             ... restore our special terminal state ...
        }

        This routine can also 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 that 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 that would normally have hung will return end-of-
        file; writes that would normally have caused SIGTTOU signals are
        instead permitted while SIGTTOU is ignored.

        Interrupt-level process handling

        Sigset(3) lets you handle process state changes as they occur. It
        provides an interrupt-handling routine for the SIGCHLD signal, a
        signal that occurs whenever the status of a child process
        changes.  You establish a signal handler as follows:

             sigset(SIGCHLD, onchild);




        DG/UX 4.00                                                 Page 4
               Licensed material--property of copyright holder(s)





                                                                  jobs(3)



        The shell or other process then waits for a change in child
        status with code like this:

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

        Here, sighold temporarily blocks the SIGCHLD signal while the
        data structures are checked for a child to process.  If we didn't
        block the signal, we would have a race condition; the signal
        might corrupt our decision by arriving shortly after we had
        finished checking the condition but before we paused.

        If we need to wait, we call sigpause, which automically releases
        the hold on the SIGCHLD signal and waits for a signal to occur by
        starting a pause(2).  Otherwise, we simply release the SIGCHLD
        signal and process the child.

        Important: a long-standing bug in the signal mechanism has been
        fixed.  The bug lost a SIGCHLD signal if it occurred while the
        signal was blocked.  This is because sighold uses the SIG_HOLD
        signal set of sigsys(2) to prevent the signal action from being
        taken without losing the signal.  Similarly, a signal action set
        with sigset has the signal held while the action routine is
        running, much as the interrupt priority of a processor is raised
        when a device interrupt is taken.

        In this interrupt-driven style of termination processing, wait
        calls must not block when they retrieve status in the SIGCHLD
        signal handler.  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 only one interrupt is taken.

        It is even possible that no children will 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 collect all
        information by calling wait3 until no more information is
        available.  Further status changes are guaranteed to be reflected
        in another SIGCHLD handler call.

        Restarting system calls



        DG/UX 4.00                                                 Page 5
               Licensed material--property of copyright holder(s)





                                                                  jobs(3)



        In older versions of UNIX, slow system calls were interrupted
        when signals occurred, returning EINTR.  The new signal mechanism
        sigset(3) normally restarts such calls rather than interrupting
        them.  To summarize:  pause and wait return error EINTR (as
        before), ioctl and wait3 restart, and read and write restart
        unless some data was read or written; in that case, they return
        indicating how much data was read or written.  In programs that
        use the older signal(2) mechanisms, all of these calls return
        EINTR if a signal occurs during the call.


        SEE ALSO

        ioctl(2), killpg(2), setpgrp(2), sigsys(2), wait3(2), sigset(3),
        tty(4)
        csh(1) in the User's Reference for the DG/UX System.






































        DG/UX 4.00                                                 Page 6
               Licensed material--property of copyright holder(s)



Typewritten Software • bear@typewritten.org • Edmonds, WA 98026