diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 425e8210..3b24c38f 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -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 + + - 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) diff --git a/MANIFEST b/MANIFEST index cdebaf60..45cd49bd 100644 --- a/MANIFEST +++ b/MANIFEST @@ -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 diff --git a/bashline.c b/bashline.c index 637bf8f8..2569d4dc 100644 --- a/bashline.c +++ b/bashline.c @@ -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 /* 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) { diff --git a/builtins/common.h b/builtins/common.h index a4f9275d..d4ad0407 100644 --- a/builtins/common.h +++ b/builtins/common.h @@ -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; diff --git a/builtins/read.def b/builtins/read.def index 6405b355..e19f1c91 100644 --- a/builtins/read.def +++ b/builtins/read.def @@ -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; diff --git a/examples/shellmath/faster_e_demo.sh* b/examples/shellmath/faster_e_demo.sh* deleted file mode 100755 index 84558a2e..00000000 --- a/examples/shellmath/faster_e_demo.sh* +++ /dev/null @@ -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 - diff --git a/examples/shellmath/slower_e_demo.sh* b/examples/shellmath/slower_e_demo.sh* deleted file mode 100755 index d8fc9314..00000000 --- a/examples/shellmath/slower_e_demo.sh* +++ /dev/null @@ -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 - diff --git a/include/posixtime.h b/include/posixtime.h index d60ece37..1d50ab6c 100644 --- a/include/posixtime.h +++ b/include/posixtime.h @@ -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) diff --git a/lib/readline/readline.h b/lib/readline/readline.h index 90b53892..e7e94419 100644 --- a/lib/readline/readline.h +++ b/lib/readline/readline.h @@ -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)) diff --git a/lib/sh/zread.c b/lib/sh/zread.c index 71a06a76..d8a74221 100644 --- a/lib/sh/zread.c +++ b/lib/sh/zread.c @@ -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; diff --git a/quit.h b/quit.h index db8a776b..0af1d121 100644 --- a/quit.h +++ b/quit.h @@ -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 diff --git a/tests/case.tests b/tests/case.tests index 1ffba97b..7ad4c683 100644 --- a/tests/case.tests +++ b/tests/case.tests @@ -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 diff --git a/tests/read.right b/tests/read.right index f1610608..5000d380 100644 --- a/tests/read.right +++ b/tests/read.right @@ -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 diff --git a/tests/read2.sub b/tests/read2.sub index 8c6f5306..d3530115 100644 --- a/tests/read2.sub +++ b/tests/read2.sub @@ -11,6 +11,8 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . # +: ${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 << 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 diff --git a/tests/read7.sub b/tests/read7.sub index 3410d9ff..469f3c81 100644 --- a/tests/read7.sub +++ b/tests/read7.sub @@ -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 } diff --git a/trap.c b/trap.c index 1b27fb3a..dd1c9a56 100644 --- a/trap.c +++ b/trap.c @@ -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; }