11.5 Process Groups, Sessions and Controlling Terminals

Team-FLY

The previous section implemented signal handling for ush with simple commands. Signal handling for pipelines and background processes requires additional machinery. Pipelines need process groups, and background processes need sessions and controlling terminals.

11.5.1 Process Groups

A process group is a collection of processes established for purposes such as signal delivery. Each process has a process group ID that identifies the process group to which it belongs. Both the kill command and the kill function treat a negative process ID value as a process group ID and send a signal to each member of the corresponding process group.

Example 11.19

The following command sends SIGINT to the process group 3245 .

 kill -INT -3245 

In contrast, the following command sends SIGINT just to the process 3245 .

 kill -INT 3245 

The process group leader is a process whose process ID has the same value as the process group ID. A process group persists as long as any process is in the group. Thus, a process group may not have a leader if the leader dies or joins another group.

A process can change its process group with setpgid . The setpgid function sets the process group ID of process pid to have process group ID pgid . It uses the process ID of the calling process if pid is 0. If pgid is 0, the process specified by pid becomes a group leader.

  SYNOPSIS  #include <unistd.h>   int setpgid(pid_t pid, pid_t pgid);  POSIX  

The setpgid function returns 0 if successful. If unsuccessful , setpgid returns “1 and sets errno . The following table lists the mandatory errors for setpgid .

errno

cause

EACCES

pid corresponds to a child that has already called exec

EINVAL

pgid is negative or has an unsupported value

EPERM

pid is the process ID of a session leader, or pid is the process ID of a child process not in the caller's session, or pgid does not match pid and there is no process with a process ID matching pgid in the caller's session

ESRCH

pid does not match the caller's process ID or that of any of its children

When a child is created with fork , it gets a new process ID but it inherits the process group ID of its parent. The parent can use setpgid to change the group ID of a child as long as the child has not yet called exec . A child process can also give itself a new process group ID by setting its process group ID equal to its process ID.

Example 11.20

The following code segment forks a child that calls executecmd . The child places itself in a new process group.

 pid = fork(); if ((pid == 0) && (setpgid(getpid(), getpid()) != -1))) {    executecmd(cmd);    return 1; } 

Either or both of the calls to getpid could be replaced with 0.

Exercise 11.21

