aboutsummaryrefslogtreecommitdiff
path: root/manual/job.texi
diff options
context:
space:
mode:
Diffstat (limited to 'manual/job.texi')
-rw-r--r--manual/job.texi1319
1 files changed, 0 insertions, 1319 deletions
diff --git a/manual/job.texi b/manual/job.texi
deleted file mode 100644
index 72b55997d2..0000000000
--- a/manual/job.texi
+++ /dev/null
@@ -1,1319 +0,0 @@
-@node Job Control, Name Service Switch, Inter-Process Communication, Top
-@c %MENU% All about process groups and sessions
-@chapter Job Control
-
-@cindex process groups
-@cindex job control
-@cindex job
-@cindex session
-@dfn{Job control} refers to the protocol for allowing a user to move
-between multiple @dfn{process groups} (or @dfn{jobs}) within a single
-@dfn{login session}. The job control facilities are set up so that
-appropriate behavior for most programs happens automatically and they
-need not do anything special about job control. So you can probably
-ignore the material in this chapter unless you are writing a shell or
-login program.
-
-You need to be familiar with concepts relating to process creation
-(@pxref{Process Creation Concepts}) and signal handling (@pxref{Signal
-Handling}) in order to understand this material presented in this
-chapter.
-
-@menu
-* Concepts of Job Control:: Jobs can be controlled by a shell.
-* Job Control is Optional:: Not all POSIX systems support job control.
-* Controlling Terminal:: How a process gets its controlling terminal.
-* Access to the Terminal:: How processes share the controlling terminal.
-* Orphaned Process Groups:: Jobs left after the user logs out.
-* Implementing a Shell:: What a shell must do to implement job control.
-* Functions for Job Control:: Functions to control process groups.
-@end menu
-
-@node Concepts of Job Control, Job Control is Optional, , Job Control
-@section Concepts of Job Control
-
-@cindex shell
-The fundamental purpose of an interactive shell is to read
-commands from the user's terminal and create processes to execute the
-programs specified by those commands. It can do this using the
-@code{fork} (@pxref{Creating a Process}) and @code{exec}
-(@pxref{Executing a File}) functions.
-
-A single command may run just one process---but often one command uses
-several processes. If you use the @samp{|} operator in a shell command,
-you explicitly request several programs in their own processes. But
-even if you run just one program, it can use multiple processes
-internally. For example, a single compilation command such as @samp{cc
--c foo.c} typically uses four processes (though normally only two at any
-given time). If you run @code{make}, its job is to run other programs
-in separate processes.
-
-The processes belonging to a single command are called a @dfn{process
-group} or @dfn{job}. This is so that you can operate on all of them at
-once. For example, typing @kbd{C-c} sends the signal @code{SIGINT} to
-terminate all the processes in the foreground process group.
-
-@cindex session
-A @dfn{session} is a larger group of processes. Normally all the
-processes that stem from a single login belong to the same session.
-
-Every process belongs to a process group. When a process is created, it
-becomes a member of the same process group and session as its parent
-process. You can put it in another process group using the
-@code{setpgid} function, provided the process group belongs to the same
-session.
-
-@cindex session leader
-The only way to put a process in a different session is to make it the
-initial process of a new session, or a @dfn{session leader}, using the
-@code{setsid} function. This also puts the session leader into a new
-process group, and you can't move it out of that process group again.
-
-Usually, new sessions are created by the system login program, and the
-session leader is the process running the user's login shell.
-
-@cindex controlling terminal
-A shell that supports job control must arrange to control which job can
-use the terminal at any time. Otherwise there might be multiple jobs
-trying to read from the terminal at once, and confusion about which
-process should receive the input typed by the user. To prevent this,
-the shell must cooperate with the terminal driver using the protocol
-described in this chapter.
-
-@cindex foreground job
-@cindex background job
-The shell can give unlimited access to the controlling terminal to only
-one process group at a time. This is called the @dfn{foreground job} on
-that controlling terminal. Other process groups managed by the shell
-that are executing without such access to the terminal are called
-@dfn{background jobs}.
-
-@cindex stopped job
-If a background job needs to read from its controlling
-terminal, it is @dfn{stopped} by the terminal driver; if the
-@code{TOSTOP} mode is set, likewise for writing. The user can stop
-a foreground job by typing the SUSP character (@pxref{Special
-Characters}) and a program can stop any job by sending it a
-@code{SIGSTOP} signal. It's the responsibility of the shell to notice
-when jobs stop, to notify the user about them, and to provide mechanisms
-for allowing the user to interactively continue stopped jobs and switch
-jobs between foreground and background.
-
-@xref{Access to the Terminal}, for more information about I/O to the
-controlling terminal.
-
-@node Job Control is Optional, Controlling Terminal, Concepts of Job Control , Job Control
-@section Job Control is Optional
-@cindex job control is optional
-
-Not all operating systems support job control. @gnusystems{} do
-support job control, but if you are using @theglibc{} on some other
-system, that system may not support job control itself.
-
-You can use the @code{_POSIX_JOB_CONTROL} macro to test at compile-time
-whether the system supports job control. @xref{System Options}.
-
-If job control is not supported, then there can be only one process
-group per session, which behaves as if it were always in the foreground.
-The functions for creating additional process groups simply fail with
-the error code @code{ENOSYS}.
-
-The macros naming the various job control signals (@pxref{Job Control
-Signals}) are defined even if job control is not supported. However,
-the system never generates these signals, and attempts to send a job
-control signal or examine or specify their actions report errors or do
-nothing.
-
-
-@node Controlling Terminal, Access to the Terminal, Job Control is Optional, Job Control
-@section Controlling Terminal of a Process
-
-One of the attributes of a process is its controlling terminal. Child
-processes created with @code{fork} inherit the controlling terminal from
-their parent process. In this way, all the processes in a session
-inherit the controlling terminal from the session leader. A session
-leader that has control of a terminal is called the @dfn{controlling
-process} of that terminal.
-
-@cindex controlling process
-You generally do not need to worry about the exact mechanism used to
-allocate a controlling terminal to a session, since it is done for you
-by the system when you log in.
-@c ??? How does GNU system let a process get a ctl terminal.
-
-An individual process disconnects from its controlling terminal when it
-calls @code{setsid} to become the leader of a new session.
-@xref{Process Group Functions}.
-
-@c !!! explain how it gets a new one (by opening any terminal)
-@c ??? How you get a controlling terminal is system-dependent.
-@c We should document how this will work in the GNU system when it is decided.
-@c What Unix does is not clean and I don't think GNU should use that.
-
-@node Access to the Terminal, Orphaned Process Groups, Controlling Terminal, Job Control
-@section Access to the Controlling Terminal
-@cindex controlling terminal, access to
-
-Processes in the foreground job of a controlling terminal have
-unrestricted access to that terminal; background processes do not. This
-section describes in more detail what happens when a process in a
-background job tries to access its controlling terminal.
-
-@cindex @code{SIGTTIN}, from background job
-When a process in a background job tries to read from its controlling
-terminal, the process group is usually sent a @code{SIGTTIN} signal.
-This normally causes all of the processes in that group to stop (unless
-they handle the signal and don't stop themselves). However, if the
-reading process is ignoring or blocking this signal, then @code{read}
-fails with an @code{EIO} error instead.
-
-@cindex @code{SIGTTOU}, from background job
-Similarly, when a process in a background job tries to write to its
-controlling terminal, the default behavior is to send a @code{SIGTTOU}
-signal to the process group. However, the behavior is modified by the
-@code{TOSTOP} bit of the local modes flags (@pxref{Local Modes}). If
-this bit is not set (which is the default), then writing to the
-controlling terminal is always permitted without sending a signal.
-Writing is also permitted if the @code{SIGTTOU} signal is being ignored
-or blocked by the writing process.
-
-Most other terminal operations that a program can do are treated as
-reading or as writing. (The description of each operation should say
-which.)
-
-For more information about the primitive @code{read} and @code{write}
-functions, see @ref{I/O Primitives}.
-
-
-@node Orphaned Process Groups, Implementing a Shell, Access to the Terminal, Job Control
-@section Orphaned Process Groups
-@cindex orphaned process group
-
-When a controlling process terminates, its terminal becomes free and a
-new session can be established on it. (In fact, another user could log
-in on the terminal.) This could cause a problem if any processes from
-the old session are still trying to use that terminal.
-
-To prevent problems, process groups that continue running even after the
-session leader has terminated are marked as @dfn{orphaned process
-groups}.
-
-When a process group becomes an orphan, its processes are sent a
-@code{SIGHUP} signal. Ordinarily, this causes the processes to
-terminate. However, if a program ignores this signal or establishes a
-handler for it (@pxref{Signal Handling}), it can continue running as in
-the orphan process group even after its controlling process terminates;
-but it still cannot access the terminal any more.
-
-@node Implementing a Shell, Functions for Job Control, Orphaned Process Groups, Job Control
-@section Implementing a Job Control Shell
-
-This section describes what a shell must do to implement job control, by
-presenting an extensive sample program to illustrate the concepts
-involved.
-
-@iftex
-@itemize @bullet
-@item
-@ref{Data Structures}, introduces the example and presents
-its primary data structures.
-
-@item
-@ref{Initializing the Shell}, discusses actions which the shell must
-perform to prepare for job control.
-
-@item
-@ref{Launching Jobs}, includes information about how to create jobs
-to execute commands.
-
-@item
-@ref{Foreground and Background}, discusses what the shell should
-do differently when launching a job in the foreground as opposed to
-a background job.
-
-@item
-@ref{Stopped and Terminated Jobs}, discusses reporting of job status
-back to the shell.
-
-@item
-@ref{Continuing Stopped Jobs}, tells you how to continue jobs that
-have been stopped.
-
-@item
-@ref{Missing Pieces}, discusses other parts of the shell.
-@end itemize
-@end iftex
-
-@menu
-* Data Structures:: Introduction to the sample shell.
-* Initializing the Shell:: What the shell must do to take
- responsibility for job control.
-* Launching Jobs:: Creating jobs to execute commands.
-* Foreground and Background:: Putting a job in foreground of background.
-* Stopped and Terminated Jobs:: Reporting job status.
-* Continuing Stopped Jobs:: How to continue a stopped job in
- the foreground or background.
-* Missing Pieces:: Other parts of the shell.
-@end menu
-
-@node Data Structures, Initializing the Shell, , Implementing a Shell
-@subsection Data Structures for the Shell
-
-All of the program examples included in this chapter are part of
-a simple shell program. This section presents data structures
-and utility functions which are used throughout the example.
-
-The sample shell deals mainly with two data structures. The
-@code{job} type contains information about a job, which is a
-set of subprocesses linked together with pipes. The @code{process} type
-holds information about a single subprocess. Here are the relevant
-data structure declarations:
-
-@smallexample
-@group
-/* @r{A process is a single process.} */
-typedef struct process
-@{
- struct process *next; /* @r{next process in pipeline} */
- char **argv; /* @r{for exec} */
- pid_t pid; /* @r{process ID} */
- char completed; /* @r{true if process has completed} */
- char stopped; /* @r{true if process has stopped} */
- int status; /* @r{reported status value} */
-@} process;
-@end group
-
-@group
-/* @r{A job is a pipeline of processes.} */
-typedef struct job
-@{
- struct job *next; /* @r{next active job} */
- char *command; /* @r{command line, used for messages} */
- process *first_process; /* @r{list of processes in this job} */
- pid_t pgid; /* @r{process group ID} */
- char notified; /* @r{true if user told about stopped job} */
- struct termios tmodes; /* @r{saved terminal modes} */
- int stdin, stdout, stderr; /* @r{standard i/o channels} */
-@} job;
-
-/* @r{The active jobs are linked into a list. This is its head.} */
-job *first_job = NULL;
-@end group
-@end smallexample
-
-Here are some utility functions that are used for operating on @code{job}
-objects.
-
-@smallexample
-@group
-/* @r{Find the active job with the indicated @var{pgid}.} */
-job *
-find_job (pid_t pgid)
-@{
- job *j;
-
- for (j = first_job; j; j = j->next)
- if (j->pgid == pgid)
- return j;
- return NULL;
-@}
-@end group
-
-@group
-/* @r{Return true if all processes in the job have stopped or completed.} */
-int
-job_is_stopped (job *j)
-@{
- process *p;
-
- for (p = j->first_process; p; p = p->next)
- if (!p->completed && !p->stopped)
- return 0;
- return 1;
-@}
-@end group
-
-@group
-/* @r{Return true if all processes in the job have completed.} */
-int
-job_is_completed (job *j)
-@{
- process *p;
-
- for (p = j->first_process; p; p = p->next)
- if (!p->completed)
- return 0;
- return 1;
-@}
-@end group
-@end smallexample
-
-
-@node Initializing the Shell, Launching Jobs, Data Structures, Implementing a Shell
-@subsection Initializing the Shell
-@cindex job control, enabling
-@cindex subshell
-
-When a shell program that normally performs job control is started, it
-has to be careful in case it has been invoked from another shell that is
-already doing its own job control.
-
-A subshell that runs interactively has to ensure that it has been placed
-in the foreground by its parent shell before it can enable job control
-itself. It does this by getting its initial process group ID with the
-@code{getpgrp} function, and comparing it to the process group ID of the
-current foreground job associated with its controlling terminal (which
-can be retrieved using the @code{tcgetpgrp} function).
-
-If the subshell is not running as a foreground job, it must stop itself
-by sending a @code{SIGTTIN} signal to its own process group. It may not
-arbitrarily put itself into the foreground; it must wait for the user to
-tell the parent shell to do this. If the subshell is continued again,
-it should repeat the check and stop itself again if it is still not in
-the foreground.
-
-@cindex job control, enabling
-Once the subshell has been placed into the foreground by its parent
-shell, it can enable its own job control. It does this by calling
-@code{setpgid} to put itself into its own process group, and then
-calling @code{tcsetpgrp} to place this process group into the
-foreground.
-
-When a shell enables job control, it should set itself to ignore all the
-job control stop signals so that it doesn't accidentally stop itself.
-You can do this by setting the action for all the stop signals to
-@code{SIG_IGN}.
-
-A subshell that runs non-interactively cannot and should not support job
-control. It must leave all processes it creates in the same process
-group as the shell itself; this allows the non-interactive shell and its
-child processes to be treated as a single job by the parent shell. This
-is easy to do---just don't use any of the job control primitives---but
-you must remember to make the shell do it.
-
-
-Here is the initialization code for the sample shell that shows how to
-do all of this.
-
-@smallexample
-/* @r{Keep track of attributes of the shell.} */
-
-#include <sys/types.h>
-#include <termios.h>
-#include <unistd.h>
-
-pid_t shell_pgid;
-struct termios shell_tmodes;
-int shell_terminal;
-int shell_is_interactive;
-
-
-/* @r{Make sure the shell is running interactively as the foreground job}
- @r{before proceeding.} */
-
-void
-init_shell ()
-@{
-
- /* @r{See if we are running interactively.} */
- shell_terminal = STDIN_FILENO;
- shell_is_interactive = isatty (shell_terminal);
-
- if (shell_is_interactive)
- @{
- /* @r{Loop until we are in the foreground.} */
- while (tcgetpgrp (shell_terminal) != (shell_pgid = getpgrp ()))
- kill (- shell_pgid, SIGTTIN);
-
- /* @r{Ignore interactive and job-control signals.} */
- signal (SIGINT, SIG_IGN);
- signal (SIGQUIT, SIG_IGN);
- signal (SIGTSTP, SIG_IGN);
- signal (SIGTTIN, SIG_IGN);
- signal (SIGTTOU, SIG_IGN);
- signal (SIGCHLD, SIG_IGN);
-
- /* @r{Put ourselves in our own process group.} */
- shell_pgid = getpid ();
- if (setpgid (shell_pgid, shell_pgid) < 0)
- @{
- perror ("Couldn't put the shell in its own process group");
- exit (1);
- @}
-
- /* @r{Grab control of the terminal.} */
- tcsetpgrp (shell_terminal, shell_pgid);
-
- /* @r{Save default terminal attributes for shell.} */
- tcgetattr (shell_terminal, &shell_tmodes);
- @}
-@}
-@end smallexample
-
-
-@node Launching Jobs, Foreground and Background, Initializing the Shell, Implementing a Shell
-@subsection Launching Jobs
-@cindex launching jobs
-
-Once the shell has taken responsibility for performing job control on
-its controlling terminal, it can launch jobs in response to commands
-typed by the user.
-
-To create the processes in a process group, you use the same @code{fork}
-and @code{exec} functions described in @ref{Process Creation Concepts}.
-Since there are multiple child processes involved, though, things are a
-little more complicated and you must be careful to do things in the
-right order. Otherwise, nasty race conditions can result.
-
-You have two choices for how to structure the tree of parent-child
-relationships among the processes. You can either make all the
-processes in the process group be children of the shell process, or you
-can make one process in group be the ancestor of all the other processes
-in that group. The sample shell program presented in this chapter uses
-the first approach because it makes bookkeeping somewhat simpler.
-
-@cindex process group leader
-@cindex process group ID
-As each process is forked, it should put itself in the new process group
-by calling @code{setpgid}; see @ref{Process Group Functions}. The first
-process in the new group becomes its @dfn{process group leader}, and its
-process ID becomes the @dfn{process group ID} for the group.
-
-@cindex race conditions, relating to job control
-The shell should also call @code{setpgid} to put each of its child
-processes into the new process group. This is because there is a
-potential timing problem: each child process must be put in the process
-group before it begins executing a new program, and the shell depends on
-having all the child processes in the group before it continues
-executing. If both the child processes and the shell call
-@code{setpgid}, this ensures that the right things happen no matter which
-process gets to it first.
-
-If the job is being launched as a foreground job, the new process group
-also needs to be put into the foreground on the controlling terminal
-using @code{tcsetpgrp}. Again, this should be done by the shell as well
-as by each of its child processes, to avoid race conditions.
-
-The next thing each child process should do is to reset its signal
-actions.
-
-During initialization, the shell process set itself to ignore job
-control signals; see @ref{Initializing the Shell}. As a result, any child
-processes it creates also ignore these signals by inheritance. This is
-definitely undesirable, so each child process should explicitly set the
-actions for these signals back to @code{SIG_DFL} just after it is forked.
-
-Since shells follow this convention, applications can assume that they
-inherit the correct handling of these signals from the parent process.
-But every application has a responsibility not to mess up the handling
-of stop signals. Applications that disable the normal interpretation of
-the SUSP character should provide some other mechanism for the user to
-stop the job. When the user invokes this mechanism, the program should
-send a @code{SIGTSTP} signal to the process group of the process, not
-just to the process itself. @xref{Signaling Another Process}.
-
-Finally, each child process should call @code{exec} in the normal way.
-This is also the point at which redirection of the standard input and
-output channels should be handled. @xref{Duplicating Descriptors},
-for an explanation of how to do this.
-
-Here is the function from the sample shell program that is responsible
-for launching a program. The function is executed by each child process
-immediately after it has been forked by the shell, and never returns.
-
-@smallexample
-void
-launch_process (process *p, pid_t pgid,
- int infile, int outfile, int errfile,
- int foreground)
-@{
- pid_t pid;
-
- if (shell_is_interactive)
- @{
- /* @r{Put the process into the process group and give the process group}
- @r{the terminal, if appropriate.}
- @r{This has to be done both by the shell and in the individual}
- @r{child processes because of potential race conditions.} */
- pid = getpid ();
- if (pgid == 0) pgid = pid;
- setpgid (pid, pgid);
- if (foreground)
- tcsetpgrp (shell_terminal, pgid);
-
- /* @r{Set the handling for job control signals back to the default.} */
- signal (SIGINT, SIG_DFL);
- signal (SIGQUIT, SIG_DFL);
- signal (SIGTSTP, SIG_DFL);
- signal (SIGTTIN, SIG_DFL);
- signal (SIGTTOU, SIG_DFL);
- signal (SIGCHLD, SIG_DFL);
- @}
-
- /* @r{Set the standard input/output channels of the new process.} */
- if (infile != STDIN_FILENO)
- @{
- dup2 (infile, STDIN_FILENO);
- close (infile);
- @}
- if (outfile != STDOUT_FILENO)
- @{
- dup2 (outfile, STDOUT_FILENO);
- close (outfile);
- @}
- if (errfile != STDERR_FILENO)
- @{
- dup2 (errfile, STDERR_FILENO);
- close (errfile);
- @}
-
- /* @r{Exec the new process. Make sure we exit.} */
- execvp (p->argv[0], p->argv);
- perror ("execvp");
- exit (1);
-@}
-@end smallexample
-
-If the shell is not running interactively, this function does not do
-anything with process groups or signals. Remember that a shell not
-performing job control must keep all of its subprocesses in the same
-process group as the shell itself.
-
-Next, here is the function that actually launches a complete job.
-After creating the child processes, this function calls some other
-functions to put the newly created job into the foreground or background;
-these are discussed in @ref{Foreground and Background}.
-
-@smallexample
-void
-launch_job (job *j, int foreground)
-@{
- process *p;
- pid_t pid;
- int mypipe[2], infile, outfile;
-
- infile = j->stdin;
- for (p = j->first_process; p; p = p->next)
- @{
- /* @r{Set up pipes, if necessary.} */
- if (p->next)
- @{
- if (pipe (mypipe) < 0)
- @{
- perror ("pipe");
- exit (1);
- @}
- outfile = mypipe[1];
- @}
- else
- outfile = j->stdout;
-
- /* @r{Fork the child processes.} */
- pid = fork ();
- if (pid == 0)
- /* @r{This is the child process.} */
- launch_process (p, j->pgid, infile,
- outfile, j->stderr, foreground);
- else if (pid < 0)
- @{
- /* @r{The fork failed.} */
- perror ("fork");
- exit (1);
- @}
- else
- @{
- /* @r{This is the parent process.} */
- p->pid = pid;
- if (shell_is_interactive)
- @{
- if (!j->pgid)
- j->pgid = pid;
- setpgid (pid, j->pgid);
- @}
- @}
-
- /* @r{Clean up after pipes.} */
- if (infile != j->stdin)
- close (infile);
- if (outfile != j->stdout)
- close (outfile);
- infile = mypipe[0];
- @}
-
- format_job_info (j, "launched");
-
- if (!shell_is_interactive)
- wait_for_job (j);
- else if (foreground)
- put_job_in_foreground (j, 0);
- else
- put_job_in_background (j, 0);
-@}
-@end smallexample
-
-
-@node Foreground and Background, Stopped and Terminated Jobs, Launching Jobs, Implementing a Shell
-@subsection Foreground and Background
-
-Now let's consider what actions must be taken by the shell when it
-launches a job into the foreground, and how this differs from what
-must be done when a background job is launched.
-
-@cindex foreground job, launching
-When a foreground job is launched, the shell must first give it access
-to the controlling terminal by calling @code{tcsetpgrp}. Then, the
-shell should wait for processes in that process group to terminate or
-stop. This is discussed in more detail in @ref{Stopped and Terminated
-Jobs}.
-
-When all of the processes in the group have either completed or stopped,
-the shell should regain control of the terminal for its own process
-group by calling @code{tcsetpgrp} again. Since stop signals caused by
-I/O from a background process or a SUSP character typed by the user
-are sent to the process group, normally all the processes in the job
-stop together.
-
-The foreground job may have left the terminal in a strange state, so the
-shell should restore its own saved terminal modes before continuing. In
-case the job is merely stopped, the shell should first save the current
-terminal modes so that it can restore them later if the job is
-continued. The functions for dealing with terminal modes are
-@code{tcgetattr} and @code{tcsetattr}; these are described in
-@ref{Terminal Modes}.
-
-Here is the sample shell's function for doing all of this.
-
-@smallexample
-@group
-/* @r{Put job @var{j} in the foreground. If @var{cont} is nonzero,}
- @r{restore the saved terminal modes and send the process group a}
- @r{@code{SIGCONT} signal to wake it up before we block.} */
-
-void
-put_job_in_foreground (job *j, int cont)
-@{
- /* @r{Put the job into the foreground.} */
- tcsetpgrp (shell_terminal, j->pgid);
-@end group
-
-@group
- /* @r{Send the job a continue signal, if necessary.} */
- if (cont)
- @{
- tcsetattr (shell_terminal, TCSADRAIN, &j->tmodes);
- if (kill (- j->pgid, SIGCONT) < 0)
- perror ("kill (SIGCONT)");
- @}
-@end group
-
- /* @r{Wait for it to report.} */
- wait_for_job (j);
-
- /* @r{Put the shell back in the foreground.} */
- tcsetpgrp (shell_terminal, shell_pgid);
-
-@group
- /* @r{Restore the shell's terminal modes.} */
- tcgetattr (shell_terminal, &j->tmodes);
- tcsetattr (shell_terminal, TCSADRAIN, &shell_tmodes);
-@}
-@end group
-@end smallexample
-
-@cindex background job, launching
-If the process group is launched as a background job, the shell should
-remain in the foreground itself and continue to read commands from
-the terminal.
-
-In the sample shell, there is not much that needs to be done to put
-a job into the background. Here is the function it uses:
-
-@smallexample
-/* @r{Put a job in the background. If the cont argument is true, send}
- @r{the process group a @code{SIGCONT} signal to wake it up.} */
-
-void
-put_job_in_background (job *j, int cont)
-@{
- /* @r{Send the job a continue signal, if necessary.} */
- if (cont)
- if (kill (-j->pgid, SIGCONT) < 0)
- perror ("kill (SIGCONT)");
-@}
-@end smallexample
-
-
-@node Stopped and Terminated Jobs, Continuing Stopped Jobs, Foreground and Background, Implementing a Shell
-@subsection Stopped and Terminated Jobs
-
-@cindex stopped jobs, detecting
-@cindex terminated jobs, detecting
-When a foreground process is launched, the shell must block until all of
-the processes in that job have either terminated or stopped. It can do
-this by calling the @code{waitpid} function; see @ref{Process
-Completion}. Use the @code{WUNTRACED} option so that status is reported
-for processes that stop as well as processes that terminate.
-
-The shell must also check on the status of background jobs so that it
-can report terminated and stopped jobs to the user; this can be done by
-calling @code{waitpid} with the @code{WNOHANG} option. A good place to
-put a such a check for terminated and stopped jobs is just before
-prompting for a new command.
-
-@cindex @code{SIGCHLD}, handling of
-The shell can also receive asynchronous notification that there is
-status information available for a child process by establishing a
-handler for @code{SIGCHLD} signals. @xref{Signal Handling}.
-
-In the sample shell program, the @code{SIGCHLD} signal is normally
-ignored. This is to avoid reentrancy problems involving the global data
-structures the shell manipulates. But at specific times when the shell
-is not using these data structures---such as when it is waiting for
-input on the terminal---it makes sense to enable a handler for
-@code{SIGCHLD}. The same function that is used to do the synchronous
-status checks (@code{do_job_notification}, in this case) can also be
-called from within this handler.
-
-Here are the parts of the sample shell program that deal with checking
-the status of jobs and reporting the information to the user.
-
-@smallexample
-@group
-/* @r{Store the status of the process @var{pid} that was returned by waitpid.}
- @r{Return 0 if all went well, nonzero otherwise.} */
-
-int
-mark_process_status (pid_t pid, int status)
-@{
- job *j;
- process *p;
-@end group
-
-@group
- if (pid > 0)
- @{
- /* @r{Update the record for the process.} */
- for (j = first_job; j; j = j->next)
- for (p = j->first_process; p; p = p->next)
- if (p->pid == pid)
- @{
- p->status = status;
- if (WIFSTOPPED (status))
- p->stopped = 1;
- else
- @{
- p->completed = 1;
- if (WIFSIGNALED (status))
- fprintf (stderr, "%d: Terminated by signal %d.\n",
- (int) pid, WTERMSIG (p->status));
- @}
- return 0;
- @}
- fprintf (stderr, "No child process %d.\n", pid);
- return -1;
- @}
-@end group
-@group
- else if (pid == 0 || errno == ECHILD)
- /* @r{No processes ready to report.} */
- return -1;
- else @{
- /* @r{Other weird errors.} */
- perror ("waitpid");
- return -1;
- @}
-@}
-@end group
-
-@group
-/* @r{Check for processes that have status information available,}
- @r{without blocking.} */
-
-void
-update_status (void)
-@{
- int status;
- pid_t pid;
-
- do
- pid = waitpid (WAIT_ANY, &status, WUNTRACED|WNOHANG);
- while (!mark_process_status (pid, status));
-@}
-@end group
-
-@group
-/* @r{Check for processes that have status information available,}
- @r{blocking until all processes in the given job have reported.} */
-
-void
-wait_for_job (job *j)
-@{
- int status;
- pid_t pid;
-
- do
- pid = waitpid (WAIT_ANY, &status, WUNTRACED);
- while (!mark_process_status (pid, status)
- && !job_is_stopped (j)
- && !job_is_completed (j));
-@}
-@end group
-
-@group
-/* @r{Format information about job status for the user to look at.} */
-
-void
-format_job_info (job *j, const char *status)
-@{
- fprintf (stderr, "%ld (%s): %s\n", (long)j->pgid, status, j->command);
-@}
-@end group
-
-@group
-/* @r{Notify the user about stopped or terminated jobs.}
- @r{Delete terminated jobs from the active job list.} */
-
-void
-do_job_notification (void)
-@{
- job *j, *jlast, *jnext;
- process *p;
-
- /* @r{Update status information for child processes.} */
- update_status ();
-
- jlast = NULL;
- for (j = first_job; j; j = jnext)
- @{
- jnext = j->next;
-
- /* @r{If all processes have completed, tell the user the job has}
- @r{completed and delete it from the list of active jobs.} */
- if (job_is_completed (j)) @{
- format_job_info (j, "completed");
- if (jlast)
- jlast->next = jnext;
- else
- first_job = jnext;
- free_job (j);
- @}
-
- /* @r{Notify the user about stopped jobs,}
- @r{marking them so that we won't do this more than once.} */
- else if (job_is_stopped (j) && !j->notified) @{
- format_job_info (j, "stopped");
- j->notified = 1;
- jlast = j;
- @}
-
- /* @r{Don't say anything about jobs that are still running.} */
- else
- jlast = j;
- @}
-@}
-@end group
-@end smallexample
-
-@node Continuing Stopped Jobs, Missing Pieces, Stopped and Terminated Jobs, Implementing a Shell
-@subsection Continuing Stopped Jobs
-
-@cindex stopped jobs, continuing
-The shell can continue a stopped job by sending a @code{SIGCONT} signal
-to its process group. If the job is being continued in the foreground,
-the shell should first invoke @code{tcsetpgrp} to give the job access to
-the terminal, and restore the saved terminal settings. After continuing
-a job in the foreground, the shell should wait for the job to stop or
-complete, as if the job had just been launched in the foreground.
-
-The sample shell program handles both newly created and continued jobs
-with the same pair of functions, @w{@code{put_job_in_foreground}} and
-@w{@code{put_job_in_background}}. The definitions of these functions
-were given in @ref{Foreground and Background}. When continuing a
-stopped job, a nonzero value is passed as the @var{cont} argument to
-ensure that the @code{SIGCONT} signal is sent and the terminal modes
-reset, as appropriate.
-
-This leaves only a function for updating the shell's internal bookkeeping
-about the job being continued:
-
-@smallexample
-@group
-/* @r{Mark a stopped job J as being running again.} */
-
-void
-mark_job_as_running (job *j)
-@{
- Process *p;
-
- for (p = j->first_process; p; p = p->next)
- p->stopped = 0;
- j->notified = 0;
-@}
-@end group
-
-@group
-/* @r{Continue the job J.} */
-
-void
-continue_job (job *j, int foreground)
-@{
- mark_job_as_running (j);
- if (foreground)
- put_job_in_foreground (j, 1);
- else
- put_job_in_background (j, 1);
-@}
-@end group
-@end smallexample
-
-@node Missing Pieces, , Continuing Stopped Jobs, Implementing a Shell
-@subsection The Missing Pieces
-
-The code extracts for the sample shell included in this chapter are only
-a part of the entire shell program. In particular, nothing at all has
-been said about how @code{job} and @code{program} data structures are
-allocated and initialized.
-
-Most real shells provide a complex user interface that has support for
-a command language; variables; abbreviations, substitutions, and pattern
-matching on file names; and the like. All of this is far too complicated
-to explain here! Instead, we have concentrated on showing how to
-implement the core process creation and job control functions that can
-be called from such a shell.
-
-Here is a table summarizing the major entry points we have presented:
-
-@table @code
-@item void init_shell (void)
-Initialize the shell's internal state. @xref{Initializing the
-Shell}.
-
-@item void launch_job (job *@var{j}, int @var{foreground})
-Launch the job @var{j} as either a foreground or background job.
-@xref{Launching Jobs}.
-
-@item void do_job_notification (void)
-Check for and report any jobs that have terminated or stopped. Can be
-called synchronously or within a handler for @code{SIGCHLD} signals.
-@xref{Stopped and Terminated Jobs}.
-
-@item void continue_job (job *@var{j}, int @var{foreground})
-Continue the job @var{j}. @xref{Continuing Stopped Jobs}.
-@end table
-
-Of course, a real shell would also want to provide other functions for
-managing jobs. For example, it would be useful to have commands to list
-all active jobs or to send a signal (such as @code{SIGKILL}) to a job.
-
-
-@node Functions for Job Control, , Implementing a Shell, Job Control
-@section Functions for Job Control
-@cindex process group functions
-@cindex job control functions
-
-This section contains detailed descriptions of the functions relating
-to job control.
-
-@menu
-* Identifying the Terminal:: Determining the controlling terminal's name.
-* Process Group Functions:: Functions for manipulating process groups.
-* Terminal Access Functions:: Functions for controlling terminal access.
-@end menu
-
-
-@node Identifying the Terminal, Process Group Functions, , Functions for Job Control
-@subsection Identifying the Controlling Terminal
-@cindex controlling terminal, determining
-
-You can use the @code{ctermid} function to get a file name that you can
-use to open the controlling terminal. In @theglibc{}, it returns
-the same string all the time: @code{"/dev/tty"}. That is a special
-``magic'' file name that refers to the controlling terminal of the
-current process (if it has one). To find the name of the specific
-terminal device, use @code{ttyname}; @pxref{Is It a Terminal}.
-
-The function @code{ctermid} is declared in the header file
-@file{stdio.h}.
-@pindex stdio.h
-
-@comment stdio.h
-@comment POSIX.1
-@deftypefun {char *} ctermid (char *@var{string})
-@safety{@prelim{}@mtsafe{@mtsposix{/!string}}@assafe{}@acsafe{}}
-@c This function is a stub by default; the actual implementation, for
-@c posix systems, returns a pointer to a string literal if passed a NULL
-@c string. It's not clear we want to commit to being MT-Safe in the
-@c !string case, so maybe add mtasurace{:ctermid/!string} when we take
-@c prelim out, to make room for using a static buffer in the future.
-The @code{ctermid} function returns a string containing the file name of
-the controlling terminal for the current process. If @var{string} is
-not a null pointer, it should be an array that can hold at least
-@code{L_ctermid} characters; the string is returned in this array.
-Otherwise, a pointer to a string in a static area is returned, which
-might get overwritten on subsequent calls to this function.
-
-An empty string is returned if the file name cannot be determined for
-any reason. Even if a file name is returned, access to the file it
-represents is not guaranteed.
-@end deftypefun
-
-@comment stdio.h
-@comment POSIX.1
-@deftypevr Macro int L_ctermid
-The value of this macro is an integer constant expression that
-represents the size of a string large enough to hold the file name
-returned by @code{ctermid}.
-@end deftypevr
-
-See also the @code{isatty} and @code{ttyname} functions, in
-@ref{Is It a Terminal}.
-
-
-@node Process Group Functions, Terminal Access Functions, Identifying the Terminal, Functions for Job Control
-@subsection Process Group Functions
-
-Here are descriptions of the functions for manipulating process groups.
-Your program should include the header files @file{sys/types.h} and
-@file{unistd.h} to use these functions.
-@pindex unistd.h
-@pindex sys/types.h
-
-@comment unistd.h
-@comment POSIX.1
-@deftypefun pid_t setsid (void)
-@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
-@c This is usually a direct syscall, but if a syscall is not available,
-@c we use a stub, or Hurd- and BSD-specific implementations. The former
-@c uses a mutex and a hurd critical section, and the latter issues a few
-@c syscalls, so both seem safe, the locking on Hurd is safe because of
-@c the critical section.
-The @code{setsid} function creates a new session. The calling process
-becomes the session leader, and is put in a new process group whose
-process group ID is the same as the process ID of that process. There
-are initially no other processes in the new process group, and no other
-process groups in the new session.
-
-This function also makes the calling process have no controlling terminal.
-
-The @code{setsid} function returns the new process group ID of the
-calling process if successful. A return value of @code{-1} indicates an
-error. The following @code{errno} error conditions are defined for this
-function:
-
-@table @code
-@item EPERM
-The calling process is already a process group leader, or there is
-already another process group around that has the same process group ID.
-@end table
-@end deftypefun
-
-@comment unistd.h
-@comment SVID
-@deftypefun pid_t getsid (pid_t @var{pid})
-@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
-@c Stub or direct syscall, except on hurd, where it is equally safe.
-
-The @code{getsid} function returns the process group ID of the session
-leader of the specified process. If a @var{pid} is @code{0}, the
-process group ID of the session leader of the current process is
-returned.
-
-In case of error @code{-1} is returned and @code{errno} is set. The
-following @code{errno} error conditions are defined for this function:
-
-@table @code
-@item ESRCH
-There is no process with the given process ID @var{pid}.
-@item EPERM
-The calling process and the process specified by @var{pid} are in
-different sessions, and the implementation doesn't allow to access the
-process group ID of the session leader of the process with ID @var{pid}
-from the calling process.
-@end table
-@end deftypefun
-
-@comment unistd.h
-@comment POSIX.1
-@deftypefun pid_t getpgrp (void)
-@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
-The @code{getpgrp} function returns the process group ID of
-the calling process.
-@end deftypefun
-
-@comment unistd.h
-@comment POSIX.1
-@deftypefun int getpgid (pid_t @var{pid})
-@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
-@c Stub or direct syscall, except on hurd, where it is equally safe.
-
-The @code{getpgid} function
-returns the process group ID of the process @var{pid}. You can supply a
-value of @code{0} for the @var{pid} argument to get information about
-the calling process.
-
-In case of error @code{-1} is returned and @code{errno} is set. The
-following @code{errno} error conditions are defined for this function:
-
-@table @code
-@item ESRCH
-There is no process with the given process ID @var{pid}.
-The calling process and the process specified by @var{pid} are in
-different sessions, and the implementation doesn't allow to access the
-process group ID of the process with ID @var{pid} from the calling
-process.
-@end table
-@end deftypefun
-
-@comment unistd.h
-@comment POSIX.1
-@deftypefun int setpgid (pid_t @var{pid}, pid_t @var{pgid})
-@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
-@c Stub or direct syscall, except on hurd, where it is equally safe.
-The @code{setpgid} function puts the process @var{pid} into the process
-group @var{pgid}. As a special case, either @var{pid} or @var{pgid} can
-be zero to indicate the process ID of the calling process.
-
-This function fails on a system that does not support job control.
-@xref{Job Control is Optional}, for more information.
-
-If the operation is successful, @code{setpgid} returns zero. Otherwise
-it returns @code{-1}. The following @code{errno} error conditions are
-defined for this function:
-
-@table @code
-@item EACCES
-The child process named by @var{pid} has executed an @code{exec}
-function since it was forked.
-
-@item EINVAL
-The value of the @var{pgid} is not valid.
-
-@item ENOSYS
-The system doesn't support job control.
-
-@item EPERM
-The process indicated by the @var{pid} argument is a session leader,
-or is not in the same session as the calling process, or the value of
-the @var{pgid} argument doesn't match a process group ID in the same
-session as the calling process.
-
-@item ESRCH
-The process indicated by the @var{pid} argument is not the calling
-process or a child of the calling process.
-@end table
-@end deftypefun
-
-@comment unistd.h
-@comment BSD
-@deftypefun int setpgrp (pid_t @var{pid}, pid_t @var{pgid})
-@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
-@c Direct syscall or setpgid wrapper.
-This is the BSD Unix name for @code{setpgid}. Both functions do exactly
-the same thing.
-@end deftypefun
-
-
-@node Terminal Access Functions, , Process Group Functions, Functions for Job Control
-@subsection Functions for Controlling Terminal Access
-
-These are the functions for reading or setting the foreground
-process group of a terminal. You should include the header files
-@file{sys/types.h} and @file{unistd.h} in your application to use
-these functions.
-@pindex unistd.h
-@pindex sys/types.h
-
-Although these functions take a file descriptor argument to specify
-the terminal device, the foreground job is associated with the terminal
-file itself and not a particular open file descriptor.
-
-@comment unistd.h
-@comment POSIX.1
-@deftypefun pid_t tcgetpgrp (int @var{filedes})
-@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
-@c Stub, or ioctl on BSD and GNU/Linux.
-This function returns the process group ID of the foreground process
-group associated with the terminal open on descriptor @var{filedes}.
-
-If there is no foreground process group, the return value is a number
-greater than @code{1} that does not match the process group ID of any
-existing process group. This can happen if all of the processes in the
-job that was formerly the foreground job have terminated, and no other
-job has yet been moved into the foreground.
-
-In case of an error, a value of @code{-1} is returned. The
-following @code{errno} error conditions are defined for this function:
-
-@table @code
-@item EBADF
-The @var{filedes} argument is not a valid file descriptor.
-
-@item ENOSYS
-The system doesn't support job control.
-
-@item ENOTTY
-The terminal file associated with the @var{filedes} argument isn't the
-controlling terminal of the calling process.
-@end table
-@end deftypefun
-
-@comment unistd.h
-@comment POSIX.1
-@deftypefun int tcsetpgrp (int @var{filedes}, pid_t @var{pgid})
-@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
-@c Stub, or ioctl on BSD and GNU/Linux.
-This function is used to set a terminal's foreground process group ID.
-The argument @var{filedes} is a descriptor which specifies the terminal;
-@var{pgid} specifies the process group. The calling process must be a
-member of the same session as @var{pgid} and must have the same
-controlling terminal.
-
-For terminal access purposes, this function is treated as output. If it
-is called from a background process on its controlling terminal,
-normally all processes in the process group are sent a @code{SIGTTOU}
-signal. The exception is if the calling process itself is ignoring or
-blocking @code{SIGTTOU} signals, in which case the operation is
-performed and no signal is sent.
-
-If successful, @code{tcsetpgrp} returns @code{0}. A return value of
-@code{-1} indicates an error. The following @code{errno} error
-conditions are defined for this function:
-
-@table @code
-@item EBADF
-The @var{filedes} argument is not a valid file descriptor.
-
-@item EINVAL
-The @var{pgid} argument is not valid.
-
-@item ENOSYS
-The system doesn't support job control.
-
-@item ENOTTY
-The @var{filedes} isn't the controlling terminal of the calling process.
-
-@item EPERM
-The @var{pgid} isn't a process group in the same session as the calling
-process.
-@end table
-@end deftypefun
-
-@comment termios.h
-@comment Unix98
-@deftypefun pid_t tcgetsid (int @var{fildes})
-@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
-@c Ioctl call, if available, or tcgetpgrp followed by getsid.
-This function is used to obtain the process group ID of the session
-for which the terminal specified by @var{fildes} is the controlling terminal.
-If the call is successful the group ID is returned. Otherwise the
-return value is @code{(pid_t) -1} and the global variable @var{errno}
-is set to the following value:
-@table @code
-@item EBADF
-The @var{filedes} argument is not a valid file descriptor.
-
-@item ENOTTY
-The calling process does not have a controlling terminal, or the file
-is not the controlling terminal.
-@end table
-@end deftypefun