Tuesday, December 22, 2009

11.7 Job Control



[ Team LiB ]






11.7 Job Control


A shell is said to have job control if it allows a user to move the foreground process group into the background and to move a process group from the background to the foreground. Job control involves changing the foreground process group of a controlling terminal.


The tcgetpgrp function returns the process group ID of the foreground process group of a particular controlling terminal. To obtain an open file descriptor for the controlling terminal, open the pathname obtained from the ctermid function described in Section 11.5.



SYNOPSIS

#include <unistd.h>

pid_t tcgetpgrp(int fildes);
POSIX

If successful, the tcgetpgrp function returns the process group ID of the foreground process group associated with the terminal. If the terminal has no foreground process group, tcgetpgrp returns a value greater than 1 that doesn't match any existing process group ID. If unsuccessful, the tcgetpgrp function returns �1 and sets errno. The following table lists the mandatory errors for tcgetpgrp.


errno

cause

EBADF

fildes is invalid

ENOTTY

caller does not have a controlling terminal, or fildes does not correspond to a controlling terminal


The tcsetpgrp function sets the foreground process group of the controlling terminal associated with fildes to pgid_id. If a background process calls tcsetpgrp on a fildes associated with its controlling terminal, its process group receives a SIGTTOU signal, provided that this process is not blocking or ignoring SIGTTOU.



SYNOPSIS

#include <unistd.h>

int tcsetpgrp(int fildes, pid_t pgid_id);
POSIX

If successful, tcsetpgrp returns 0. If unsuccessful, tcsetpgrp returns �1 and sets errno. The following table lists the mandatory errors for tcsetpgrp.


errno

cause

EBADF

fildes is invalid

EINVAL

implementation does not support the value of pgid_id

ENOTTY

caller does not have a controlling terminal, or fildes does not correspond to a controlling terminal, or controlling terminal is no longer associated with the session of the caller

EPERM

value of pgid_id is supported but does not match the process group ID of any process in the session of the caller


In addition to running processes in the foreground and background, job control allows users to selectively stop processes and resume their execution later. For example, you may want to run a long job in the background but periodically halt it to examine its status or provide input. The C shell and the KornShell allow job control, as do most shells under Linux, but the Bourne shell does not. This section describes job control in the C shell. The Linux shells and the KornShell are almost identical with respect to job control.


A job consists of the processes needed to run a single command line. When a shell starts a job in the background, it assigns a job number and displays the job number and process IDs of the processes in the job. If a pipeline is started in the background, all processes in the pipeline have the same job number. The job number is typically a small integer. If there are no other jobs in the background, the shell assigns the command job number 1. Generally, shells assign a background job a number that is one greater than the current largest background job number.


The jobs command displays the jobs running under a shell.



Example 11.31

The following commands illustrate job control for the C shell. The shell displays the prompt ospmt%. The commands appear after this prompt. The shell produces the other messages shown.



ospmt% du . | sort -n > duout &
[1] 23145 23146
ospmt% grep mybook *.tex > mybook.out &
[2] 23147
ospmt% rusers | grep myboss > myboss.out &
[3] 23148 23149
ospmt% jobs
[1] + Running du . | sort -n > duout
[2] - Running grep mybook *.tex > mybook.out
[3] Running rusers | grep myboss > myboss.out


The jobs command shows three running background jobs. The job number is at the start of the line in square brackets. If the second job finishes first, the shell displays the following line when the user presses the return.



[2] Done grep mybook *.tex > mybook.out

If at that time the user executes another jobs command, the following output appears.



[1] + Running du . | sort -n > duout
[3] - Running rusers | grep myboss > myboss.out

You may refer to job n by %n in various shell commands. Example 11.31 shows a + after the job number of job [1], meaning that it is the current job and is the default for the fg and bg commands. The - represents the previous job.



Example 11.32

The following command kills job 2 without referring to process IDs.



kill -KILL %2


A background job can be either running or stopped. To stop a running job, use the stop command. The stopped job becomes the current job and is suspended.



Example 11.33

The following command stops job two.



stop %2


To start a stopped job running in the background, use the bg command. In this case, bg or bg % or bg %2 all work, since job 2 is the current job.


Use the fg command to move a background job (either running or stopped) into the foreground, and the SIGSTOP character (typically Ctrl-Z) to move the foreground job into the background in the stopped state. The combination Ctrl-Z and bg makes the foreground job a running background job.


Since fg, bg and jobs are built into the shell, these commands may not have their own man pages. To get information on these commands in the C shell, execute man csh.



Exercise 11.34

Experiment with job control (assuming that it is available). Move processes in and out of the foreground.



A shell that supports job control must keep track of all foreground and background process groups in its session. When the terminal generates a SIGSTOP interrupt (usually in response to Ctrl-Z), the foreground process group is placed in the stopped state. How should the shell get back in control? Fortunately, waitpid blocks the parent shell until the state of one of its children changes. Thus, an appropriate call to waitpid by the parent shell allows the shell to regain control after the foreground process group is suspended. The shell can start a suspended process group by sending it the SIGCONT signal. If the shell wants to restart that group in the foreground, it must use tcsetpgrp to tell the controlling terminal what the foreground process group is. Since a given process or process group can run in the foreground or the background at different times during its execution, each child command must start a new process group regardless of whether it is started in the background or foreground.


One job control problem not yet addressed in this discussion is how a process obtains input from standard input. If the process is in the foreground, there is no problem. If there is no job control and the process is started in the background, its standard input is redirected to /dev/null to prevent it from grabbing characters from the foreground process. This simple redirection does not work with job control. Once a process redirects standard input, it cannot use standard input to read from the original controlling terminal when brought to the foreground. The solution specified by POSIX is for the kernel to generate a SIGTTIN signal when a background process attempts to read from the controlling terminal. The default action for SIGTTIN stops the job. The shell detects a change in the status of the child when it executes waitpid and then displays a message. The user can then choose to move the process to the foreground so it can receive input.


Background jobs can write to standard error. If a background process attempts to write to standard output while standard output is still directed to the controlling terminal, the terminal device driver generates a SIGTTOU for the process. In this case, the c_lflag member of the struct termios structure for the terminal has the TOSTOP flag set. A user then has the option of moving the job to the foreground so that it can send output to the controlling terminal. If the process has redirected standard input and standard output, it does I/O from the redirected sources.



Exercise 11.35

Write a simple program that writes to standard output. Start the program in the background under your regular shell and see if it can write to standard output without generating a SIGTTOU signal.







    [ Team LiB ]



    No comments: