Process Groups, Sessions, and Controlling Terminals

    In addition to having a process ID, each process also belongs to a process group. A process group is a collection of processes, usually joined together in the same job, where each process receives various signals from the same terminal. Each process group has a process group ID and can be stored in the pid_t data type.
    The function getpgrp returns the process group ID of the calling process, and the function getpgid returns the process group ID of a specific process.
#include <unistd.h>
pid_t getpgrp(void); /* Return value: process group ID of the calling process */
pid_t getpgid(pid_t pid); /* Return value: If successful, return the process group ID; otherwise, return -1 */

    When pid equals 0, getpgid(0) is equivalent to getpgrp().
    Each process group has a leader process whose process group ID is equal to its process ID. A group leader process can create a process group, create the processes in the group, and then terminate. As long as there is a process in a process group, the process group exists, regardless of whether its leader process is terminated. The time zone from the creation of a process group to the departure of the last process in it is called the lifetime of the process group. The last process in each process group can be terminated or transferred to another process group.
    A process can call setpgid to join an existing process group or to create a new process group (the setsid function can also create a new process group, see below).
#include <unistd.h>
int setpgid(pid_t pid, pid_t pgid); /* Return value: if successful, return 0; otherwise, return -1 */

    The setpgid function sets the process group ID of the pid process to pgid. If these two parameters are equal, the process specified by pid becomes the process group leader. If pid is 0, the caller's process ID is used. Whereas, if pgid is 0, the process ID specified by pid is used as the process group ID.
    A process can only set the process group ID for itself or its child process. After its child process calls exec, it will not change the process group ID of the child process. In most job control, this function is called after a fork to cause the parent process to set the process group ID of its child process, and also to cause the child process to set its own process group ID. Although one of these is redundant, it is guaranteed that this does happen before the parent and child processes think the child has entered the process group. Otherwise, since the order in which the parent and child processes run is uncertain, a race condition will arise because the group membership of the child process depends on which process executes first.

    A collection of one or more process groups is called a session. A session in the figure below has 3 process groups.

    Usually several processes are grouped together by the shell's pipes. For example, the arrangement in the figure above might be formed by a shell command of the form:
        proc1 | proc2 & proc3 | proc4 | proc5 The
    process calls the setsid function to establish a new session.
#include <unistd.h>
pid_t setsid(void); /* Return value: If successful, return the process group ID; otherwise, return -1 */

    If the calling process is not the leader of a process group, this function creates a new session. Specifically, the following three things will happen:
    (1) The process becomes the session leader of the new session (session leader, that is, the process that created the session).
    (2) The process becomes the leader process of a new process group.
    (3) The process does not have a controlling terminal (see below), and even if it had before, the connection would be severed.
    If the calling process is already a group leader process, this function returns an error. To avoid this, fork is usually called first, which then causes the parent process to terminate while the child process continues. Because the child process inherits the process group ID of the parent process, and its process ID is newly allocated, the two cannot be equal, which ensures that the child process is not the leader of a process group.
    The getsid function returns the process group ID of the session leader.
