From 9de65210c61581c50f92b84f6cf0df19f5c63046 Mon Sep 17 00:00:00 2001 From: Johnothan King Date: Thu, 6 Aug 2020 18:53:25 -0700 Subject: [PATCH] Add ${.sh.pid} as an alternative to $BASHPID (#109) This variable is like Bash's $BASHPID, but in virtual subshells it will retain its previous value as virtual subshells don't fork. Both $BASHPID and ${.sh.pid} are different from $$ as the latter is only set to the parent shell's process ID (i.e. it isn't set to the process ID of the current subshell). src/cmd/ksh93/include/defs.h: - Add 'current_pid' for storing the current process ID at a valid memory address. - Change 'ppid' from 'int32_t' to 'pid_t', as the return value from 'getppid' is of the 'pid_t' data type. src/cmd/ksh93/data/variables.c, src/cmd/ksh93/include/variables.h, src/cmd/ksh93/sh/init.c, src/cmd/ksh93/sh/xec.c: - Add the ${.sh.pid} variable as an alternative to $BASHPID. The process ID is stored in a struct before ${.sh.pid} is set as environment variables are pointers that must point to a valid memory address. ${.sh.pid} is updated by the _sh_fork() function, which is called when ksh forks a new process with sh_fork() or sh_ntfork(). src/cmd/ksh93/tests/variables.sh: - Add ${.sh.pid} to the list of special variables and add three regression tests for ${.sh.pid}. src/cmd/ksh93/tests/subshell.sh: - Update the PATH forking regression test to use ${.sh.pid} and remove the TODO note. --- NEWS | 6 ++++++ src/cmd/ksh93/data/variables.c | 1 + src/cmd/ksh93/include/defs.h | 3 ++- src/cmd/ksh93/include/variables.h | 3 ++- src/cmd/ksh93/sh.1 | 10 ++++++++++ src/cmd/ksh93/sh/init.c | 3 ++- src/cmd/ksh93/sh/xec.c | 3 +++ src/cmd/ksh93/tests/subshell.sh | 7 +++---- src/cmd/ksh93/tests/variables.sh | 16 ++++++++++++++++ 9 files changed, 45 insertions(+), 7 deletions(-) diff --git a/NEWS b/NEWS index 87a59cf54..c5f7fde08 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,12 @@ Any uppercase BUG_* names are modernish shell bug IDs. - Fixed a crash that occurred intermittently if 'set -b'/'set -o notify' is active and $PS1 contains a command substitution running an external command. +- Added the '${.sh.pid}' variable as an alternative to Bash's '$BASHPID'. + This variable is set to the current shell's PID, unlike '$$' (which is + set to the parent shell's PID). In virtual subshells '${.sh.pid}' is not + changed from its previous value, while in forked subshells '${.sh.pid}' + is set to the subshell's process ID. + 2020-08-05: - Fixed a bug in functions that caused ksh to crash when an array with an diff --git a/src/cmd/ksh93/data/variables.c b/src/cmd/ksh93/data/variables.c index f6646bac6..cadada6fd 100644 --- a/src/cmd/ksh93/data/variables.c +++ b/src/cmd/ksh93/data/variables.c @@ -99,6 +99,7 @@ const struct shtable2 shtab_variables[] = ".sh.stats", 0, (char*)0, ".sh.math", 0, (char*)0, ".sh.pool", 0, (char*)0, + ".sh.pid", NV_INTEGER|NV_NOFREE, (char*)0, "SHLVL", NV_INTEGER|NV_NOFREE|NV_EXPORT, (char*)0, #if SHOPT_MULTIBYTE "CSWIDTH", 0, (char*)0, diff --git a/src/cmd/ksh93/include/defs.h b/src/cmd/ksh93/include/defs.h index 816876559..67fc40be6 100644 --- a/src/cmd/ksh93/include/defs.h +++ b/src/cmd/ksh93/include/defs.h @@ -122,7 +122,8 @@ struct shared gid_t groupid; gid_t egroupid; pid_t pid; - int32_t ppid; + pid_t ppid; + pid_t current_pid; /* pid of the current ksh instance */ unsigned char sigruntime[2]; Namval_t *bltin_nodes; Namval_t *bltin_cmds; diff --git a/src/cmd/ksh93/include/variables.h b/src/cmd/ksh93/include/variables.h index c53e45f3b..6fff7921c 100644 --- a/src/cmd/ksh93/include/variables.h +++ b/src/cmd/ksh93/include/variables.h @@ -90,6 +90,7 @@ #define SH_STATS (shgd->bltin_nodes+60) #define SH_MATHNOD (shgd->bltin_nodes+61) #define SH_JOBPOOL (shgd->bltin_nodes+62) -#define SHLVL (shgd->bltin_nodes+63) +#define SH_PIDNOD (shgd->bltin_nodes+63) +#define SHLVL (shgd->bltin_nodes+64) #endif /* SH_VALNOD */ diff --git a/src/cmd/ksh93/sh.1 b/src/cmd/ksh93/sh.1 index 47230f48e..4ed099f6e 100644 --- a/src/cmd/ksh93/sh.1 +++ b/src/cmd/ksh93/sh.1 @@ -1664,6 +1664,16 @@ discipline function is invoked. .B .sh.subshell 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 +.B .sh.pid +retains its previous value. +.TP .B .sh.value Set to the value of the variable at the time that the .B set diff --git a/src/cmd/ksh93/sh/init.c b/src/cmd/ksh93/sh/init.c index 2ca5a3c72..6d3c8e8b8 100644 --- a/src/cmd/ksh93/sh/init.c +++ b/src/cmd/ksh93/sh/init.c @@ -1220,7 +1220,7 @@ Shell_t *sh_init(register int argc,register char *argv[], Shinit_f userinit) beenhere = 1; shp = &sh; shgd = newof(0,struct shared,1,0); - shgd->pid = getpid(); + shgd->current_pid = shgd->pid = getpid(); shgd->ppid = getppid(); shgd->userid=getuid(); shgd->euserid=geteuid(); @@ -1832,6 +1832,7 @@ static Init_t *nv_init(Shell_t *shp) nv_stack(LANGNOD, &ip->LANG_init); #endif /* _hdr_locale */ (PPIDNOD)->nvalue.lp = (&shp->gd->ppid); + (SH_PIDNOD)->nvalue.lp = (&shp->gd->current_pid); (TMOUTNOD)->nvalue.lp = (&shp->st.tmout); (MCHKNOD)->nvalue.lp = (&sh_mailchk); (OPTINDNOD)->nvalue.lp = (&shp->st.optindex); diff --git a/src/cmd/ksh93/sh/xec.c b/src/cmd/ksh93/sh/xec.c index a031edcf2..255f47713 100644 --- a/src/cmd/ksh93/sh/xec.c +++ b/src/cmd/ksh93/sh/xec.c @@ -2917,6 +2917,9 @@ pid_t _sh_fork(Shell_t *shp,register pid_t parent,int flags,int *jobid) sh_onstate(SH_NOLOG); if (shp->fn_reset) shp->fn_depth = shp->fn_reset = 0; + /* Set ${.sh.pid} to the child process ID */ + shp->gd->current_pid = getpid(); + SH_PIDNOD->nvalue.lp = &shp->gd->current_pid; #if SHOPT_ACCT sh_accsusp(); #endif /* SHOPT_ACCT */ diff --git a/src/cmd/ksh93/tests/subshell.sh b/src/cmd/ksh93/tests/subshell.sh index c49d109a3..468001697 100755 --- a/src/cmd/ksh93/tests/subshell.sh +++ b/src/cmd/ksh93/tests/subshell.sh @@ -747,14 +747,13 @@ v=$($SHELL $testvars) && [[ "$v" == "a= b= c=0" ]] || err_exit 'variables set in # ====== # Setting PATH in virtual subshell should trigger a fork; restoring PATH after leaving virtual subshell should not. -# TODO: it would be really nice to have a ${.sh.pid} for this sort of test (like $BASHPID on bash)... SHELL=$SHELL "$SHELL" -c ' ( - "$SHELL" -c "echo DEBUG \$PPID" + echo "DEBUG ${.sh.pid}" readonly PATH - "$SHELL" -c "echo DEBUG \$PPID" + echo "DEBUG ${.sh.pid}" ) - "$SHELL" -c "echo DEBUG \$PPID" + echo "DEBUG ${.sh.pid}" : extra command to disable "-c" exec optimization ' | awk '/^DEBUG/ { pid[NR] = $2; } END { exit !(pid[1] == pid[2] && pid[2] == pid[3]); }' \ || err_exit "setting PATH to readonly in subshell triggers an erroneous fork" diff --git a/src/cmd/ksh93/tests/variables.sh b/src/cmd/ksh93/tests/variables.sh index cb4b7b6c6..96266856f 100755 --- a/src/cmd/ksh93/tests/variables.sh +++ b/src/cmd/ksh93/tests/variables.sh @@ -915,6 +915,7 @@ set -- \ ".sh.stats" \ ".sh.math" \ ".sh.pool" \ + ".sh.pid" \ "SHLVL" \ "CSWIDTH" @@ -991,5 +992,20 @@ $SHELL -c ' e=$? ((e == 1)) || err_exit "Failure in making one or more special variables readonly in a subshell (exit status $e)" +# ====== +# ${.sh.pid} should be the forked subshell's PID +( + ulimit -t unlimited + [[ ${.sh.pid} == $$ ]] +) && err_exit "\${.sh.pid} is the same as \$$ (both are $$)" + +# ${.sh.pid} should be the PID of the running job +echo ${.sh.pid} > "$tmp/jobpid" & +wait +[[ $(cat "$tmp/jobpid") == ${.sh.pid} ]] && err_exit "\${.sh.pid} is not set to a job's PID (expected $!, got $(cat "$tmp/jobpid"))" + +# ${.sh.pid} should be the same as $$ in the parent shell +[[ $$ == ${.sh.pid} ]] || err_exit "\${.sh.pid} and \$$ differ in the parent shell (expected $$, got ${.sh.pid})" + # ====== exit $((Errors<125?Errors:125))