What can go wrong with the following alternative to the code of Example 11.20?

 pid = fork(); if ((pid > 0) && (setpgid(pid, pid) == -1)) {    perror("Failed to set child's process group"); else if (pid == 0) {     executecmd(cmd);     return 1; } 

Answer:

The alternative code has a race condition. If the child performs execvp in executecmd before the parent calls setpgid , the code fails.

The getpgrp function returns the process group ID of the caller.

  SYNOPSIS  #include <unistd.h>   pid_t getpgrp(void);  POSIX  

No errors are defined for getpgrp .

The POSIX:XSI Extension also defines a setpgrp function that is similar to setpgid . However, setpgrp allows greater flexibility than is required for job control and may present a security risk.

11.5.2 Sessions

To make signal delivery transparent, POSIX uses sessions and controlling terminals. A session is a collection of process groups established for job control purposes. The creator of a session is called the session leader . We identify sessions by the process IDs of their leaders . Every process belongs to a session, which it inherits from its parent.

Each session may have a controlling terminal associated with it. A shell uses the controlling terminal of its session to interact with the user . A particular controlling terminal is associated with exactly one session. A session may have several process groups, but at any given time only one of these process groups can receive input from and send output to the controlling terminal. The designated process group is called the foreground process group or the foreground job . The other process groups in the session are called background process groups or background jobs . The main purpose of job control is to change which process group is in the foreground. The background process groups are not affected by keyboard input from the controlling terminal of the session.

Use the ctermid function to obtain the name of the controlling terminal. The ctermid function returns a pointer to a string that corresponds to the pathname of the controlling terminal for the current process. This string may be in a statically generated area if s is a NULL pointer. If s is not NULL , it should point to a character array of at least L_ctermid bytes. The ctermid function copies a string representing the controlling terminal into that array.

  SYNOPSIS  #include <stdio.h>   char *ctermid(char *s);  POSIX:CX  

The ctermid function returns an empty string if it is unsuccessful.

Exercise 11.22

What happens if you enter Ctrl-C while executing the following command string in ush4 ?

 ls -l  sort -n +4  more 

Answer:

The SIGINT signal is delivered to the three child processes executing the three filters as well as to the parent shell process because all of these processes are in the foreground process group. The parent catches SIGINT with jumphd ; the three children take the default action and terminate.

Section 3.6 introduced background processes. The & character at the end of the command line designates a command or pipeline to be run as a background process group in most shells .

Exercise 11.23

What happens if you enter Ctrl-C while the following command is executing in the C shell?

 ls -l  sort -n +4  more & 

Answer:

None of the processes in the pipeline receive the SIGINT signal, since the pipeline is in the background and has no connection to the controlling terminal.

A process can create a new session with itself as the leader by calling setsid . The setsid function also creates a new process group with the process group ID equal to the process ID of the caller. The calling process is the only one in the new process group and the new session. The session has no controlling terminal.

  SYNOPSIS  #include <unistd.h>   pid_t setsid(void);  POSIX  

If successful, setsid returns the new value of the process group ID. If unsuccessful, setsid returns (pid_t) “1 and sets errno . The setsid function sets errno to EPERM if the caller is already a process group leader.

A process can discover session IDs by calling getsid . The getsid function takes a process group ID parameter, pid , and returns the process group ID of the process that is the session leader of the process specified by pid . If 0, pid specifies the calling process.

  SYNOPSIS  #include <unistd.h>   pid_t getsid(pid_t pid);  POSIX:XSI  

If successful, getsid returns a process group ID. If unsuccessful, getsid returns “1 and sets errno . The following table lists the mandatory errors for getsid .

errno

cause

EPERM

process specified by pid is not in the same session as the calling process and the implementation does not allow access to the process group ID of that session leader

ESRCH

no process corresponds to pid

Figure 11.1 shows a shell with several process groups. Each solid rectangle represents a process with its process ID, process group ID and the session ID. All of the processes have session ID 1357, the process ID and session ID of the shell. The process group ID is the same as the process ID of one of its members , the process group leader.

Figure 11.1. Five process groups for session 1357.

graphics/11fig01.gif

Example 11.24

The following sequence of commands might give rise to the process group structure of Figure 11.1.

 ls -l  sort -n +4  grep testfile > testfile.out & grep process  sort > process.out & du . > du.out & cat /etc/passwd  grep users  sort  head > users.out & 
Exercise 11.25

Write a short program called showid that takes one command-line argument. The showid program outputs to standard error a single line with its command-line argument, its process ID, parent process ID, process group ID and session ID. After the display, showid starts an infinite loop that does nothing. Execute the following commands to verify how your login shell handles process groups and sessions for pipelines.

 showid 1  showid 2  showid 3 

Which process in the pipeline is the process group leader? Is the shell in the same process group as the pipeline? Which processes in the pipeline are children of the shell and which are grandchildren? How does this change if the pipeline is started in the background?

Answer:

The results vary depending on the shell that is used. Some shells make all the processes children of the shell. Others have only the first or last process in the pipeline as a child of the shell and the rest are grandchildren. Either the first or the last process may be the process group leader. If a shell does not support job control, it is possible for the shell to be the process group leader of the pipeline unless the pipeline is started in the background.

Summary:

  • The shell is a session leader.

  • All processes created by the shell are in this session.

  • All processes created on a single command line are in the same process group.

  • If the shell supports job control or the command line is started in the background, a new process group is formed for these processes.

  • One of the process groups of the shell is the foreground process group and can interact with the controlling terminal.

Team-FLY


Unix Systems Programming
UNIX Systems Programming: Communication, Concurrency and Threads
ISBN: 0130424110
EAN: 2147483647
Year: 2003
Pages: 274

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net