#include <unistd.h>
pid_t getsid(pid_t pid);
                /* Return value: If successful, return the process group ID of the session head process; otherwise, return -1 */

    If pid is 0, getsid returns the process group ID of the calling process's session leader. For security reasons, some implementations impose this restriction: if the pid does not belong to the caller's session, the calling process cannot get the process group ID of the session leader.

    Sessions and process groups have some other features.
    * A session can have a controlling terminal, usually a terminal device (in the case of a terminal login) or a pseudo-terminal device (in the case of a network login).
    * The session leader process that establishes the connection with the controlling terminal is called the controlling process.
    * Several process groups in a session can be divided into a foreground process group and multiple background process groups.
    * If a session has a controlling terminal, it has a foreground process group, other process groups are background process groups.
    * Whenever the terminal interrupt key (usually Delete or Ctrl+C) or the exit key (usually Ctrl+\) is entered, the interrupt signal or exit signal will be sent to all processes in the foreground process group.
    * If the terminal interface detects that the modem or network has been disconnected, it sends a hangup signal to the controlling process (session leader).
    These characteristics can be represented by the diagram below.

    Normally a controlling terminal is automatically established when you log in. POSIX.1 leaves the choice of how the controlling terminal is allocated to the implementation. For example, when a session leader opens the first terminal device not already associated with a session, System V-derived systems assign this as the controlling terminal as long as the O_NOCTTY flag is not specified when calling open; When a process calls ioctl with TIOCSCTTY as the request parameter (the third parameter is a null pointer), BSD-based systems (but Mac OS X 10.6.8 uses the System V approach) assigns a controlling terminal to the session. For this call to succeed, the session must not already have a controlling terminal (usually an ioctl call follows a calls to setsid, which guarantees that the process is a session leader without a controlling terminal).
    Sometimes programs interact with the controlling terminal regardless of whether standard input or standard output is redirected. The way to ensure that the program can talk to the controlling terminal is to open the file /dev/tty, this special file is synonymous with the controlling terminal in the kernel. A typical example is the getpass function for reading passwords, which is called by the program crypt and can be used in pipes. For example:
        crypt < salaris | lpr
    Decrypts the file salaries and pipes the output to the print buffer service.
    The following functions can be used to inform the kernel which process group is the foreground process group, so that the device driver knows where to send terminal input and terminal-generated signals.
#include <unistd.h>
pid_t tcgetpgrp(int fd); /* Return value: if successful, return foreground process group ID; otherwise, return -1 */
int tcsetpgrp(int fd, pid_t pgrpid); /* Return value: if successful, return 0; otherwise, return -1 */

#include <termios.h>
pid_t tcgetsid(int fd);
                    /* Return value: If successful, return the process group ID of the session head process; otherwise, return -1 */

    The function tcgetpgrp returns the foreground process group ID associated with the terminal opened on fd.
    If the process has a controlling terminal, tcsetpgrp can be called to set the foreground process group ID to a process group ID pgrpid within the same session, and fd must refer to the session's controlling terminal. Both tcgetpgrp and tcsetpgrp are normally invoked by the job control shell.
    If the file descriptor of the controlling terminal is given, the process group ID of the session leader can be obtained with tcgetsid.

    The following diagram shows the various related data structures used in FreeBSD.

    Each session is allocated a session structure (eg each time setsid is called), where:
    * s_count is the number of process groups in the session. When it is decremented to 0, the structure can be freed.
    * s_leader is a pointer to the session leader's proc structure.
    * s_ttyvp is a pointer to the controlling terminal vnode structure.
    * s_ttyp is a pointer to the controlling terminal tty structure.
    * s_sid is the session ID (not part of the Single UNIX Specification).
    When calling setsid, the kernel allocates a new session structure. s_count is set to 1, s_leader is set to a pointer to the calling process's proc structure, and s_sid is set to the process ID. Since the new session has no controlling terminal, s_ttyvp and s_ttyp are set to null pointers.
    For the tty structure, each terminal device and pseudo-terminal device is allocated a structure in the kernel where:
    * t_session points to the session structure that uses this terminal as the controlling terminal. The terminal uses this pointer to send a suspend signal to the session leader when it loses the carrier signal.
    * t_pgrp points to the pgrp structure of the foreground process group. Terminal drivers use this field to send signals to the foreground process group.
    * t_termios is a structure that contains all special characters (such as interrupt Ctrl+C) and information related to this terminal (such as baud rate, echo on or off, etc.).
    * t_winsize is a winsize type structure containing the current size of the terminal window. When the terminal window size changes, the signal SIGWINCH will be sent to the foreground process group.
    The pgrp structure contains information for a specific process group, where:
    * pg_id is the process group ID.
    * pg_session points to the session structure of the session to which this process group belongs.
    * pg_members is a pointer to the member table of this process group proc structure.
    The proc structure contains all the information for a process, where:
    * p_pid contains the process ID.
    * p_pptr is a pointer to the parent process proc structure.
    * p_pgrp is a pointer to the pgrp structure of the process group to which this process belongs.
    * The p_pglist structure contains two pointers to the previous and next process in the process group.
    Finally there is a vnode structure, which is allocated when the controlling terminal device is opened. All process access to /dev/tty goes through this structure.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326135968&siteId=291194637