Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!cmcl2!husc6!ut-sally!std-unix From: std-u...@ut-sally.UUCP (Moderator, John Quarterman) Newsgroups: mod.std.unix Subject: mod.std.unix P1003 job control proposal Message-ID: <5993@ut-sally.UUCP> Date: Sat, 11-Oct-86 21:38:15 EDT Article-I.D.: ut-sally.5993 Posted: Sat Oct 11 21:38:15 1986 Date-Received: Sat, 11-Oct-86 23:59:38 EDT Organization: IEEE P1003 Portable Operating System for Computer Environments Committee Lines: 517 Approved: j...@sally.utexas.edu From: im4u!caip!hplabs!hpda!hpisoa1!da...@sally.utexas.edu (Dave Lennert) Date: Thu, 9 Oct 86 14:06:30 pdt Attached is the P1003 job control proposal. The first file contains the text as accepted at the September P1003 meeting in Palo Alto. Note that this text sometimes replaces, and sometimes augments, existing POSIX text. The second file contains the problems noticed since then and the proposed resolutions. Dave Lennert ucbvax!hpda!davel [UUCP] Hewlett-Packard - 47UX ihnp4!hplabs!hpda!davel [UUCP] 19447 Pruneridge Ave. hpda!da...@ucb-vax.ARPA [ARPA] Cupertino, CA 95014 (408) 447-6325 [AT&T] # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by davel at hpisoa1 on Thu Oct 9 13:23:24 1986 # # This archive contains: # acceptedtext problems # echo x - acceptedtext cat >acceptedtext <<'@EOF' IEEE SYSTEM FOR COMPUTER ENVIRONMENTS Std 1003.1 2.3 General Terms Replace or add the following definitions: job control option Job control allows users to selectively stop (suspend) the execution of processes and continue (resume) their execution at a later point. The user typically employs this facility via the interactive interface jointly supplied by the terminal I/O driver and a command interpreter. Conforming implementations may optionally support job control facilities (see Symbolic Constants 2.10). Portions of the standard operating system interface which are required only on implementations which support the job control option are so labelled. process group leader A process group leader is a process whose process ID is the same as its process group ID. Any process that is not a process group leader may detach itself from its process group and becomes the process group leader of a new process group by calling either the setpgrp() or setpgrp2() function, which can cause a process to become either a session process group leader or a job process group leader, respectively. Job process group leaders can exist on implementations which support the job control option. saved process group ID An active process has a saved process group ID that is set to the saved process group ID of the parent process at the time of creation of the process (via the fork() function). It is reset to the process group ID of the process when the process successfully calls one of the exec functions. 2.10 Symbolic Constants Add the following new constant after the IEEE1003 constant defintion: IEEE1003job If this symbol is defined then the implementation supports the job control option. ---------------------------------------------------------------------- IEEE SYSTEM FOR COMPUTER ENVIRONMENTS Std 1003.1 3.2.1 Wait for Process Termination Functions: wait(), wait2() 3.2.1.1 Synopsis Add the following at the end of the section: #include <sys/wait.h> int wait2 (stat_loc, options) int *stat_loc; int options; 3.2.1.2 Description Add the following at the end of the section: If the wait2() variant is used, then there are two options available for modifying the behavior of the system call. They may be combined by oring them together. The first is WNOHANG which prevents wait2() from suspending the calling process even if there are children to wait for. In this case, a value of zero is returned indicating there are no children which have stopped or died. If the second option WUNTRACED is set, wait2() will also return information when children of the current process are stopped because they received a SIGTTIN, SIGTTOU, SIGTSTP, or SIGSTOP signal. The wait2() function is provided if the implementation supports the job control option. 3.2.1.3 Returns Add the following at the end of the section: If wait2() is called, the WNOHANG option is used, and there are no stopped or terminated children, then a value of zero is returned. Otherwise, a value of -1 is returned and errno shall be set to indicate the error. ---------------------------------------------------------------------- IEEE SYSTEM FOR COMPUTER ENVIRONMENTS Std 1003.1 In section 3.2.2.2 Description of the _exit function replace the paragraph: If the process is a process group leader, the SIGHUP signal may be sent to each process that has a process group ID equal to that of the calling process. with: If the process is a session process group leader, the SIGHUP signal may be sent to each process that has a process group ID equal to that of the calling process; also, all such processes may have their process group ID set to zero. If the implementation supports the job control option and if the calling process has child processes that are stopped, they will be sent SIGHUP and SIGCONT signals. ---------------------------------------------------------------------- IEEE SYSTEM FOR COMPUTER ENVIRONMENTS Std 1003.1 3.3.1 Signal Names 3.3.1.2 Description Add the following at the end of the signals list. SIGCLD + child process terminated If the implementation supports the job control option then the following are defined: SIGSTOP # stop (cannot be caught or ignored) SIGTSTP # stop signal generated from keyboard SIGTTIN # background read attempted from control terminal SIGTTOU # background write attempted to control terminal SIGCONT %+ continue after stop + Indicates that the action on SIG_DFL is to ignore the signal, rather than terminate the process. # Indicates that the action on SIG_DFL is to stop rather than terminate the process. % Indicates that the signal will not be held off by a stopped process. ---------------------------------------------------------------------- IEEE SYSTEM FOR COMPUTER ENVIRONMENTS Std 1003.1 In section 3.3.2.2 Description of the kill() function, add the following paragraph at the end of the Description section. As a single special case on implementations that support the job control option, the continue signal SIGCONT can be sent to any process that is a descendant of the current process. ---------------------------------------------------------------------- IEEE SYSTEM FOR COMPUTER ENVIRONMENTS Std 1003.1 3.3.3 Signal Processing 3.3.3.2 Description Replace the SIG_DFL and SIG_IGN discussions with the following text. (Note that this text needs rewording based on the signal working group decisions from Palo Alto, 9/86. Bob Lenk is planning on merging this text with the proposal he sends you. So you should only have to verify that he has done this.) SIG_DFL - signal specific default action For all signals listed in the table in <signal.h> 3.3.1, unless otherwise indicated the default action is either simple abnormal termination or abnormal termination with actions of the receiving process. The result of abnormal termination with actions is implementation-dependent. Abnormal termination with actions may result in the creation of a file named core in the receiving process's current directory. Such a core file should contain sufficient information to document the state of the process at the time of the signal. For certain indicated signals listed in the table in <signal.h> 3.3.1, the default action is to stop (suspend) the receiving process. While a process is stopped, any additional signals that are sent to the process will be held off until the process is continued. An exception to this is SIGCONT which always causes the receiving process to continue if it is stopped. When a process is continued, pending signals will be processed. For certain indicated signals listed in the table in <signal.h> 3.3.1, the default action is to ignore the signal. Signals not described <signal.h> 3.3.1 may have other default actions. SIG_IGN - ignore signal The signal sig is to be ignored. The signals SIGKILL and SIGSTOP shall not be ignored. Ignoring SIGCLD may cause terminating children to be ignored by the wait functions 3.2.1. At the end of the "function address - catch signal" discussion, replace the statement: The signal SIGKILL cannot be caught. with: The signals SIGKILL and SIGSTOP cannot be caught. 3.3.3.4 Errors Replace: [EINVAL] The value sig is either an illegal signal number or SIGKILL. with: [EINVAL] The value sig is either an illegal signal number, or is equal to SIGKILL or SIGSTOP. ---------------------------------------------------------------------- IEEE SYSTEM FOR COMPUTER ENVIRONMENTS Std 1003.1 Replace all of section 4.3.1 with: 4.3.1 Get Process Group ID Functions: getpgrp(), getpgrp2() 4.3.1.1 Synopsis int getpgrp ( ) int getpgrp2 (pid) int pid; 4.3.1.2 Description The getpgrp() function returns the process group ID of the calling process. The getpgrp2() function returns the process group ID of the specified process. If pid is zero, the call applies to the current process. For this to be allowed, the real or effective user ID of the current process must match the real or effective user ID of the referenced process, the effective user ID of the current process must be super-user, or the referenced process must be a descendant of the current process. The saved set-user ID of the referenced process may be checked in place of its effective user ID. The getpgrp2() function is provided if the implementation supports the job control option. 4.3.1.3 Returns The getpgrp() function returns the process group ID of the calling process. Upon successful completion, the getpgrp2() function returns the process group ID of the specified process. Otherwise a value of -1 is returned and errno is set to indicate the error. 4.3.1.4 Errors If the getpgrp2() function returns -1, the value stored in errno may be interpreted as follows: [EPERM] The effective user ID of the current process is not super-user, the real or effective user ID of the current process does not match the real or effective user ID (or saved set-user ID) of the specified process, and the specified process is not a descendant of the current process. [ESRCH] No process can be found corresponding to that specified by pid. 4.3.1.5 References setpgrp() 4.3.2, signal() 3.3.3. ---------------------------------------------------------------------- IEEE SYSTEM FOR COMPUTER ENVIRONMENTS Std 1003.1 Replace all of section 4.3.2 with: 4.3.2 Set Process Group Functions: setpgrp(), setpgrp2() 4.3.2.1 Synopsis int setpgrp ( ) int setpgrp2 (pid, pgrp) int pid, pgrp; 4.3.2.2 Description The setpgrp() function sets the process group ID of the calling process to the process ID of the calling process and returns the new process group ID. The calling process becomes a session process group leader. The setpgrp() function relinquishes the process's controlling terminal unless the process is already the process group leader. The setpgrp2() function sets the process group ID of the process specified by pid to be pgrp. If pid is zero, the process group ID of the calling process will be affected. If the affected process's new process group ID is the same as its process ID then the affected process becomes a job control process group leader. The setpgrp2() function does not affect the process's controlling terminal. The setpgrp2() function is provided if the implementation supports the job control option. The following condition must be met for the setpgrp2() function to succeed; otherwise, the error [EINVAL] is returned: The value of pgrp must be in the range of valid process group ID values, or it must be zero ("no process group"). In addition, one or more of the following conditions must be met for the setpgrp2() function to succeed; otherwise, the error [EPERM] is returned: The effective user ID of the calling process is super- user. The affected process is a descendant of the calling process. The real or effective user ID of the calling process matches the real or effective user ID of the affected process. The saved set-user ID of the affected process may be checked in place of its effective user ID. In addition, one or more of the following conditions must be met for the setpgrp2() function to succeed, otherwise, the error [EPERM] is returned: The effective user ID of the calling process is super- user. The value of pgrp matches the saved process group ID of the calling process. All processes with a process ID or process group ID that is the same as pgrp have the same real or effective user ID as the real or effective user ID of the calling process, or are descendants of the calling process. The saved set-user ID of the related processes may be checked in place of their effective user ID. 4.3.2.3 Returns The setpgrp() function returns the value of the new process group ID. Upon successful completion, the setpgrp2() function returns a value of 0. Otherwise, a value of -1 is returned and errno is set to indicate the error. 4.3.2.4 Errors If the setpgrp2() function returns -1, the value stored in errno may be interpreted as follows: [ESRCH] No process can be found corresponding to that specified by pid. [EPERM] The effective user ID of the calling process is not super-user; and the real or effective user ID of the calling process does not match the real or effective user ID (or saved set-user ID) of the specified process; and the specified processes are not descendants of the calling process. [EPERM] The effective user ID of the calling process is not super-user; and the value pgrp does not match the saved process group ID of calling process; and a process exists that is not a descendant of the calling process and whose process ID or process group ID match pgrp, while neither the real or effective user ID (or saved set-user ID) of this process match either the real or effective user ID of the calling process. [EINVAL] The value for pgrp is outside the range of valid process group ID values and is non-zero. 4.3.2.5 References exec 3.1.2, _exit() 3.2.2, fork() 3.1.1, getpid() 4.1.1, kill() 3.3.2, signal() 3.3.3. ---------------------------------------------------------------------- IEEE SYSTEM FOR COMPUTER ENVIRONMENTS Std 1003.1 Alter the forthcoming reliable signals proposal, the sigvector() description, by adding the following paragraph: The sv_flags field can be used to modify the receipt the specified signal. If sig is SIGCLD and the implementation supports the job control option, the following flag bit can be set in sv_flags: SV_CLDSTOP Also generate SIGCLD when children stop @EOF chmod 664 acceptedtext echo x - problems cat >problems <<'@EOF' There are two omissions in the job control specification that have come to light since it was accepted at the P1003 meeting in Palo Alto. There will be forthcoming proposals to correct these. Omission 1: Bob Lenk noticed that, in adding SIGCLD to the required portion of POSIX, we neglected to deal with the issue of what happens when SIGCLD is set to SIG_IGN. Specifically, on ATT this causes terminated children to be invisible to wait*() while on BSD there is no such side effect. Bob Lenk feels the best way to handle this is to disallow conforming applications from setting SIGCLD to SIG_IGN. (There is no advantage to using SIG_IGN over SIG_DFL in the case of SIGCLD anyway.) Bob is planning on submitting a cleanup proposal proposing this. Omission 2: Doug Gwyn pointed out the following omission: The changes to section 3.2.1.2 for wait2() did not contain a description of the returned status information in the case of stopped children. I've submitted a proposal to add the following additional text: [OLD TEXT FOR CONTEXT:] wait2() will also return information when children of the current process are stopped because they received a SIGTTIN, SIGTTOU, SIGTSTP, or SIGSTOP signal. [NEW TEXT:] In this case, the status information can also be interpreted in the following way: If the child process stopped, the 8 bits of status (corresponding to the octal value 0177400) will contain the number of the signal that caused the process to stop and the low order 8 bits corresponding to the octal value 0377 will be set equal to the octal value 0177. @EOF chmod 664 problems exit 0 Volume-Number: Volume 7, Number 53
Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!cmcl2!husc6!ut-sally!std-unix From: std-u...@ut-sally.UUCP (Moderator, John Quarterman) Newsgroups: mod.std.unix Subject: Re: mod.std.unix P1003 job control proposal Message-ID: <5994@ut-sally.UUCP> Date: Sat, 11-Oct-86 21:44:47 EDT Article-I.D.: ut-sally.5994 Posted: Sat Oct 11 21:44:47 1986 Date-Received: Sun, 12-Oct-86 00:00:20 EDT References: <5993@ut-sally.UUCP> Organization: IEEE P1003 Portable Operating System for Computer Environments Committee Lines: 1244 Approved: j...@sally.utexas.edu From: hplabs!hpda!hpisoa1!davel (Dave Lennert) Date: Thu, 09 Oct 86 22:33:31 -0800 As an addendum to the P1003 job control proposal text I submitted, here's a paper describing the 4.2 job control implementation, the System V incompatibilities, and how they were resolved. This was the background investigation that went into the P1003 proposal. This is the same paper that appears in the Atlanta USENIX proceedings. [ June 1986, pp. 459-474. -mod ] It uses the -ms macro package. Dave Lennert ucbvax!hpda!davel [UUCP] Hewlett-Packard - 47UX ihnp4!hplabs!hpda!davel [UUCP] 19447 Pruneridge Ave. hpda!da...@ucb-vax.ARPA [ARPA] Cupertino, CA 95014 (408) 447-6325 [AT&T] # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by davel on Thu Oct 9 22:29:34 PDT 1986 # Contents: jobpaper.ms echo x - jobpaper.ms sed 's/^@//' > "jobpaper.ms" <<'@//E*O*F jobpaper.ms//' @.de PB @.sp 1 @.RS @.nf @.. @.de PE @.fi @.RE @.sp 1 @.. @.DA @. \" Put page numbers at bottom center rather than top center @.rm CH @.ds CF - \\n(PN - @. \" UX - UNIX macro @.de UX @.ie \\n(UX \s-1UNIX\s0\\$1 @.el \{\ \s-1UNIX\s0\\$1\(dg @.FS \(dg \s-1UNIX\s0 is a trademark of AT&T. @.FE @.nr UX 1 @.\} @.. @.TL A System V Compatible Implementation of 4.2BSD Job Control @.AU David C. Lennert @.AI Hewlett-Packard Company Information Technology Group hplabs\^!\^hpda\^!\^davel @.AB This paper gives an overview of how process groups and controlling terminals are handled in System V and 4.2BSD and then discusses the effect 4.2BSD job control has on these things. A modified 4.2BSD interface is discussed which supports 4.2BSD job control functionality but in a way which allows AT&T System V compatibility. This interface has been implemented in Hewlett-Packard's @.UX system, HP-UX. @.AE @.sp 1 @.NH INTRODUCTION @.PP The job control functionality first introduced into @.UX by Jim Kulp of IIASA and later provided by 4.2BSD @.UX has become a \fIde facto\fP industry standard. However, this job control facility, as implemented in 4.2BSD, is incompatible in several respects with System V. @.PP Recently a proposal was submitted to the IEEE P1003 Portable Operating System standard committee by Sun Microsystems [Harris86] which attempts to define 4.2BSD job control functionality in a way compatible with System V. Hewlett-Packard Company has been independently developing a similar proposal. HP's proposal is almost identical to Sun's but goes beyond it to address many "corner case" areas which strongly affect System V compatibility. @.PP This paper gives an overview of the relevant areas of System V functionality which are affected. It then overviews how job control is implemented in 4.2BSD and how this impacts the System V interface. Finally, the HP-UX interface is presented and a similar overview of its implementation is given. @.PP The various overviews cover how job control signals are generated, passed, and acknowledged by the tty driver and user processes. They also explain how process groups are established and changed. @.sp 1 @.NH FUNDAMENTALS @.PP In the following discussion the reader is assumed to have an understanding of several fundamental concepts found in the @.UX operating system. For convenience these concepts are briefly reviewed here. @.NH 2 Process Groups and Controlling Terminals @.PP Every process has a unique numeric value associated with it called its \fIprocess ID\fP. Every process also has a non-unique numeric value associated with it called its \fIprocess group ID\fP. A \fIprocess group\fP is a collection of processes having identical numeric process group ID's. Typically, one process in the process group will be the \fIprocess group leader\fP. The process group leader has a process ID which is numerically equal to the process group ID associated with all processes in the process group. Typically, the process group leader is the ancestor of all other processes in the process group. @.PP A process can have a \fIcontrolling terminal\fP which is usually the login terminal of the user who created the process. A process can obtain access to its controlling terminal by opening the file \fI/dev/tty\fP. All processes in the same process group typically share the same controlling terminal. A terminal usually has a process group ID associated with it, called the \fItty group ID\fP. When a user generates a keyboard signal (e.g., by typing the interrupt character), the tty driver sends the appropriate signal to all processes which are members of the process group indicated by the tty group ID. In summary, usually, but not necessarily, all processes in the same process group share the same controlling terminal, and the tty group ID for that terminal is equal to the process group ID of the process group. @.PP For further explanation see [Roch85] and intro(2) in your favorite @.UX Programmer's Manual. @.NH 2 4.2BSD Job Control @.PP 4.2BSD job control allows users to selectively stop (suspend) the execution of processes and continue (resume) their execution at any later point. This only easily works for processes which are stopped and continued during the same login session. @.PP The user almost always employs this facility via the interactive interface jointly supplied by the system tty driver and a job control shell such as csh(1) or ksh(1). The tty driver recognizes a user-defined \fIsuspend character\fP which causes all current foreground processes to stop and the user's job control shell to resume. The job control shell provides commands which continue stopped processes in either the foreground or background. The tty driver will also stop a background process when it attempts to read from or write to the users terminal. This allows the user to finish or suspend their foreground task without interruption and continue the stopped background process at a more convenient time. @.PP To enable the system to support this, 4.2BSD job control introduces five new signals: SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, and SIGCONT. The first four signals cause a process to stop unless the signals are being caught or ignored. SIGCONT always causes a stopped process to continue. (SIGCONT has no effect on processes which are not stopped.) SIGSTOP cannot be caught or ignored. @.PP The tty driver sends some of these signals to all processes in the tty process group under the following conditions: The driver sends SIGTSTP when the user types the suspend or delayed suspend character. The driver sends SIGTTIN (SIGTTOU) when a background process attempts to read from (write to) its controlling terminal. SIGCONT is usually only sent by a job control shell when the user requests that a stopped process be continued. Of course, any signal can be sent by a user via the kill(1) command or by a program via the kill(2) system call. @.PP It should be noted that these signals can be added to a @.UX implementation in a manner which preserves source and object code compatibility. A process is not required to be aware of them. By default the signals do "the right thing." @.PP For further information see [Joy80] and [UCB83]. @.sp 1 @.NH AT&T SYSTEM V @.NH 2 Introduction @.PP System V process groups closely resemble the concept of a login session. That is, all processes spawned during the same login session tend to belong to the same process group, and keyboard signals are typically sent to all processes spawned from the login session. @.NH 2 System V Process Group Handling @.PP In System V, the only way to alter the process group associated with a process (p_pgrp) is via setpgrp(2). And this can only set the process group to equal the process ID (pid) of the process. When this happens the resulting process with pid = p_pgrp is called a process group leader. Since a process's pid can never change, once a process issues a setpgrp(2) call it irrevocably becomes a process group leader. @.PP The init(1M) process spawns all other processes on the system either directly or indirectly. Before directly spawning a process (after the fork(2) but before the exec(2)), init calls setpgrp(2). Thus all original children (not orphans) of init are forced to (irrevocably) be process group leaders. @.PP When a new process is created, it is assigned a new pid but it inherits the process group number of its parent. Thus child processes are, by default, not process group leaders (although they can become a process group leader via setpgrp(2)). @.PP When a process group leader which has a controlling terminal (see below) terminates, SIGHUP is sent to all processes in the same process group. @.PP Further, when a process group leader terminates, all processes that belong to this process group are altered to belong to no process group (their p_pgrp is set to zero). More precisely, when any process exits, all processes whose process group (p_pgrp) equals the pid of the terminating process will have their p_pgrp set to zero; this check succeeds only in the case of a terminating process group leader. @.NH 2 System V Controlling Terminals @.PP A terminal that is currently open by a process may also be a "controlling terminal" for a process group. When certain control characters are typed on a controlling terminal, signals are sent by the terminal driver to all processes that belong to the process group associated with the terminal. @.PP When a process becomes a process group leader (via setpgrp(2)) it automatically loses its controlling terminal. After this, the first terminal (that is not already a controlling terminal) opened by the process is assigned to be the controlling terminal for that process. Also, the process group associated with that terminal (t_pgrp, also known as the tty group ID) is set equal to the process group associated with the process group leader (p_pgrp). All child processes inherit the controlling terminal and process group of their parent. @.PP More precisely, in System V, the process group associated with a terminal (t_pgrp), can be changed in the following ways: @.IP (1) When a terminal is opened by a process group leader (pid == p_pgrp) that does not already have a controlling terminal, it becomes the controlling terminal for that process group (t_pgrp is set equal to p_pgrp) if it is not already a controlling terminal. @.IP (2) When a process group leader (pid == p_pgrp) dies, if it has a controlling terminal that is associated with the same process group (t_pgrp == p_pgrp), then that terminal is disassociated from that process group (t_pgrp is set to zero). @.IP (3) When the last process to have a terminal open closes that terminal, the terminal is disassociated from its process group (t_pgrp is set to zero). @.NH 2 System V Typical Scenario @.PP This is a typical scenario for the birth and death of a process group and its controlling terminal. @.PP The init(1M) process wants to enable a terminal for login. It calls fork(2) to create a new process and then calls setpgrp(2) to make the process a process group leader which also removes the process's controlling terminal. It then runs the getty(1M) program as the process via exec(2). Getty opens the terminal causing it to become getty's controlling terminal and be associated with getty's process group (t_pgrp is set to p_pgrp). Getty replaces itself with login(1) which replaces itself with a login shell, e.g., sh(1). Usually no program calls setpgrp(2) and thus all descendent processes of the login shell are in the same process group and have the same controlling terminal; keyboard signals are sent to all processes launched during this session. @.PP When a logout occurs, the login shell (which is the process group leader) dies and the controlling terminal is freed up (t_pgrp is set to zero) so that it can be claimed as a controlling terminal by a subsequent getty respawned by init. SIGHUP is sent to all processes in the same process group. The process group (p_pgrp) of all descendent processes is then set to zero. @.PP Note that there may continue to be background processes (previously started by the now defunct login shell) which continue to execute but keyboard signals will no longer be sent to these processes (since both t_pgrp and p_pgrp equal zero). @.sp 1 @.NH 4.2BSD @.NH 2 Introduction @.PP 4.2BSD process groups closely resemble the concept of a task within a login session, where a task represents a set of processes which are affected as a group by job control operations. Every time a job control shell (e.g., csh) spawns either a foreground or background command, all processes in the pipeline (and their descendents) are placed in their own unique process group with the first command in the pipeline being the process group leader. @.PP A task is in the foreground when the process group associated with the controlling terminal for the task (t_pgrp) is equal to the process group associated with the processes in the task (p_pgrp). Otherwise the task is in the background. A job control shell moves a job between the foreground and background by adjusting the terminal process group (t_pgrp) of the controlling terminal. @.PP Note that 4.2BSD forms new process groups with process group leaders much more often than System V usually does (every command versus every login). @.NH 2 4.2BSD Process Group Handling @.PP In 4.2BSD, the process group associated with a process (p_pgrp) can be altered in two ways. The first is via setpgrp(2). 4.2BSD's setpgrp(2) is analogous to System V's setpgrp(2) except that the former can affect processes other than the current process and can cause the affected process to adopt a process group other than that process's process ID (pid). Thus, unlike System V, a process can cease to be a process group leader. @.PP In addition to setpgrp(2), a process that is not a member of any process group (p_pgrp == 0) will "inherit" or join the process group associated with its controlling terminal at the time the process is assigned a controlling terminal during open(2). If the terminal being opened is not presently the controlling terminal for any process group, then the process opening the terminal will first be made a process group leader (p_pgrp will be set to p_pid) and then the terminal will become the controlling terminal for this new process group. All this is done by the tty open code. @.PP When a new process is created it inherits the process group of its parent. @.PP Unlike System V init(1M), 4.2BSD init(8) does not call setpgrp(2) when spawning other processes. All processes spawned by init inherit init's process group which happens to be zero ("not a member of any process group"). This is actually crucial for assigning controlling terminals; see below. @.NH 2 4.2BSD Controlling Terminals @.PP Unlike System V, a 4.2BSD process does not lose its controlling terminal when altering its process group (via setpgrp(2)). Also unlike System V, a 4.2BSD process that is a process group leader (pid == p_pgrp) but which has no controlling terminal does not receive a controlling terminal when opening a new terminal. @.PP A process can obtain a controlling terminal under 4.2BSD in only the following ways: @.IP (1) A process can inherit a controlling terminal from its parent. @.IP (2) A process that is not a member of any process group (p_pgrp == 0) can open any terminal and that terminal will become its controlling terminal (whether or not it is already the controlling terminal for another process). However, this can happen in one of two ways: @.IP If the terminal is not already a controlling terminal (t_pgrp == 0) then the opening process becomes a process group leader (its p_pgrp is set equal to its pid) and the terminal becomes its controlling terminal (t_pgrp is set to the new p_pgrp value). @.IP If the terminal is already a controlling terminal for another process (t_pgrp is not zero) then the opening process joins the process group already associated with the controlling terminal. That is, p_pgrp is set equal to the current t_pgrp. Note that the opening process does not become a process group leader, i.e., p_pgrp is not equal to its pid. @.IP Note that this procedure only happens during the first terminal open for a process that was either originally spawned by init or whose ancestor processes (all the way back to init) never altered their process group (p_pgrp) either by opening a terminal or calling setpgrp(2). @.PP A terminal ceases to be a controlling terminal (t_pgrp is set to zero) under 4.2BSD in the following way: @.IP (1) When the last process to have a terminal open closes that terminal then the terminal is disassociated from its process group (t_pgrp is set to zero). @.PP There are two other facilities unique to 4.2BSD which affect access to control terminals: the TIOCSPGRP ioctl(2) and vhangup(2). @.PP The TIOCSPGRP ioctl(2) function changes a terminal's process group (t_pgrp) to any desired value. It is typically used by csh(1) to control which set of processes (process group) is in the foreground. @.PP The vhangup(2) function is invoked by init after forking but before exec'ing getty. This function removes read and write permission for all processes (including the caller) that have the controlling terminal open (whether or not it is their controlling terminal). It then sends SIGHUP to the process group associated with the terminal (t_pgrp). The latter action is similar to the System V functionality that sends SIGHUP to a process group on death of the process group leader; 4.2BSD does not do this on the death of a process group leader. @.NH 2 4.2BSD Typical Scenario @.PP This is a typical scenario for the birth and death of a login, its controlling terminal, and process groups associated with a job. @.PP The init(8) process wants to enable a terminal for login. First it creates a new process via fork(2). Then it opens the terminal which (because the p_pgrp inherited from init is zero) causes it to become the controlling terminal for this process and either alters the process group (p_pgrp) of the process to match the terminal process group (t_pgrp) if non-zero, or alters both p_pgrp and t_pgrp to equal the process ID (pid) if t_pgrp is zero. At this point the new process has a controlling terminal whose process group (t_pgrp) is equal to the process's process group (p_pgrp). However, the process may not be a process group leader (i.e., p_pgrp may not equal pid). @.PP Now the new process calls vhangup(2) to remove access permissions for the controlling terminal from all processes (as well as sending SIGHUP to any processes in the process group previously associated with the terminal). The new process then reopens the terminal to get a file descriptor with read and write permissions since the vhangup(2) removed these permission from the file descriptor returned by the previous open. The previous file descriptor is not closed until now to prevent losing the controlling terminal; (remember that p_pgrp for the new process is no longer zero.) @.PP The new process now replaces itself with getty(8) which replaces itself with login(1) which replaces itself with a login shell, e.g., csh(1). Csh now begins to manipulate the process group associated with the terminal (t_pgrp) via the TIOCSPGRP and TIOCGPGRP ioctl(2) calls and the process group associated with its child processes (p_pgrp) via setpgrp(2) in order to allow job control. This happens (briefly) in the following way: @.PP Csh launches a pipeline by making all programs in the pipeline be immediate descendents of csh. (This is different from sh which makes all programs in the pipeline except the last be descendents of the last program in the pipeline.) All programs in the pipeline belong to the same process group (not the same as csh's process group) and the first program in the pipeline is the process group leader (its pid is equal to the process group for the pipeline). If the pipeline is being launched in the foreground (or moved to the foreground) then the process group associated with the terminal (t_pgrp) is set to the process group of the pipeline. @.PP When a logout occurs, the login shell dies. Any pending SIGTTIN, SIGTTOU, and SIGTSTP signals are cleared for all descendent processes. All immediate child processes are inherited as orphans by init; if any are currently stopped then they are killed (SIGKILL). If the exiting process is the last process that has the controlling terminal open then the terminal's process group (t_pgrp) is set to zero, otherwise it is left alone. Nothing special is done for process group leaders; in fact, login shells are frequently not process group leaders. (SIGHUP is not sent and the controlling terminal is not necessarily cleared.) @.PP Note that there may continue to be processes (previously started by the now defunct login shell) which continue to execute. And that keyboard signals can still be sent to these processes under some circumstances (specifically when the processes were in the foreground (p_pgrp == t_pgrp) when the login shell died; this usually only happens when the login shell is killed from another terminal via kill(1).) Note also that this continues to be true even after a new session logs in on the same terminal since the new login shell joins the process group which is already associated with the terminal from the prior login. @.NH 2 Job Control Signal Handling @.PP The following discussions concerning signals and kernel process synchronization are similar to ones found in [Thom78], [Ritch79], and [Bach79]. @.NH 3 Basic Overview @.PP Usually a process is either running or sleeping waiting for an event to occur (e.g., I/O completion). When a signal is sent to a process (either by another process or an I/O driver) what actually occurs is that a flag is set for the receiving (or target) process indicating that the signal has been sent and the target process performs the actual signal operation to itself the next time it runs. Thus sending a signal amounts to requesting the target process to itself perform a particular action. If the target process is already running it is interrupted to process the signal. If it is runnable but not currently running then the system merely waits for it to become the currently running process at which point the signal is acknowledged. If the target process is sleeping then either it is moved into a runnable state (if it is sleeping at an "interruptable" priority) or it is left sleeping (at an "uninterruptable" priority) and the signal is not acknowledged until the slept on event occurs. @.PP The kernel procedure which sends a signal is psignal() and is executed by the sending process or driver. Psignal() updates a list of pending signals for the receiving process. If the receiving process is the currently running process and it is executing in kernel mode then the pending signal is acknowledged when the current system call completes. (This is the case where the sending process and the receiving process are the same.) If the receiving process is the currently running process and it is executing in user mode then a special event is generated which causes the process to enter the kernel and acknowledge the pending signal. (This is the case where the sending "process" is really an interrupt handler which, for example, is servicing an interrupt character typed on a user's terminal.) If the receiving process is sleeping but not holding off signals then it is set running via wakeup(); the pending signal is acknowledged as soon as the receiving process executes. If the receiving process is suspended in a sleep state that holds off signals ("sleeping uninterruptably") then it is left sleeping; the pending signal will be acknowledged after the waited for event occurs. @.PP The procedure which tests for a pending signal is issig() and is executed by the receiving process. Issig() is executed whenever the receiving process changes from kernel mode to user mode execution; for example, at the completion of a system call. It is also executed whenever the receiving process is awakened from being suspended in a sleep state that does not hold off signals ("sleeping interruptably"). @.PP The procedure which performs the requested signal operation (e.g., invoking a signal handler or killing the process) is psig() and is executed by the receiving process if issig() returns true. @.PP This basic structure is essentially the same in System V, 4.2BSD, and HP-UX. However, under 4.2BSD-style job control, these general principles can work slightly differently: @.PP When processing stop signals, the psignal() function, called by the sending process, actually stops the target process sometimes. In these cases, the target process never realizes that it received the signal or that it stopped. However, in other cases, psignal() performs the usual process of setting the flag (p_sig) requesting that the target process stop itself the next time it runs. @.PP The issig() function, called by the target process, can actually stop the target process. @.PP The psig() function is only called in the case where a user handler has been provided for the job control signal. @.PP A more complete description of job control signal handling is contained in the pseudocode below. @.NH 3 psignal() @.PP To send SIGCONT to a target process: @.PB sending SIGCONT clears any pending stop signals; if the target process is STOPPED but is also SLEEPING (p_wchan != 0) merely continue the process's SLEEP; else if the target process is STOPPED and is NOT SLEEPING (p_wchan == 0) set the process RUNNING; @.PE @.PP To send a stop signal (SIGTSTP, SIGTTIN, SIGTTOU, SIGSTOP) to a target process: @.PB sending a stop signal clears any pending SIGCONT; if the target process is RUNNABLE or RUNNING note the pending signal in p_sig; else if the target process is SLEEPING NON-interruptably note the pending signal in p_sig; else if the target process is SLEEPING interruptably and IS catching the signal note the pending signal in p_sig and wakeup the process from its sleep; else if the target process is SLEEPING interruptably and is NOT catching the signal stop the process by setting its state to SSTOP but leave it sleeping on its p_wchan; send SIGCLD to parent (if it expects BSD-style) @.PE @.PP General note: sending a stop signal (other than SIGSTOP) to a child of init causes the target process to be killed. @.NH 3 issig() @.PP Issig() is called in all cases except where the process was sleeping interruptably and was not catching the signal. @.PP To acknowledge a pending SIGCONT or stop signal: @.PB if in the middle of a VFORK hold off all stop signals (pretend they don't exist yet) else if catching the signal return a request to invoke user signal handler via psig() else if SIGCONT do nothing /* pretend it doesn't exist */ else /* stop signals */ stop the process by setting its state to SSTOP send SIGCLD to parent (if it expects BSD-style) call swtch() to dispatch another process @.PE @.PP General note: sending a stop signal (other than SIGSTOP) to a child of init causes the target process to be killed. @.NH 3 psig() @.PP Psig() is called whenever issig() returns an indication that a user handler is defined for a job control signal. Psig() merely invokes the user signal handler. @.NH 3 wakeup() @.PP The fact that a process is sleeping (waiting for an event to occur) is indicated by two process state values: p_wchan is non-zero, indicating the event being waited for, and the process state is SSLEEP. @.PP Wakeup() usually causes all processes waiting (sleeping) on a specified event to be awakened. When a process is awakened two things happen: The process is removed from the sleep queue (p_wchan is cleared) and it is added to the run queue. @.PP If, however, wakeup() discovers a process whose p_wchan matches the specified event but whose process state is SSTOP (stopped) then the process is removed from the sleep queue (indicating that the waited for even has happened) but it is not placed on the run queue. A subsequent SIGCONT will cause it to be placed on the run queue. @.PP Thus it is possible to have a process which is both sleeping (p_wchan non-zero) and stopped (process state is SSTOP rather than SSLEEP). @.NH 3 Signal Setup via init @.PP When init(8) launches any process it causes the process to ignore all the job control stop signals (SIGTSTP, SIGTTIN, & SIGTTOU). This allows login shells which are not job control shells to automatically ignore the signals. Further, all descendent processes of such a login shell will also ignore these signals unless they explicitly enable them. @.NH 2 Foreground/Background Processes @.NH 3 Basic Overview @.PP 4.2BSD job control supports the notion of a process being in the @.I foreground or @.I background. The distinction is a background process is usually forced to stop when it attempts to perform I/O (including most control operations) on its controlling terminal, while a foreground process is not hindered. @.PP Specifically, when a background process attempts to read from its controlling terminal it is sent the SIGTTIN signal which, by default, causes it to stop. When it attempts to write to its controlling terminal and LTOSTOP has been enabled for the terminal, then the process is sent the SIGTTOU signal which, by default, causes it to stop. If, however, a background process has chosen to catch the signal, the specified user handler is invoked. If the process is ignoring or masking the stop signal(s), then the terminal I/O request returns an I/O error, EIO. @.PP A background process is one whose process group (p_pgrp) is not equal to the process group of its controlling terminal (t_pgrp) (and t_pgrp is not zero). All other processes (including ones doing I/O to terminals that are not their controlling terminals) are considered to be in the foreground. @.NH 3 Tty Driver Provisions @.PP To distinguish between foreground and background programs the tty driver must perform checks on attempted I/O operations to a process's controlling terminal. This is done in several places. @.PP At the beginning of a read/write system call the tty driver checks to see if the calling process is in the background. If it is, then all processes in the process group of the calling process are sent the appropriate signal (SIGTTIN or SIGTTOU) unless the signal is masked or ignored by the calling process. In this case the driver returns the EIO error. After the tty driver sends the signal, the calling process is put to sleep waiting for the \fIlightning bolt event\fP\(dg. @.FS \(dg The lightning bolt event is a standard @.UX event which occurs frequently, for example, every second. @.FE This allows the calling process to receive the signal (and usually stop). When the process returns from the sleep (usually by being continued) the tty driver repeats the foreground/background check before proceeding with the operation. @.PP When the process is in the foreground, the I/O operation proceeds. In the case of a terminal read this usually results in the process being put to sleep to wait for input characters to arrive. At this point the user could type their suspend character (e.g., ^Z). This causes the interrupt portion of the tty driver to send SIGTSTP to the controlling terminal's process group (i.e., all processes which are in the foreground). In our scenario this would include the process sleeping on terminal input, and this would typically cause it to stop. @.PP When a sleeping process is stopped it is also left sleeping as well. If, in this case, tty input characters subsequently arrived then the process would be awakened. However, because it is also stopped, it would not be set running; it would merely be "unslept". @.PP At some later time the process would be continued (e.g., via a csh "fg" or "bg" command which sends SIGCONT). If the process had not been previously unslept it would merely continue its sleeping; it would receive no indication that it had stopped and continued. If the process had been previously unslept it would now be set running. @.PP When the process is set running it resumes execution in the tty driver. Because a (potentially substantial) amount of time has elapsed and because the process may have been stopped and restarted, the tty driver is no longer sure whether this process is still in the foreground. So before checking if input characters are available, the tty driver rechecks whether the process is in the foreground or background. This is necessary because, in our scenario, the stopped process could have been continued in the background (via csh "bg"). To check this the tty driver merely repeats the foreground/background check it made at the beginning of the system call. @.sp 1 @.NH SYSTEM V INCOMPATIBILITIES AND THEIR RESOLUTIONS @.PP Job control as implemented in 4.2BSD is incompatible with System V semantics in some significant respects. This section discusses each of these incompatibilities and the resolution implemented in HP-UX to maintain System V compatibility. @.PP The system interface needed to support 4.2BSD-style job control, tailored for System V compatibility as discussed in this section, is presented in the form of manual page excerpts in [Len86]. @.NH 2 Setpgrp(2) Changes @.PP Because the needed semantics of 4.2BSD setpgrp(2) conflict with the semantics of System V setpgrp(2), the 4.2BSD setpgrp(2) function was renamed to be setpgrp2(2). (The choice of new name is arbitrary; setpgrp2 was chosen in the same spirit as 4.2BSD's wait3(2).) @.NH 2 SIGHUP Changes @.PP System V semantics state that when a process group leader dies, all processes in the same process group are sent the SIGHUP signal which, by default, kills all the processes. @.PP Job control shells execute a command by making all processes in the pipeline belong to the same (brand new) process group and by making the first program in the pipeline be the process group leader. Typically, the first program in a pipeline terminates before the other programs. Under System V semantics, this would cause the premature death of the remaining pipeline. Because of this, 4.2BSD does not generate SIGHUP on process group leader death. @.PP In order to support System V semantics and still allow job control to function properly, HP-UX makes a distinction between a "System V process group leader" and a "job control process group leader". A System V process group leader is given System V semantics (SIGHUP is generated) and a job control process group leader is given 4.2BSD semantics (SIGHUP is not generated). A process which becomes a process group leader via setpgrp(2) is considered to be a System V process group leader. A process which becomes a process group leader via setpgrp2(2) is considered to be a job control process group leader. Since the HP-UX (and System V) init(1M) program calls setpgrp(2) on behalf of all processes it spawns, all login shells start out as System V process group leaders. A process must explicitly call setpgrp2(2) to deviate from the System V semantics. @.NH 2 SIGCLD Changes @.PP Under System V, SIGCLD is sent to a process whenever one of its immediate child processes dies. Under 4.2BSD, SIGCLD (or its variant, SIGCHLD) is also generated when a process changes state from running to stopped. Since a System V application would not expect to receive SIGCLD under these new circumstances and since a job control shell would not be able to function properly without such notification, a compatible compromise was developed. @.PP The (parent) process wishing to trap SIGCLD may set a flag when calling the HP-UX sigvector(2)\(dg @.FS \(dg Sigvector(2) is an HP-UX extension proposed to the IEEE P1003 [Head85] which supports both the reliable signal operations of 4.2BSD sigvec(2) and the conventional signal operations of System V signal(2). In HP-UX, signal(2) is implemented as a library using sigvector(2). Note that the changes proposed here to sigvector(2) can be identically made to 4.2BSD sigvec(2). @.FE \|routine to establish a signal handler. This flag will cause SIGCLD to be sent for stopped children, in addition to terminated children. A System V application using signal(2) will see the System V compatible SIGCLD semantics. @.NH 2 Controlling Terminal Changes @.PP Under System V, whenever a process group leader dies, the controlling terminal associated with that process group (if any) is deallocated (disassociated from that process group). 4.2BSD does not deallocate controlling terminals on process group leader death for the following reason: Job control shells make the lead process in every pipeline a process group leader. If the controlling terminal for each pipeline were deallocated whenever the lead process terminated, then the remaining processes would effectively become background processes (assuming they were currently in the foreground) and would stop when any of them attempted subsequent I/O to the terminal. @.PP To allow both semantics, controlling terminals are only deallocated when a "System V process group leader" dies and not when a "job control process group leader" dies. (See the discussion of SIGHUP changes above.) @.PP However, this change leads to the following problem: In order for a terminal to be allocated as a controlling terminal for a new login, it must be deallocated when the previous login terminates. System V relies on process group leader death to deallocate controlling terminals (since all login shells are forced to be process group leaders by init(1M)). This is no longer reliable since login shells could become "job control process group leaders". Further, not all logins are spawned directly by init(1M); the 4.2BSD rlogin facility is a prime example. 4.2BSD solves this problem by allowing a new login to join the process group of the controlling terminal which is still allocated from the previous login. However this violates System V compatibility. @.PP The solution chosen was to mark a process that causes a controlling terminal to be allocated and to deallocate the controlling terminal whenever that process terminates. This reliably catches logins which are spawned either directly or indirectly from init(1M), whether they are "System V process group leaders" or not. Controlling terminals continue to be deallocated on death of System V process group leaders using the System V semantics. @.NH 2 Security @.PP Several security holes exist in the 4.2BSD process group altering mechanisms. To plug these holes the following changes were made. @.PP 4.2BSD setpgrp(2) allows a process to alter the process group associated with another process to any value. 4.2BSD restricts this operation so that the affected process must pass the same security restrictions enforced when sending signals, or must be a descendent of the calling process. However, this still allows a process to join a process group already associated with another user. To tighten this security, setpgrp2(2) was further restricted such that if the specified new process group value is equal to the process ID (pid) or process group ID of any existing processes, then all such processes must pass the above security restrictions. @.PP Similarly, the 4.2BSD TIOCSPGRP ioctl(2) allows a terminal's process group to be altered to any value. This allows a user's terminal to easily become an additional "controlling terminal" for another user's process group; keyboard signals can be sent to the other user's processes, thus bypassing the security enforced by kill(2). Because of this, the TIOCSPGRP ioctl(2) was altered to enforce similar security restrictions as setpgrp2(2). @.PP In System V and 4.2BSD, a process can obtain access to its controlling terminal by opening the file \fI/dev/tty\fP. Under System V, processes left executing after a user's logout are allowed further access to \fI/dev/tty\fP until the terminal it represents is reallocated as a controlling terminal for a new login. More specifically, \fI/dev/tty\fP access is allowed whenever the process group ID of the leftover process matches the process group ID of the terminal. These IDs continue to match immediately after logout (since both have been zeroed) until the terminal is re-enabled for login by getty(1M). (Note that when the new login terminates, \fI/dev/tty\fP access is restored again to these prior processes because the controlling terminal's process group ID is re-zeroed.) Further, if a process has its controlling terminal opened directly (not via the \fI/dev/tty\fP synonym) then access is not restricted at all after logout. These System V semantics can constitute security problems. However, they are not explicitly required by the System V Interface Definition [ATT86]. @.PP 4.2BSD does nothing to hamper \fI/dev/tty\fP access for processes remaining after logout. The process group ID for the controlling terminal is not altered, and, in fact, it is preserved even into the next login (since subsequent logins join the already existing process group associated with the terminal, if any). These semantics also represent security problems. However, 4.2BSD does prohibit access to the controlling terminal if it is opened directly; this is accomplished when init(8) issues the vhangup(2) system call. @.PP Although preserving the System V semantics for controlling terminal access after logout is not deemed necessary or even recommended, it is easy to do in the following way. Whenever a process that allocated a controlling terminal dies, all processes which share this controlling terminal have their process group ID zeroed. This is analogous to, and occurs in addition to, the System V behavior of zeroing the process group ID for all related processes when their process group leader dies. \fI/dev/tty\fP checks similar to System V can then be employed. @.NH 2 TTY Driver Considerations @.PP For System V compatibility, the suspend and delayed suspend characters are defaulted to a disabled value (0377). This means that job control is "inactive" by default when a user logs on. The user must explicitly activate job control by defining either or both of these characters via stty(1) or some similar interface. @.PP There should be no problem allowing 4.2BSD-style job control, as modified here, to co-exist with System V's shell layers job control system. (See shl(1) and sxt(7) in the System V Release 2 reference manuals.) @.sp 1 @.NH HP-UX @.NH 2 Introduction @.PP HP-UX process groups are used in two major ways. @.PP System V process groups closely resemble the concept of a login session. That is, all processes spawned during the same login session tend to belong to the same process group, and keyboard signals are typically sent to all processes spawned from the login session. @.PP Job control process groups closely resemble the concept of a task within a login session, where a task represents a set of processes which are affected as a group by job control operations. Every time a job control shell (e.g., csh) spawns either a foreground or background command, all processes in the pipeline (and their descendents) are placed in their own unique process group with the first command in the pipeline being the process group leader. @.PP A task is in the foreground when the process group associated with the controlling terminal for the task (t_pgrp) is equal to the process group associated with the processes in the task (p_pgrp). Otherwise the task is in the background. A job control shell moves a job between the foreground and background by adjusting the terminal process group (t_pgrp) of the controlling terminal. @.PP Note that a job control shell forms new process groups with process group leaders much more often than a non-job control (System V) shell usually does (every command versus every login). @.NH 2 HP-UX Process Group Handling @.PP In HP-UX, the process group associated with a process (p_pgrp) can be altered via setpgrp(2) or setpgrp2(2). @.PP As in System V, setpgrp(2) can only set the process group to equal the process ID (pid) of the process. When this happens, the resulting process with pid = p_pgrp is called a System V process group leader. @.PP Setpgrp2(2) is analogous to setpgrp(2) except that it can affect processes other than the current process and can cause the affected process to adopt a process group other than that process's process ID (pid). Setpgrp2(2) also forms job control process groups rather than System V process groups. Using setpgrp2(2), the calling process, or certain other processes, can either become a job control process group leader or can cease to be a process group leader. @.PP Because job control process groups are handled slightly differently by HP-UX than System V process groups, HP-UX marks processes that are job control process group leaders (i.e., that have called setpgrp2(2) without subsequently calling setpgrp(2)). @.PP The init(1M) process spawns all other processes on the system either directly or indirectly. Before directly spawning a process (after the fork(2) but before the exec(2)), init calls setpgrp(2). Thus all original children (not orphans) of init are forced to start out as System V process group leaders. @.PP When a new process is created, it is assigned a new pid but it inherits the process group number of its parent. Thus child processes are, by default, not process group leaders (although they can become a process group leader via either setpgrp(2) or setpgrp2(2)). @.PP When a System V process group leader that has a controlling terminal (see below) terminates, SIGHUP is sent to all processes in the same process group. Further, when a System V process group leader terminates, all processes which belong to this process group are altered to belong to no process group (their p_pgrp is set to zero). @.PP Also, whenever any process that allocated a controlling terminal terminates, all processes that share this controlling terminal are altered to belong to no process group (their p_pgrp is set to zero). @.PP When any process exits, any pending SIGTTIN, SIGTTOU, and SIGTSTP signals are cleared from all descendent processes (not just immediate children). @.NH 2 HP-UX Controlling Terminals @.PP A terminal that is currently open by a process may also be a "controlling terminal" for a process group (collection of processes). When certain control characters are typed on a controlling terminal, signals are sent by the terminal driver to all processes which belong to the process group associated with the terminal. These include the job control suspend and delayed suspend characters. @.PP Controlling terminals also play a role in determining whether a process is in the foreground or background. See FOREGROUND/BACKGROUND PROCESSES above. @.PP When a process becomes a System V process group leader (via setpgrp(2)) it automatically loses its controlling terminal. (This does not happen for a job control process group leader, i.e. when calling setpgrp2(2).) After this, the first terminal (that is not already a controlling terminal) opened by a process that is a (System V or job control) process group leader is assigned to be the controlling terminal for that process; also the process group associated with that terminal (t_pgrp) is set equal to the process group associated with the process group leader process (p_pgrp). All child processes inherit the controlling terminal and process group of their parent. @.PP More precisely, in HP-UX, the process group associated with a terminal (t_pgrp), can be changed in the following ways: @.IP (1) When a terminal is opened by a System V or job control process group leader (pid == p_pgrp) that does not already have a controlling terminal, it becomes the controlling terminal for that process group (t_pgrp is set equal to p_pgrp) if it is not already a controlling terminal. @.IP (2) When a System V process group leader (pid == p_pgrp) dies, if it has a controlling terminal that is associated with the same process group (t_pgrp == p_pgrp), that terminal is disassociated from that process group (t_pgrp is set to zero). @.IP (3) When any process dies which originally caused a controlling terminal to be created (see (1) above), if it still has a controlling terminal, that terminal is disassociated from its process group (t_pgrp is set to zero). @.IP (4) When the last process to have a terminal open closes that terminal, the terminal is disassociated from its process group (t_pgrp is set to zero). @.IP (5) The TIOCSPGRP ioctl(2) call can explicitly change a terminal's process group (t_pgrp) to any value within certain security restrictions. This is used by a job control shell to change which set of processes (process group) is in the foreground. @.NH 2 HP-UX Typical Scenario @.PP This is a typical scenario for the birth and death of a login, its controlling terminal, and the process groups associated with a job. @.PP The init(1M) process wants to enable a terminal for login. It creates a new process via fork(2) and calls setpgrp(2) to make it a System V process group leader which also removes its controlling terminal. Init then runs the getty(1M) program as the process via exec(2). Getty opens the terminal causing the terminal to become getty's controlling terminal and be associated with getty's process group (t_pgrp is set to p_pgrp). As a side effect, this process is now marked as having created a controlling terminal; when it dies the controlling terminal will be freed for re-use. Getty replaces itself with login(1) which replaces itself with a login shell. @.PP At this point one of two scenarios typically takes place. The login shell is either a job control shell (e.g., csh(1)) or it is not (e.g., sh(1)). @.PP If the login shell is not a job control shell then things proceed much as they do on System V. Usually no program calls setpgrp(2) or setpgrp2(2) and thus all descendent processes of the login shell are in the same process group and have the same controlling terminal; keyboard signals are sent to all processes launched during this session. @.PP If the login shell is a job control shell, then job control operations are performed. Csh begins to manipulate the process group associated with the terminal (t_pgrp) via the TIOCSPGRP and TIOCGPGRP ioctl(2) calls and the process group associated with its child processes (p_pgrp) via setpgrp2(2) in order to allow job control. This happens (briefly) in the following way: @.PP Csh launches a pipeline by making all programs in the pipeline be immediate descendents of csh. (This is different from sh which makes all programs in the pipeline except the last be descendents of the last program in the pipeline.) All programs in the pipeline belong to the same process group (not the same as csh's process group) and the first program in the pipeline is the process group leader (its pid is equal to the process group for the pipeline). This process is specially marked as a job control process group leader since it was established via setpgrp2(2); this basically prevents SIGHUP from being sent to the pipeline when the lead process dies. If the pipeline is being launched in the foreground (or moved to the foreground) then the process group associated with the terminal (t_pgrp) is set to the process group of the pipeline via the TIOCSPGRP ioctl(2). @.PP When a logout occurs, the login shell dies. Any pending SIGTTIN, SIGTTOU, and SIGTSTP signals are cleared for all descendent processes. All immediate child processes are inherited as orphans by init; if any are currently stopped then they are killed (SIGKILL). Since the login shell (actually the getty before it was overlaid) created a controlling terminal, the controlling terminal is now freed (t_pgrp is set to zero) so that it can be claimed as a controlling terminal by a subsequent getty respawned by init; also, all processes which share this controlling terminal have their process group (p_pgrp) set to zero. @.PP When a logout occurs and the login shell is a System V process group leader, SIGHUP is sent to all processes in the same process group, and the process group (p_pgrp) of all descendent processes is set to zero. @.PP Note that there may continue to be background processes (previously started by the now defunct login shell) which continue to execute but keyboard signals will no longer be sent to these processes (since both t_pgrp and p_pgrp equal zero). @.sp 1 @.NH ACKNOWLEDGEMENTS @.PP The following people from Hewlett-Packard contributed to the interface design and implementation of job control for HP-UX: Jim Barton, Dave Decot, Larry Dwyer, Jeff Glasson, Rita Hanson, Stephen Hares, Steve Head, Bob Lenk, John Marvin, Dave Mears, Peter Notess, Arn Schaeffer, Eviatar Shafrir. @.PP Guy Harris from Sun Microsystems made many substantive comments and suggestions which contributed to the interface design and to this paper. @.sp 3 @.NH REFERENCES @.IP [ATT86] 15 \fISystem V Interface Definition\fP, Issue 2, AT&T, 1986. @.IP [Bach84] M. J. Bach and S. J. Buroff, "Multiprocessor @.UX Operating Systems", \fIAT&T Bell Lab. Tech. J.\fP, \fB63,\fP No. 8 (October 1984), pp. 1733-1749. @.IP [Head85] Stephen Head and Donn Terry, "Reliable Signals Proposal", IEEE P1003 Proposal #P.042, Hewlett-Packard Co., September 11, 1985. @.IP [Joy80] William Joy, "An Introduction to the C Shell", Computer Science Division, University of California at Berkeley, November 1980. @.IP [Len86] David Lennert, Guy Harris, et. al., "System V Compatible BSD-style Job Control Facilities", IEEE P1003 Proposal #P.047, Hewlett-Packard Co. & Sun Microsystems, April 9, 1986. @.IP [Ritch79] Dennis M. Ritchie, "The @.UX I/O System", \fIUNIX Programmer's Manual\fP, Seventh Edition, Volume 2b, Bell Telephone Laboratories, Murray Hill, NJ, January 1979. @.IP [Roch85] Marc J. Rochkind, \fIAdvanced @.UX Programming\fP, Englewood Cliffs, N.J.: Prentice-Hall, 1985. @.IP [Harris86] Guy Harris, "Notes on Signal, Terminal Interface, and User/Group ID Handling Proposals", IEEE P1003 Proposal #P.045, Sun Microsystems, January 11, 1986. @.IP [Thom78] K. Thompson, "UNIX Implementation", \fIBell System Tech. J.\fP, \fB57,\fP No. 6 (July - August 1978), pp. 1931-1946. @.IP [UCB83] \fIUNIX Programmer's Manual\fP, 4.2 Berkeley Software Distribution, Virtual VAX-11 Version, Computer Science Division, University of California at Berkeley, August 1983. @.PP @.bp @.DS C APPENDIX JOB CONTROL MANUAL PAGE EXCERPTS @.DE @.PP The following pages contain the @.UX manual pages which are effected by adding a System V compatible implementation of 4.2BSD job control. Note that each manual page generally contains only that portion of text which differs from the System V manual page of the same name. Sometimes, unchanged text is provided for locality reference. Changed text lines are flagged with change bars. @//E*O*F jobpaper.ms// chmod u=rw,g=rw,o=r jobpaper.ms echo Inspecting for damage in transit... temp=/tmp/shar$$; dtemp=/tmp/.shar$$ trap "rm -f $temp $dtemp; exit" 0 1 2 3 15 cat > $temp <<\!!! 1200 8792 53685 jobpaper.ms !!! wc jobpaper.ms | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp if [ -s $dtemp ] then echo "Ouch [diff of wc output]:" ; cat $dtemp else echo "No problems found." fi exit 0 Volume-Number: Volume 7, Number 54
Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!decvax!decwrl!pyramid!ut-sally!std-unix From: std-u...@ut-sally.UUCP Newsgroups: mod.std.unix Subject: Re: mod.std.unix P1003 job control proposal Message-ID: <6040@ut-sally.UUCP> Date: Sat, 18-Oct-86 00:18:02 EDT Article-I.D.: ut-sally.6040 Posted: Sat Oct 18 00:18:02 1986 Date-Received: Sat, 18-Oct-86 07:21:52 EDT References: <5993@ut-sally.UUCP> Organization: IEEE P1003 Portable Operating System for Computer Environments Committee Lines: 17 Approved: j...@sally.utexas.edu From: pyramid!utzoo!henry (Henry Spencer) Date: Fri, 17 Oct 86 20:18:05 CDT Apart from my overall objections to the concept of job control, there is one thing seriously wrong with the P1003 job control proposal as posted: it assumes that function names are distinct in at least the first 8 characters, as witness "setpgrp" vs. "setpgrp2" and "getpgrp" vs. "getpgrp2". Note that an X3J11-conforming C implementation need distinguish only the first 6 characters. I would suggest revised names for the new primitives, perhaps "setjpgrp" and "getjpgrp", with implementations which distinguish 8 or more characters providing "setpgrp2" and "getpgrp2" names as well for maximum compatibility with existing mistakes. Henry Spencer @ U of Toronto Zoology {allegra,ihnp4,decvax,pyramid}!utzoo!henry Volume-Number: Volume 7, Number 70
Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!watmath!clyde!rutgers!seismo!ut-sally!std-unix From: std-u...@ut-sally.UUCP (Moderator, John Quarterman) Newsgroups: mod.std.unix Subject: Re: mod.std.unix P1003 job control proposal Message-ID: <6102@ut-sally.UUCP> Date: Sat, 25-Oct-86 22:26:26 EST Article-I.D.: ut-sally.6102 Posted: Sat Oct 25 22:26:26 1986 Date-Received: Sun, 26-Oct-86 04:37:52 EST References: <5993@ut-sally.UUCP> Organization: IEEE P1003 Portable Operating System for Computer Environments Committee Lines: 69 Approved: j...@sally.utexas.edu From: seismo!munnari!yabbie.rmit.oz!rc...@sally.utexas.edu (Ian Donaldson) Date: Tue, 21 Oct 86 10:39:40 EST > From: im4u!caip!hplabs!hpda!hpisoa1!da...@sally.utexas.edu (Dave Lennert) > Date: Thu, 9 Oct 86 14:06:30 pdt > saved process group ID > An active process has a saved process group ID that is > set to the saved process group ID of the parent > process at the time of creation of the process (via > the fork() function). It is reset to the process > group ID of the process when the process successfully > calls one of the exec functions. What is the significance of the "saved process group ID"? How is it different to the normal process-group-ID? Who uses it? > In section 3.2.2.2 Description of the _exit function replace > the paragraph: > with: > > If the process is a session process group leader, the > SIGHUP signal may be sent to each process that has a ^^^ should be replaced by the word "will" > process group ID equal to that of the calling process; > also, all such processes may have their process group > ID set to zero. > > If the implementation supports the job control option > and if the calling process has child processes that > are stopped, they will be sent SIGHUP and SIGCONT > signals. > I disagree with the proposal on the handling of _exit processing for job control. It should be possible to not have to know in advance that you wish to log-off and leave something running that you started in foreground and later shifted to background. This is a KEY feature of job control. vhangup() will provide clean terminals on a bsd system, and we have improved vhangup further to not just turn off READ/WRITE bits, but to actually redirect the file references to /dev/null (which has the advantage of also dropping DTR reliably). Infinite-loop processes don't cause problems with system-response because they are automatically niced (something that is long-needed in UNIX systems). I see no mention of a vhangup equivalent in this proposal segment, but then again, I haven't seen the whole of P1003 either. I find the SIGHUP being sent by exiting processes to sub-proceses a plain nuisance, and it does nothing for productivity. Nohup(1) is effectively obsoleted by job control, since the process won't receive signals from terminals when they are in background anyway. One if the KEY things about job-control is that you don't have to "know in advance" what you plan to do. Nohup(1) requires that you do known in advance, and with the above proposal, nohup(1) IS required if you want to leave jobs running when you log-off. The SIGHUP and SIGCONT signals are only sent to processes in the terminal process group when modem carrier disappears on a BSD system. Children of init that are stopped are also sent SIGHUP's and SIGCONT's. Children of init that aren't stopped aren't sent anything. Ian Donaldson Volume-Number: Volume 7, Number 84
Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!ut-sally!std-unix From: std-u...@ut-sally.UUCP (Moderator, John Quarterman) Newsgroups: mod.std.unix Subject: Re: mod.std.unix P1003 job control proposal (Brett Galloway) Message-ID: <6192@ut-sally.UUCP> Date: Sat, 1-Nov-86 18:37:33 EST Article-I.D.: ut-sally.6192 Posted: Sat Nov 1 18:37:33 1986 Date-Received: Mon, 3-Nov-86 23:42:32 EST References: <6102@ut-sally.UUCP> Organization: IEEE P1003 Portable Operating System for Computer Environments Committee Lines: 85 Approved: j...@sally.utexas.edu From: pyramid!nsc!hplabs!hpda!hpisoa1!davel (Dave Lennert) Date: Wed, 29 Oct 86 10:07:47 -0800 > From: seismo!munnari!yabbie.rmit.oz!rc...@sally.utexas.edu (Ian Donaldson) > Date: Tue, 21 Oct 86 10:39:40 EST > > What is the significance of the "saved process group ID"? How is > it different to the normal process-group-ID? Who uses it? The saved process group ID is analogous to the saved user and group ID's in System V. They preserve the original values the process had when exec'd. This allows the process to adopt a different value for one of these ID's and later return to its original value. Without a "saved" value, all knowledge of the original value and of the process's rights to use it are lost. The saved process group ID value is necessary with job control in the following scenario: Root user su's to non-root user whose login shell is a job control shell (say csh). Csh resets its process group to a new value (it becomes a process group leader). When it terminates or suspends, it needs to restore both the tty group ID (a process group ID value) and its own process group ID back to the original values they had at entry. (This restores its parent to the foreground.) Under 4.2 this is no problem since there are no security checks for this. Under POSIX there are security checks based on uid's which normally are allowed since the uid of the parent process and the csh are identical, but in our scenario would be disallowed because the uid's don't match. The saved process group ID is an alternate security check which allows the above scenario. See the security discussion in setpgrp2() and in the POSIX termios proposal. > > If the process is a session process group leader, the > > SIGHUP signal may be sent to each process that has a > ^^^ should be replaced by the word "will" > > process group ID equal to that of the calling process; "May" is used here to allow 4.2 systems to conform. 4.2 does not send SIGHUP on process group leader death. Note that, with a job control shell, all child processes started by the shell are placed in a different process group than the (process group leader) shell is in. Thus when the shell dies, SIGHUP is not seen by any of the children anyway. > I disagree with the proposal on the handling of _exit processing for > job control. It should be possible to not have to know in advance > that you wish to log-off and leave something running that you started > in foreground and later shifted to background. This is a KEY feature > of job control. This key feature is preserved in the POSIX specification. Perhaps I don't understand your statement. > vhangup() will provide clean terminals on a bsd system, > and we have improved vhangup further to not just turn off READ/WRITE bits, > but to actually redirect the file references to /dev/null (which has > the advantage of also dropping DTR reliably). > I see no mention of a vhangup equivalent in this proposal segment, but > then again, I haven't seen the whole of P1003 either. vhangup() is indeed desirable. It is not required in POSIX because it is not supported on System V and, indeed, breaks System V compatiblity. (See my job control paper that was posted in mod.std.unix recently.) > Children of init that are stopped are also sent SIGHUP's and SIGCONT's. More correctly, at the time a stopped process is inherited by init (due to its parent's death), it is sent SIGHUP and SIGCONT. POSIX has this too; see the _exit part of the job control specification. > Infinite-loop processes don't cause problems with system-response because > they are automatically niced (something that is long-needed in UNIX systems). Note that this is NOT desirable on, e.g., realtime systems where that long running process may be critical. I'm also getting tired of having my rwhod reniced automatically. Dave Lennert ucbvax!hpda!davel [UUCP] Hewlett-Packard - 47UX ihnp4!hplabs!hpda!davel [UUCP] 19447 Pruneridge Ave. hpda!da...@ucb-vax.ARPA [ARPA] Cupertino, CA 95014 (408) 447-6325 [AT&T] Volume-Number: Volume 8, Number 12
Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!ut-sally!std-unix From: std-u...@ut-sally.UUCP (Moderator, John Quarterman) Newsgroups: mod.std.unix Subject: Re: mod.std.unix P1003 job control proposal (now vhangup, auto-nice) Message-ID: <6234@ut-sally.UUCP> Date: Wed, 5-Nov-86 09:54:41 EST Article-I.D.: ut-sally.6234 Posted: Wed Nov 5 09:54:41 1986 Date-Received: Wed, 5-Nov-86 22:17:20 EST References: <6192@ut-sally.UUCP> Organization: IEEE P1003 Portable Operating System for Computer Environments Committee Lines: 145 Approved: j...@sally.utexas.edu From: seismo!munnari!yabbie.rmit.oz!rc...@sally.utexas.edu (Ian Donaldson) Date: Tue, 4 Nov 86 09:05:35ligt > From: pyramid!nsc!hplabs!hpda!hpisoa1!davel (Dave Lennert) > Date: Wed, 29 Oct 86 10:07:47 -0800 I spoke about HUP's sent when an _exit is done, not realising at the time that it is only done by a sesion-group leader, and only to the same process-group, obviously (it is now) excluding those processes running in background. > This key feature is preserved in the POSIX specification. Perhaps I > don't understand your statement. I withdraw the statement. In the same article, I wrote: > > vhangup() will provide clean terminals on a bsd system, > > and we have improved vhangup further to not just turn off READ/WRITE bits, > > but to actually redirect the file references to /dev/null (which has > > the advantage of also dropping DTR reliably). > > vhangup() is indeed desirable. It is not required in POSIX because it is > not supported on System V and, indeed, breaks System V compatiblity. I forgot to add the other advantage of my vhangup(), in that any read's by processes from the terminal return EOF rather than a read-error, and any writes go to the bit-bucket, rather than producing a write-error. This is very desirable in stuations where you have started something in foreground (eg: make, without redirecting I/O) and you want it to -complete- in background, rather than crash because it cannot write diagnostics or output... Of course, you cannot -see- the output, but that is another topic (along the lines of login-suspension - see ravings in net.unix-wizards about 6 months ago). Some programs of course would need to be trained to not repeatedly read beyond EOF assuming somebody is hitting ^D, otherwise they will do-so forever. Berkeley 4.2bsd Csh and Mail already have been trained, and exit if a certain large number of consecutive EOF's are read. There are probably others. We have not felt need to modify any more programs, though there is the stray program that just sits there all day, once a fortnight perhaps. Readnews seems to be an often offendor (2.10.3). I also wrote: > > Infinite-loop processes don't cause problems with system-response because > > they are automatically niced (something that is long-needed in UNIX > > systems). > > Note that this is NOT desirable on, e.g., realtime systems where that > long running process may be critical. I'm also getting tired of having > my rwhod reniced automatically. > > Dave Lennert ucbvax!hpda!davel [UUCP] Granted, it probably -isn't- desirable at some sites, or perhaps even some particular users at certain sites, but it is necessary for any site that has lots of cpu-intensive tasks mixed in with lots of heavily interactive (eg: vi) sessions. The auto-nicing that I have seen in 4.2 (not sure who added it) whereby a process gets niced by 1 every 40 cpu seconds until the nice reaches +15 is NOT the sort of thing I am talking about. The obvious problem with this algorithm is that it makes no distinctions on what it nices - it nices compiles (ok, good), but it also nices vi (bad), and eventually nices the shell (worse, as everything you start inherits the nice from the shell). It also makes no distinction on -who- it nices; except that root is never niced (neither are other users, provided they are running at elevated priority). This means that all non-root owned daemons get niced also. I experimentally implemented a smarter, but still very simple auto-nicing algorithm that works well here nearly all of the time: it is an extension of the one above, except that interactive processes are identified very simply by the fact that they do tty input (sounds logical). A process is only niced if it consumes N cpu seconds since last doing some tty input (we have N set small, to 5 cpu seconds). This means that an interactive shell is rarely ever niced, and vi always has a good response time regardless of what else is going on in the system (unless you're doing complicated length string searches or the like). Another "quick hack" allowed all uid's less-than a certain number (say 2) to be immue to auto-nicing - this got around the daemon problem, altough very unelegantly. The kernel mods were trivial, amounting to less than a screenful of code all-up. In a nutshell it was one mod to clock.c (kern_clock.c for 4bsd), to increment the nice if the conditions warrant it; and another mod to ttyread() to reset the nice and the accumulated cpu time since the last ttyread(). I have watched people breath discontent over the net with vi's response time, and all the hack's that they've tried (including a suid root pre-elevate-nice command). Vi is only mentioned because it is common to almost all systems. The problem is much deeper than just vi. Any system that treats non-interactive jobs the same as interactive jobs is sure to have a rotten response-time. Interactive jobs are not jobs that are just "associated" with a terminal either. People expecting to do half-hour compiles from the terminal soon learn that there is no advantage in doing-so, and it is better to come back later and free up the terminal for somebody else to use (productively). > Note that this is NOT desirable on, e.g., realtime systems where that > long running process may be critical. Perhaps, but then my version of auto-nice may solve most of such problems anyway. If the program on the real-time system communicates with other than tty's in an "interactive" fashion, then this could be incorporated into the algorithm quite easily. Lots of things could be incorporated into the algorithm - such as a per-user nice-rate and nice-limit. People will never learn - just telling them to "nice" their jobs rarely works. They either forget to, or just don't do it on principle. SVR2 has no way of renicing a job other than restarting it (counter-productive), and telling somebody to change their nice on the humungous compile they just started after they've left and gone home is also often very difficult (read impossible), leaving a very slow system. Vi and similar programs on our systems nearly always have a good response time - the times that they don't would most probably be attributed to excess paging and swapping activity and filesystem I/O. > I'm also getting tired of having > my rwhod reniced automatically. Maybe it wouldn't be with the algoritm I mentioned (I've never used rwhod so I can't answer that). At least auto-nicing of some variety I have mentioned should be provided as a standard -option-. Those who don't like it can turn it off, but I'll bet your boots that they will be in a minority once they've tried it. Not having the option at all is not very nice (excuse the pun :-). Ian Donaldson Volume-Number: Volume 8, Number 37