From 1a0d75d47c9d15e78449953751c2b8c6693c850d Mon Sep 17 00:00:00 2001 From: Martijn Dekker Date: Wed, 27 Jul 2022 19:08:57 +0200 Subject: [PATCH] Add ${.sh.ppid} (re: 48f78227) Since we now have sh.current_ppid, we might as well point a shell variable to it, as the cost is nil. Together, ${.sh.pid} and ${.sh.ppid} (updated when a virtual subshell forks) form a logical counterpart pair to $$ and $PPID (never updated in subshells). This commit also adds a section to the manual page that hopefully does away with the depressingly widespread subshell/child shell confusion once and for all... :P --- src/cmd/ksh93/data/variables.c | 1 + src/cmd/ksh93/include/variables.h | 5 +- src/cmd/ksh93/sh.1 | 98 +++++++++++++++++++++++++++---- src/cmd/ksh93/sh/init.c | 1 + src/cmd/ksh93/tests/variables.sh | 2 +- 5 files changed, 91 insertions(+), 16 deletions(-) diff --git a/src/cmd/ksh93/data/variables.c b/src/cmd/ksh93/data/variables.c index d28d54f07..a764379d1 100644 --- a/src/cmd/ksh93/data/variables.c +++ b/src/cmd/ksh93/data/variables.c @@ -103,6 +103,7 @@ const struct shtable2 shtab_variables[] = ".sh.math", 0, (char*)0, ".sh.pool", 0, (char*)0, ".sh.pid", NV_PID|NV_NOFREE, (char*)0, + ".sh.ppid", NV_PID|NV_NOFREE, (char*)0, ".sh.tilde", 0, (char*)0, "SHLVL", NV_INTEGER|NV_NOFREE|NV_EXPORT, (char*)0, "", 0, (char*)0 diff --git a/src/cmd/ksh93/include/variables.h b/src/cmd/ksh93/include/variables.h index ad90dbf24..7d6e5d60d 100644 --- a/src/cmd/ksh93/include/variables.h +++ b/src/cmd/ksh93/include/variables.h @@ -113,7 +113,8 @@ extern void sh_save_rand_seed(struct rand *, int); #define SH_MATHNOD (sh.bltin_nodes+61) #define SH_JOBPOOL (sh.bltin_nodes+62) #define SH_PIDNOD (sh.bltin_nodes+63) -#define SH_TILDENOD (sh.bltin_nodes+64) -#define SHLVL (sh.bltin_nodes+65) +#define SH_PPIDNOD (sh.bltin_nodes+64) +#define SH_TILDENOD (sh.bltin_nodes+65) +#define SHLVL (sh.bltin_nodes+66) #endif /* SH_VALNOD */ diff --git a/src/cmd/ksh93/sh.1 b/src/cmd/ksh93/sh.1 index 473f9653c..5277cb1aa 100644 --- a/src/cmd/ksh93/sh.1 +++ b/src/cmd/ksh93/sh.1 @@ -192,9 +192,9 @@ shell option is on) by a .IR pipe (2) to the standard input of the next command. -Each command, -except possibly the last, -is run as a separate process. +Each command except the last is run asynchronously in a subshell (see +.I Subshells\^ +below). If the .B monitor or @@ -562,7 +562,9 @@ status is 0, otherwise the exit status is 1. .br Execute .I list\^ -in a separate environment. +in a subshell (see +.I Subshells\^ +below). Note, that if two adjacent open parentheses are needed for nesting, a space must be inserted to avoid evaluation as an arithmetic command as described above. @@ -927,6 +929,55 @@ If this value is non-empty and does not start with a .BR \(ap , it replaces the default tilde expansion when the function terminates. Otherwise, the tilde expansion is left unchanged. +.SS Subshells. +A +.I subshell\^ +is a separate execution environment that is a complete duplicate of the +current shell environment, except for two things: all traps are reset to +default except those for signals that are being ignored, and subshells +cannot be interactive (i.e., they have no command prompt). +Changes made within a subshell do not affect the parent environment and are +lost when the subshell exits. +.PP +Particular care should be taken not to confuse a subshell with a newly +invoked shell that is merely a child process of the current shell, +and which (unlike a subshell) starts from scratch in terms of +variables and functions and may be interactive. +Beware of shell tutorials on the Internet that confuse these. +.PP +Subshells are not themselves invoked as commands. +Instead, the following are automatically run in or from a subshell: +.RS 8 +.IP \[bu] 3 +any command or group of commands enclosed in parentheses; +.IP \[bu] +command substitutions of the first and third form (see +.I "Command Substitution" +below); +.IP \[bu] +process substitutions (see +.I "Process Substitution" +below); +.IP \[bu] +all elements of a pipeline except the last; +.IP \[bu] +any command executed asynchronously (i.e., in a background process). +.RE +.PP +Creating processes is expensive, so as a performance optimization, a +subshell of a non-interactive shell may share the process of its parent +environment. Such a subshell is known as a virtual subshell. +Subshells are virtual unless or until something (such as asynchronous +execution, or an attempt to set a process limit using the +.B ulimit +built-in command, or other implementation- or system-defined requirements) +makes it necessary to fork it into a separate process. +Barring any bugs in the shell, virtual subshells should be indistinguishable +from real subshells except by their execution speed and their process ID. +See the description of the +.B .sh.pid +variable below for more information. +.RE .SS Command Substitution. The standard output from a command list enclosed in parentheses preceded by a dollar sign ( @@ -1614,7 +1665,8 @@ that run in the current environment may return status values in this range. .B $ The process ID of the main shell process. Note that this value will not change in a subshell, even if the subshell runs in a different process. -See also \f3.sh.pid\fP. +See also +.BR .sh.pid . .TP .B _ Initially, the value of @@ -1783,14 +1835,30 @@ discipline function is invoked. The current depth for subshells and command substitution. .TP .B .sh.pid -Set to the process ID of the current shell. -This is distinct from -.B $$ -as in forked subshells this is set to the process ID of the -subshell instead of the parent shell's process ID. -In virtual subshells +Set to the process ID of the current shell process. +Unlike +.BR $$ , +this is updated in a subshell when it forks into a new process. +Note that a virtual subshell may have to fork mid-execution +due to various system- and implementation-dependent requirements, +so the value should not be counted on to remain the same +from one command to the next. +If a persistent process ID is required for a subshell, +it must be ensured it is running in its own process first. +Any attempt to set a process limit using the +.B ulimit +built-in command, such as +.BR "ulimit -t unlimited 2>/dev/null" , +is a reliable way to make a subshell fork if it hasn't already. +.TP +.B .sh.ppid +Set to the process ID of the parent of the current shell process. +Unlike +.BR $PPID , +this is updated in a subshell when it forks into a new process. +The same note as for .B .sh.pid -retains its previous value. +applies. .TP .B .sh.value Set to the value of the variable at the time that the @@ -1864,7 +1932,11 @@ built-in command. .TP .B .SM PPID -The process ID of the parent of the shell. +The process ID of the parent of the main shell process. +Note that this value will not change in a subshell, +even if the subshell runs in a different process. +See also +.BR .sh.ppid . .TP .B .SM PWD diff --git a/src/cmd/ksh93/sh/init.c b/src/cmd/ksh93/sh/init.c index c132ff187..d60a64434 100644 --- a/src/cmd/ksh93/sh/init.c +++ b/src/cmd/ksh93/sh/init.c @@ -1923,6 +1923,7 @@ static Init_t *nv_init(void) #endif /* _hdr_locale */ (PPIDNOD)->nvalue.pidp = (&sh.ppid); (SH_PIDNOD)->nvalue.pidp = (&sh.current_pid); + (SH_PPIDNOD)->nvalue.pidp = (&sh.current_ppid); (SH_SUBSHELLNOD)->nvalue.ip = (&sh.realsubshell); (TMOUTNOD)->nvalue.lp = (&sh.st.tmout); (MCHKNOD)->nvalue.lp = (&sh_mailchk); diff --git a/src/cmd/ksh93/tests/variables.sh b/src/cmd/ksh93/tests/variables.sh index 62c112c0c..a59ce3f18 100755 --- a/src/cmd/ksh93/tests/variables.sh +++ b/src/cmd/ksh93/tests/variables.sh @@ -1007,7 +1007,7 @@ set -- $( [[ -n $varname && $varname != '.sh' ]] && print -r -- "$varname" done ) -(($# >= 64)) || err_exit "could not read shtab_variables[]; adjust test script ($# items read)" +(($# >= 65)) || err_exit "could not read shtab_variables[]; adjust test script ($# items read)" # ... unset $SHELL -c '