- execute_in_subshell,execute_simple_command,execute_disk_command:
remove calls to CHECK_SIGTERM, since we don't install a handler
any more
+
+lib/readline/readline.c
+ - _rl_enable_bracketed_paste: enabled by default for the time being
+
+ 4/9
+ ---
+jobs.h
+ - JWAIT_WAITING: new flag for wait functions; means only wait for jobs
+ with the J_WAITING flag set
+ - J_WAITING: new job flag, part of arg list to `wait -n'
+ - IS_WAITING(i): job i has the J_WAITING flag set
+
+jobs.c
+ - wait_for_any_job: if the flags includes JWAIT_WAITING, we only return
+ jobs with the J_WAITING flag already set; otherwise we skip them.
+ For `wait -n args' support
+
+builtins/wait.def
+ - set_waitlist: take a list of jobspecs and set the J_WAITING flag in
+ each valid job from the list
+ - unset_waitlist: turn off the J_WAITING flag for all jobs where it's
+ set
+ - wait_builtin: if -n is supplied with a list of arguments, set the
+ J_WAITING flag in each job in the list, call wait_for_any_job with
+ the JWAIT_WAITING flag, and clean up by calling unset_waitlist().
+ From a suggestion from Robert Elz <kre@munnari.oz.au> back in 3/2019
+ (originally in 10/2017)
memset (filename_bstab, 0, sizeof (filename_bstab));
for (s = string; s && *s; s++)
- filename_bstab[*s] = 1;
+ filename_bstab[(unsigned char)*s] = 1;
}
/* Quote a filename using double quotes, single quotes, or backslashes
This file is wait.def, from which is created wait.c.
It implements the builtin "wait" in Bash.
-Copyright (C) 1987-2019 Free Software Foundation, Inc.
+Copyright (C) 1987-2020 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
status is zero. If ID is a job specification, waits for all processes
in that job's pipeline.
-If the -n option is supplied, waits for the next job to terminate and
-returns its exit status.
+If the -n option is supplied, waits for a single job from the list of IDs,
+or, if no IDs are supplied, for the next job to complete and returns its
+exit status.
If the -p option is supplied, the process or job identifier of the job
for which the exit status is returned is assigned to the variable VAR
Exit Status:
Returns the status of the last ID; fails if ID is invalid or an invalid
-option is given.
+option is given, or if -n is supplied and the shell has no unwaited-for
+children.
$END
$BUILTIN wait
#include "../execute_cmd.h"
#include "../jobs.h"
#include "../trap.h"
+#include "../sig.h"
#include "common.h"
#include "bashgetopt.h"
procenv_t wait_intr_buf;
int wait_intr_flag;
+static int set_waitlist PARAMS((WORD_LIST *));
+static void unset_waitlist PARAMS((void));
+
/* Wait for the pid in LIST to stop or die. If no arguments are given, then
wait for all of the active background processes of the shell and return
0. If a list of pids or job specs are given, return the exit status of
#if defined (JOB_CONTROL)
if (nflag)
{
+ if (list)
+ {
+ opt = set_waitlist (list);
+ if (opt == 0)
+ WAIT_RETURN (127);
+ wflags |= JWAIT_WAITING;
+ }
+
status = wait_for_any_job (wflags, &pstat);
if (status < 0)
status = 127;
+
if (vname && status >= 0)
bind_var_to_int (vname, pstat.pid);
+ if (list)
+ unset_waitlist ();
WAIT_RETURN (status);
}
#endif
WAIT_RETURN (status);
}
+
+#if defined (JOB_CONTROL)
+/* Take each valid pid or jobspec in LIST and mark the corresponding job as
+ J_WAITING, so wait -n knows which jobs to wait for. Return the number of
+ jobs we found. */
+static int
+set_waitlist (list)
+ WORD_LIST *list;
+{
+ sigset_t set, oset;
+ int job, r, njob;
+ intmax_t pid;
+ WORD_LIST *l;
+
+ BLOCK_CHILD (set, oset);
+ njob = 0;
+ for (l = list; l; l = l->next)
+ {
+ job = NO_JOB;
+ job = (l && legal_number (l->word->word, &pid) && pid == (pid_t) pid)
+ ? get_job_by_pid ((pid_t) pid, 0, 0)
+ : get_job_spec (l);
+ if (job == NO_JOB || jobs == 0 || INVALID_JOB (job))
+ {
+ sh_badjob (l->word->word);
+ continue;
+ }
+ /* We don't check yet to see if one of the desired jobs has already
+ terminated, but we could. We wait until wait_for_any_job(). This
+ has the advantage of validating all the arguments. */
+ if ((jobs[job]->flags & J_WAITING) == 0)
+ {
+ njob++;
+ jobs[job]->flags |= J_WAITING;
+ }
+ }
+ UNBLOCK_CHILD (oset);
+ return (njob);
+}
+
+/* Clean up after a call to wait -n jobs */
+static void
+unset_waitlist ()
+{
+ int i;
+ sigset_t set, oset;
+
+ BLOCK_CHILD (set, oset);
+ for (i = 0; i < js.j_jobslots; i++)
+ if (jobs[i] && (jobs[i]->flags & J_WAITING))
+ jobs[i]->flags &= ~J_WAITING;
+ UNBLOCK_CHILD (oset);
+}
+#endif
.\" Case Western Reserve University
.\" chet.ramey@case.edu
.\"
-.\" Last Change: Tue Mar 24 16:38:43 EDT 2020
+.\" Last Change: Thu Apr 9 11:50:30 EDT 2020
.\"
.\" bash_builtins, strip all but Built-Ins section
.if \n(zZ=1 .ig zZ
.if \n(zY=1 .ig zY
-.TH BASH 1 "2020 March 24" "GNU Bash 5.0"
+.TH BASH 1 "2020 April 9" "GNU Bash 5.0"
.\"
.\" There's some problem with having a `@'
.\" in a tagged paragraph with the BSD man macros.
the last-executed process substitution, if its process id is the same as
\fB$!\fP,
and the return status is zero.
-If the \fB\-n\fP option is supplied, \fBwait\fP waits for a single job
-to terminate and returns its exit status.
+If the \fB\-n\fP option is supplied,
+\fBwait\fP waits for a single job
+from the list of \fIid\fPs or, if no \fIid\fPs are supplied, any job,
+to complete and returns its exit status.
+If none of the supplied arguments is a child of the shell, or if no arguments
+are supplied and the shell has no unwaited-for children, the exit status
+is 127.
If the \fB\-p\fP option is supplied, the process or job identifier of the job
for which the exit status is returned is assigned to the variable
\fIvarname\fP named by the option argument.
@var{$!},
and the return status is zero.
If the @option{-n} option is supplied, @code{wait} waits for a single job
-to terminate and returns its exit status.
+from the list of @var{pids} or @var{jobspecs} or, if no arguments are
+supplied, any job,
+to complete and returns its exit status.
+If none of the supplied arguments is a child of the shell, or if no arguments
+are supplied and the shell has no unwaited-for children, the exit status
+is 127.
If the @option{-p} option is supplied, the process or job identifier of the job
for which the exit status is returned is assigned to the variable
@var{varname} named by the option argument.
Copyright (C) 1988-2020 Free Software Foundation, Inc.
@end ignore
-@set LASTCHANGE Tue Mar 24 16:38:56 EDT 2020
+@set LASTCHANGE Thu Apr 9 11:58:06 EDT 2020
@set EDITION 5.0
@set VERSION 5.0
-@set UPDATED 24 March 2020
-@set UPDATED-MONTH March 2020
+@set UPDATED 9 April 2020
+@set UPDATED-MONTH April 2020
BLOCK_CHILD (set, oset);
for (i = 0; i < js.j_jobslots; i++)
{
+ if ((flags & JWAIT_WAITING) && jobs[i] && IS_WAITING (i) == 0)
+ continue; /* if we don't want it, skip it */
if (jobs[i] && DEADJOB (i) && IS_NOTIFIED (i) == 0)
{
return_job:
/* Now we see if we have any dead jobs and return the first one */
BLOCK_CHILD (set, oset);
for (i = 0; i < js.j_jobslots; i++)
- if (jobs[i] && DEADJOB (i))
- goto return_job;
+ {
+ if ((flags & JWAIT_WAITING) && jobs[i] && IS_WAITING (i) == 0)
+ continue; /* if we don't want it, skip it */
+ if (jobs[i] && DEADJOB (i))
+ goto return_job;
+ }
UNBLOCK_CHILD (oset);
}
#define JWAIT_PERROR 0x01
#define JWAIT_FORCE 0x02
#define JWAIT_NOWAIT 0x04 /* don't waitpid(), just return status if already exited */
+#define JWAIT_WAITING 0x08 /* wait for jobs marked J_WAITING only */
/* The max time to sleep while retrying fork() on EAGAIN failure */
#define FORKSLEEP_MAX 16
#define J_STATSAVED 0x10 /* A process in this job had status saved via $! */
#define J_ASYNC 0x20 /* Job was started asynchronously */
#define J_PIPEFAIL 0x40 /* pipefail set when job was started */
+#define J_WAITING 0x80 /* one of a list of jobs for which we are waiting */
#define IS_FOREGROUND(j) ((jobs[j]->flags & J_FOREGROUND) != 0)
#define IS_NOTIFIED(j) ((jobs[j]->flags & J_NOTIFIED) != 0)
#define IS_JOBCONTROL(j) ((jobs[j]->flags & J_JOBCONTROL) != 0)
#define IS_ASYNC(j) ((jobs[j]->flags & J_ASYNC) != 0)
+#define IS_WAITING(j) ((jobs[j]->flags & J_WAITING) != 0)
typedef struct job {
char *wd; /* The working directory at time of invocation. */
_rl_keymap = emacs_standard_keymap;
rl_bind_keyseq_if_unbound (BRACK_PASTE_PREF, rl_bracketed_paste_begin);
-
+
+#if defined (VI_MODE)
_rl_keymap = vi_insertion_keymap;
rl_bind_keyseq_if_unbound (BRACK_PASTE_PREF, rl_bracketed_paste_begin);
+ /* XXX - is there a reason to do this in the vi command keymap? */
+#endif
_rl_keymap = xkeymap;
}
-BUILD_DIR=/usr/local/build/chet/bash/bash-current
+BUILD_DIR=/usr/local/build/bash/bash-current
THIS_SH=$BUILD_DIR/bash
PATH=$PATH:$BUILD_DIR
12
[1]- Running sleep 20 &
[3]+ Running sleep 20 &
+5: ok 1
+./jobs5.sub: line 40: wait: %8: no such job
+2: ok 2
+2: ok 3
child1 exit status 0
0
./jobs.tests: line 38: wait: %1: no such job
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
# framework to test new `wait -n' option that waits for any job to finish
set -m
sleep 20 &
-{ sleep 5; exit 12; } &
+{ sleep 2; exit 12; } &
sleep 20 &
wait -n
echo $?
jobs
+disown -a
+
+{ sleep 1 ; exit 4; } &
+{ sleep 2 ; exit 5; } & bgpid1=$!
+{ sleep 4 ; exit 6; } &
+
+wait -p wvar -n %2 %3
+case "$wvar" in
+$bgpid1) echo $?: ok 1;;
+*) echo bad 1;;
+esac
+
+{ sleep 1 ; exit 2; } & bgpid2=$!
+wait -p wvar -n %8 $!
+case $wvar in
+$bgpid2) echo $?: ok 2;;
+*) echo bad 2;;
+esac
+
+disown -a
+
+{ sleep 3; exit 1; } & { sleep 1; exit 2; } & bgpid3=$!
+{ sleep 3; exit 3; } & { sleep 3; exit 4; } &
+
+wait -n -p wpid %1 %2 %3 %4
+
+case $wpid in
+$bgpid3) echo $?: ok 3;;
+*) echo bad 3 ;;
+esac
+
+disown -a
+
+unset bgpid1 bgpid2 bgpid3
+unset wpid