read builtin timeouts no longer use SIGALRM

This commit is contained in:
Chet Ramey
2021-03-10 17:15:44 -05:00
parent 11bf534f36
commit 128c5d41b0
16 changed files with 159 additions and 183 deletions
+31
View File
@@ -9726,3 +9726,34 @@ parse.y,shell.h
- {save,restore}_parser_state: save amd restore shell_eof_token and
pushed_string_list; change callers (e.g., xparse_dolparen) so they
don't have to manage them
3/10
----
builtins/common.h
- extern declarations for moving to timers (sh_timer) for read builtin
timeouts
quit.h
- CHECK_ALRM: remove, no longer used
trap.c
- check_signals: call check_read_timeout instead of CHECK_ALRM
bashline.c
- bash_event_hook: use read_timeout instead of checking `sigalrm_seen';
that no longer exists
- bash_event_hook: accommodate readline timing out (not used yet)
lib/sh/zread.c
- zread: call read_builtin_timeout() to check for a timeout before
calling a blocking read()
builtins/read.def
- sigalrm,reset_timeout,check_read_timeout,read_builtin_timeout: new
and modified functions to use sh_timers for timeouts instead of
SIGALRM. Based on work contributed by Koichi Murase
<myoga.murase@gmail.com>
- read_builtin: use sh_timers for read timeouts (-t N) instead of
using SIGALRM
- edit_line: simulate receiving SIGALRM if readline times out (not
used yet)
+3 -2
View File
@@ -368,6 +368,7 @@ lib/readline/posixdir.h f
lib/readline/posixjmp.h f
lib/readline/posixselect.h f
lib/readline/posixstat.h f
lib/readline/posixtime.h f
lib/readline/ansi_stdlib.h f
lib/readline/rlstdc.h f
lib/readline/rlprivate.h f
@@ -868,11 +869,11 @@ examples/misc/cshtobash f
examples/shellmath/LICENSE f
examples/shellmath/README.md f
examples/shellmath/assert.sh f
examples/shellmath/faster_e_demo.sh* f
examples/shellmath/faster_e_demo.sh f
examples/shellmath/image.png f
examples/shellmath/runTests.sh f
examples/shellmath/shellmath.sh f
examples/shellmath/slower_e_demo.sh* f
examples/shellmath/slower_e_demo.sh f
examples/shellmath/testCases.in f
examples/shellmath/timingData.txt f
tests/README f
+15 -5
View File
@@ -1,6 +1,6 @@
/* bashline.c -- Bash's interface to the readline library. */
/* Copyright (C) 1987-2020 Free Software Foundation, Inc.
/* Copyright (C) 1987-2021 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -56,6 +56,7 @@
#include "shmbutil.h"
#include "trap.h"
#include "flags.h"
#include "timer.h"
#if defined (HAVE_MBSTR_H) && defined (HAVE_MBSCHR)
# include <mbstr.h> /* mbschr */
@@ -225,6 +226,7 @@ static char **prog_complete_matches;
extern int no_symbolic_links;
extern STRING_INT_ALIST word_token_alist[];
extern sh_timer *read_timeout;
/* SPECIFIC_COMPLETION_FUNCTIONS specifies that we have individual
completion functions which indicate what type of completion should be
@@ -4627,19 +4629,27 @@ bash_event_hook ()
sig = terminating_signal;
else if (interrupt_state)
sig = SIGINT;
else if (sigalrm_seen)
else if (read_timeout && read_timeout->alrmflag)
sig = SIGALRM;
else if (RL_ISSTATE (RL_STATE_TIMEOUT)) /* just in case */
{
sig = SIGALRM;
if (read_timeout)
read_timeout->alrmflag = 1;
}
else
sig = first_pending_trap ();
/* If we're going to longjmp to top_level, make sure we clean up readline.
check_signals will call QUIT, which will eventually longjmp to top_level,
calling run_interrupt_trap along the way. The check for sigalrm_seen is
to clean up the read builtin's state. */
if (terminating_signal || interrupt_state || sigalrm_seen)
calling run_interrupt_trap along the way. The check against read_timeout
is so we can clean up the read builtin's state. */
if (terminating_signal || interrupt_state || (read_timeout && read_timeout->alrmflag))
rl_cleanup_after_signal ();
bashline_reset_event_hook ();
RL_UNSETSTATE (RL_STATE_TIMEOUT); /* XXX */
/* posix mode SIGINT during read -e. We only get here if SIGINT is trapped. */
if (posixly_correct && this_shell_builtin == read_builtin && sig == SIGINT)
{
+4 -4
View File
@@ -1,6 +1,6 @@
/* common.h -- extern declarations for functions defined in common.c. */
/* Copyright (C) 1993-2020 Free Software Foundation, Inc.
/* Copyright (C) 1993-2021 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -151,6 +151,9 @@ extern void builtin_help PARAMS((void));
extern void read_tty_cleanup PARAMS((void));
extern int read_tty_modified PARAMS((void));
extern int read_builtin_timeout PARAMS((int));
extern void check_read_timeout PARAMS((void));
/* Functions from set.def */
extern int minus_o_option_value PARAMS((char *));
extern void list_minus_o_opts PARAMS((int, int));
@@ -236,9 +239,6 @@ extern int breaking;
extern int continuing;
extern int loop_level;
/* variables from read.def */
extern int sigalrm_seen;
/* variables from shift.def */
extern int print_shift_error;
+71 -30
View File
@@ -1,7 +1,7 @@
This file is read.def, from which is created read.c.
It implements the builtin "read" in Bash.
Copyright (C) 1987-2020 Free Software Foundation, Inc.
Copyright (C) 1987-2021 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -108,6 +108,7 @@ $END
#endif
#include "shmbutil.h"
#include "timer.h"
#if !defined(errno)
extern int errno;
@@ -133,11 +134,10 @@ static int read_mbchar PARAMS((int, char *, int, int, int));
static void ttyrestore PARAMS((struct ttsave *));
static sighandler sigalrm PARAMS((int));
static void reset_alarm PARAMS((void));
static void reset_timeout PARAMS((void));
/* Try this to see what the rest of the shell can do with the information. */
procenv_t alrmbuf;
int sigalrm_seen;
sh_timer *read_timeout;
static int reading, tty_modified;
static SigHandler *old_alrm;
@@ -149,21 +149,44 @@ static struct ttsave termsave;
avoids problems with the semi-tricky stuff we do with the xfree of
input_string at the top of the unwind-protect list (see below). */
/* Set a flag that CHECK_ALRM can check. This relies on zread or read_builtin
calling trap.c:check_signals(), which knows about sigalrm_seen and alrmbuf. */
/* Set a flag that check_read_timeout can check. This relies on zread or
read_builtin calling trap.c:check_signals() (which calls check_read_timeout()) */
static sighandler
sigalrm (s)
int s;
{
sigalrm_seen = 1;
/* Display warning if this is called without read_timeout set? */
if (read_timeout)
read_timeout->alrmflag = 1;
}
static void
reset_alarm ()
reset_timeout ()
{
/* Cancel alarm before restoring signal handler. */
falarm (0, 0);
set_signal_handler (SIGALRM, old_alrm);
if (read_timeout)
shtimer_clear (read_timeout);
read_timeout = 0;
}
void
check_read_timeout ()
{
if (read_timeout && shtimer_chktimeout (read_timeout))
sh_longjmp (read_timeout->jmpenv, 1);
}
int
read_builtin_timeout (fd)
int fd;
{
if ((read_timeout == 0) ||
(read_timeout->fd != fd) ||
(read_timeout->tmout.tv_sec == 0 && read_timeout->tmout.tv_usec == 0))
return 0;
return ((read_timeout->flags & SHTIMER_ALARM) ? shtimer_alrm (read_timeout)
: shtimer_select (read_timeout));
}
/* Read the value of the shell variables whose names follow.
@@ -227,7 +250,8 @@ read_builtin (list)
USE_VAR(ps2);
USE_VAR(lastsig);
sigalrm_seen = reading = tty_modified = 0;
reading = tty_modified = 0;
read_timeout = 0;
i = 0; /* Index into the string that we are reading. */
raw = edit = 0; /* Not reading raw input by default. */
@@ -332,11 +356,7 @@ read_builtin (list)
/* `read -t 0 var' tests whether input is available with select/FIONREAD,
and fails if those are unavailable */
if (have_timeout && tmsec == 0 && tmusec == 0)
#if 0
return (EXECUTION_FAILURE);
#else
return (input_avail (fd) ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
#endif
/* Convenience: check early whether or not the first of possibly several
variable names is a valid identifier, and bail early if so. */
@@ -392,7 +412,7 @@ read_builtin (list)
#if defined (SIGCHLD)
sigemptyset (&chldset);
sigprocmask (SIG_BLOCK, (sigset_t *)0, &chldset);
sigaddset (&chldset, SIGCHLD);
sigaddset (&chldset, SIGCHLD);
#endif
begin_unwind_frame ("read_builtin");
@@ -443,10 +463,25 @@ read_builtin (list)
if (tmsec > 0 || tmusec > 0)
{
code = setjmp_nosigs (alrmbuf);
read_timeout = shtimer_alloc ();
read_timeout->flags = SHTIMER_LONGJMP;
#if defined (HAVE_SELECT)
read_timeout->flags |= edit ? SHTIMER_ALARM : SHTIMER_SELECT;
#else
read_timeout->flags |= SHTIMER_ALARM;
#endif
read_timeout->fd = fd;
read_timeout->alrm_handler = sigalrm;
}
if (tmsec > 0 || tmusec > 0)
{
code = setjmp_nosigs (read_timeout->jmpenv);
if (code)
{
sigalrm_seen = 0;
reset_timeout ();
sigprocmask (SIG_SETMASK, &prevset, (sigset_t *)0);
/* Tricky. The top of the unwind-protect stack is the free of
@@ -470,8 +505,7 @@ read_builtin (list)
}
if (interactive_shell == 0)
initialize_terminating_signals ();
old_alrm = set_signal_handler (SIGALRM, sigalrm);
add_unwind_protect (reset_alarm, (char *)NULL);
add_unwind_protect (reset_timeout, (char *)NULL);
#if defined (READLINE)
if (edit)
{
@@ -479,8 +513,7 @@ read_builtin (list)
add_unwind_protect (bashline_reset_event_hook, (char *)NULL);
}
#endif
sigprocmask (SIG_BLOCK, (sigset_t *)0, &prevset);
falarm (tmsec, tmusec);
shtimer_set (read_timeout, tmsec, tmusec);
}
/* If we've been asked to read only NCHARS chars, or we're using some
@@ -556,7 +589,7 @@ read_builtin (list)
of the unwind-protect stack after the realloc() works right. */
add_unwind_protect (xfree, input_string);
CHECK_ALRM;
check_read_timeout ();
if ((nchars > 0) && (input_is_tty == 0) && ignore_delim) /* read -N */
unbuffered_read = 2;
else if ((nchars > 0) || (delim != '\n') || input_is_pipe)
@@ -575,7 +608,7 @@ read_builtin (list)
ps2 = 0;
for (print_ps2 = eof = retval = 0;;)
{
CHECK_ALRM;
check_read_timeout ();
#if defined (READLINE)
if (edit)
@@ -622,7 +655,7 @@ read_builtin (list)
}
reading = 1;
CHECK_ALRM;
check_read_timeout ();
errno = 0;
#if defined (SIGCHLD)
@@ -673,7 +706,7 @@ read_builtin (list)
#endif
if (retval <= 0) /* XXX shouldn't happen */
CHECK_ALRM;
check_read_timeout ();
/* XXX -- use i + mb_cur_max (at least 4) for multibyte/read_mbchar */
if (i + (mb_cur_max > 4 ? mb_cur_max : 4) >= size)
@@ -733,7 +766,7 @@ read_builtin (list)
add_char:
input_string[i++] = c;
CHECK_ALRM;
check_read_timeout ();
#if defined (HANDLE_MULTIBYTE)
/* XXX - what if C == 127? Can DEL introduce a multibyte sequence? */
@@ -770,7 +803,7 @@ add_char:
break;
}
input_string[i] = '\0';
CHECK_ALRM;
check_read_timeout ();
#if defined (READLINE)
if (edit)
@@ -787,7 +820,7 @@ add_char:
}
if (tmsec > 0 || tmusec > 0)
reset_alarm ();
reset_timeout ();
if (nchars > 0 || delim != '\n')
{
@@ -1160,7 +1193,15 @@ edit_line (p, itext)
bashline_reset_event_hook ();
if (ret == 0)
return ret;
{
if (RL_ISSTATE (RL_STATE_TIMEOUT))
{
sigalrm (SIGALRM); /* simulate receiving SIGALRM */
check_read_timeout ();
}
return ret;
}
len = strlen (ret);
ret = (char *)xrealloc (ret, len + 2);
ret[len++] = delim;
-68
View File
@@ -1,68 +0,0 @@
#!/usr/bin/env bash
###############################################################################
# This script performs the same task as "slower_e_demo.sh" but with a major
# performance optimization. The speedup is especially noticeable on GNU
# emulation layers for Windows such as Cygwin and minGW, where the overhead
# of subshelling is quite significant.
#
# The speedup uses global storage space to simulate pass-and-return by
# reference so that you can capture the side effects of a function call without
# writing to stdout and wrapping the call in a subshell. How to use:
#
# Turn on "__shellmath_isOptimized" as shown below.
# Then instead of invoking "mySum = $(_shellmath_add $x $y)",
# call "_shellmath_add $x $y; _shellmath_getReturnValue mySum".
###############################################################################
source shellmath.sh
# Setting the '-t' flag will cause the script to time the algorithm
if [[ "$1" == '-t' ]]; then
do_timing=${__shellmath_true}
shift
fi
if [[ $# -ne 1 ]]; then
echo "USAGE: ${BASH_SOURCE##*/} [-t] *N*"
echo " Approximates 'e' using the N-th order Maclaurin polynomial"
echo " (i.e. the Taylor polynomial centered at 0)."
echo " Specify the '-t' flag to time the main algorithm."
exit 0
elif [[ ! "$1" =~ ^[0-9]+$ ]]; then
echo "Illegal argument. Whole numbers only, please."
exit 1
fi
__shellmath_isOptimized=${__shellmath_true}
function run_algorithm()
{
# Initialize
n=0; N=$1; zero_factorial=1
# Initialize "e" to its zeroth-order term
_shellmath_divide 1 $zero_factorial
_shellmath_getReturnValue term
e=$term
# Compute successive terms T(n) := T(n-1)/n and accumulate into e
for ((n=1; n<=N; n++)); do
_shellmath_divide "$term" "$n"
_shellmath_getReturnValue term
_shellmath_add "$e" "$term"
_shellmath_getReturnValue e
done
echo "e = $e"
}
if (( do_timing == __shellmath_true )); then
time run_algorithm "$1"
else
run_algorithm "$1"
fi
exit 0
-55
View File
@@ -1,55 +0,0 @@
#!/usr/bin/env bash
###############################################################################
# This script illustrates the use of the shellmath APIs to perform
# decimal calculations. Here we approximate the mathematical constant 'e'
# using its Maclaurin polynomials (i.e. its Taylor polynomials centered at 0).
###############################################################################
source shellmath.sh
# Setting the '-t' flag will cause the script to time the algorithm
if [[ "$1" == '-t' ]]; then
do_timing=${__shellmath_true}
shift
fi
if [[ $# -ne 1 ]]; then
echo "USAGE: ${BASH_SOURCE##*/} [-t] *N*"
echo " Approximates 'e' using the N-th order Maclaurin polynomial"
echo " (i.e. the Taylor polynomial centered at 0)."
echo " Specify the '-t' flag to time the main algorithm."
exit 0
elif [[ ! "$1" =~ ^[0-9]+$ ]]; then
echo "Illegal argument. Whole numbers only, please."
exit 1
fi
function run_algorithm()
{
# Initialize
n=0; N=$1; zero_factorial=1
# Initialize e to the zeroth-order term
term=$(_shellmath_divide 1 $zero_factorial)
e=$term
# Compute successive terms T(n) := T(n-1)/n and accumulate into e
for ((n=1; n<=N; n++)); do
term=$(_shellmath_divide "$term" "$n")
e=$(_shellmath_add "$e" "$term")
done
echo "e = $e"
}
if (( do_timing == __shellmath_true )); then
time run_algorithm "$1"
else
run_algorithm "$1"
fi
exit 0
+2 -2
View File
@@ -72,8 +72,8 @@ extern int gettimeofday PARAMS((struct timeval *, void *));
#endif
/* These are non-standard. */
#if !defined (timerunset)
# define timerunset(tvp) ((tvp)->tv_sec == 0 && (tvp)->tv_usec == 0)
#if !defined (timerisunset)
# define timerisunset(tvp) ((tvp)->tv_sec == 0 && (tvp)->tv_usec == 0)
#endif
#if !defined (timerset)
# define timerset(tvp, s, u) do { tvp->tv_sec = s; tvp->tv_usec = u; } while (0)
+1
View File
@@ -906,6 +906,7 @@ extern int rl_persistent_signal_handlers;
#define RL_STATE_REDISPLAYING 0x1000000 /* updating terminal display */
#define RL_STATE_DONE 0x2000000 /* done; accepted line */
#define RL_STATE_TIMEOUT 0x4000000 /* readline() timed out */
#define RL_SETSTATE(x) (rl_readline_state |= (x))
#define RL_UNSETSTATE(x) (rl_readline_state &= ~(x))
+3 -1
View File
@@ -46,6 +46,7 @@ extern int executing_builtin;
extern void check_signals_and_traps (void);
extern void check_signals (void);
extern int signal_is_trapped (int);
extern int read_builtin_timeout (int);
/* Read LEN bytes from FD into BUF. Retry the read on EINTR. Any other
error causes the loop to break. */
@@ -58,7 +59,8 @@ zread (fd, buf, len)
ssize_t r;
check_signals (); /* check for signals before a blocking read */
while ((r = read (fd, buf, len)) < 0 && errno == EINTR)
while (((r = read_builtin_timeout (fd)) < 0 || (r = read (fd, buf, len)) < 0) &&
errno == EINTR)
{
int t;
t = errno;
+1 -7
View File
@@ -1,6 +1,6 @@
/* quit.h -- How to handle SIGINT gracefully. */
/* Copyright (C) 1993-2013 Free Software Foundation, Inc.
/* Copyright (C) 1993-2021 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -38,12 +38,6 @@ extern volatile sig_atomic_t terminating_signal;
if (interrupt_state) throw_to_top_level (); \
} while (0)
#define CHECK_ALRM \
do { \
if (sigalrm_seen) \
sh_longjmp (alrmbuf, 1); \
} while (0)
#define SETINTERRUPT interrupt_state = 1
#define CLRINTERRUPT interrupt_state = 0
-2
View File
@@ -66,8 +66,6 @@ case " " in ( [" "] ) echo ok;; ( * ) echo no;; esac
case esac in (esac) echo esac;; esac
case k in else|done|time|esac) for f in 1 2 3 ; do :; done esac
# tests of quote removal and pattern matching
${THIS_SH} ./case1.sub
${THIS_SH} ./case2.sub
+2 -1
View File
@@ -39,9 +39,10 @@ timeout 2: ok
unset or null 2
timeout 3: ok
unset or null 3
./read2.sub: line 43: read: -3: invalid timeout specification
./read2.sub: line 45: read: -3: invalid timeout specification
1
abcde
abcde
./read3.sub: line 17: read: -1: invalid number
abc
+20
View File
@@ -11,6 +11,8 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
: ${TMPDIR:=/var/tmp}
a=4
read -t 1 a < /dev/tty
@@ -50,3 +52,21 @@ echo abcde | {
read -t 0.5 a
echo $a
}
read -t .0001 a <<<abcde
echo $a
# this is the original test that prompted the change to sh_timers
cd $TMPDIR
rm -f a.pipe
mkfifo a.pipe
exec 9<> a.pipe
rm -f a.pipe
for c in {0..2000}; do
(eval "echo {0..$c}" & read -u 9 -t 0.0001) >/dev/null
printf $'ok %d' "$c" >/dev/null
done
cd $OLDPWD
rm -f $TMPDIR/a.pipe # paranoia
+3 -3
View File
@@ -13,7 +13,7 @@
#
# test behavior of native readline timeouts
read -t 0.001 -e var
read -t 0.00001 -e var
estat=$?
if [ $estat -gt 128 ]; then
echo timeout 1: ok
@@ -40,7 +40,7 @@ else
fi
echo ${var:-unset or null 3}
sleep 2 | read -t 1 -e a
sleep 1 | read -t 0.25 -e a
estat=$?
if [ $estat -gt 128 ]; then
echo timeout 4: ok
@@ -50,6 +50,6 @@ fi
# the above should all time out
echo abcde | {
read -e -t 2 a
read -e -t 0.5 a
echo $a
}
+3 -3
View File
@@ -1,7 +1,7 @@
/* trap.c -- Not the trap command, but useful functions for manipulating
those objects. The trap command is in builtins/trap.def. */
/* Copyright (C) 1987-2020 Free Software Foundation, Inc.
/* Copyright (C) 1987-2021 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -87,7 +87,6 @@ static void reset_or_restore_signal_handlers (sh_resetsig_func_t *);
static void trap_if_untrapped (int, char *);
/* Variables used here but defined in other files. */
extern procenv_t alrmbuf;
extern volatile int from_return_trap;
extern int waiting_for_child;
@@ -587,7 +586,8 @@ clear_pending_traps ()
void
check_signals ()
{
CHECK_ALRM; /* set by the read builtin */
/* Add any other shell timeouts here */
check_read_timeout (); /* set by the read builtin */
QUIT;
}