From c292a3ae50bd0605b015f80266418e391c3c10fe Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Sat, 11 Nov 2000 19:50:27 +0000 Subject: Sven: 13108: Handle traps synchronously pws: 13109, 13111: clear up zle display when output produced in trap. --- Src/Modules/zftp.c | 20 +++++++-------- Src/Modules/zpty.c | 4 +-- Src/Zle/zle_main.c | 19 ++++++++++---- Src/Zle/zle_thingy.c | 16 +++++++++--- Src/builtin.c | 12 +++++---- Src/exec.c | 22 +++++++++++----- Src/init.c | 3 ++- Src/input.c | 4 ++- Src/jobs.c | 14 ++++++---- Src/signals.c | 72 +++++++++++++++++++++++++++++++++++++++++++++------- Src/signals.h | 35 +++++++++++++++++++++++-- Src/utils.c | 30 ++++++++++++++++++++-- Src/zsh.h | 2 -- 13 files changed, 199 insertions(+), 54 deletions(-) (limited to 'Src') diff --git a/Src/Modules/zftp.c b/Src/Modules/zftp.c index e39994733..ef37dbdc7 100644 --- a/Src/Modules/zftp.c +++ b/Src/Modules/zftp.c @@ -801,7 +801,7 @@ zfgetline(char *ln, int lnsize, int tmout) cmdbuf[0] = (char)IAC; cmdbuf[1] = (char)DONT; cmdbuf[2] = ch; - write(zfsess->cfd, cmdbuf, 3); + ztrapwrite(zfsess->cfd, cmdbuf, 3); continue; case DO: @@ -811,7 +811,7 @@ zfgetline(char *ln, int lnsize, int tmout) cmdbuf[0] = (char)IAC; cmdbuf[1] = (char)WONT; cmdbuf[2] = ch; - write(zfsess->cfd, cmdbuf, 3); + ztrapwrite(zfsess->cfd, cmdbuf, 3); continue; case EOF: @@ -996,7 +996,7 @@ zfsendcmd(char *cmd) return 6; } zfalarm(tmout); - ret = write(zfsess->cfd, cmd, strlen(cmd)); + ret = ztrapwrite(zfsess->cfd, cmd, strlen(cmd)); alarm(0); if (ret <= 0) { @@ -1470,7 +1470,7 @@ zfread(int fd, char *bf, off_t sz, int tmout) int ret; if (!tmout) - return read(fd, bf, sz); + return ztrapread(fd, bf, sz); if (setjmp(zfalrmbuf)) { alarm(0); @@ -1479,7 +1479,7 @@ zfread(int fd, char *bf, off_t sz, int tmout) } zfalarm(tmout); - ret = read(fd, bf, sz); + ret = ztrapread(fd, bf, sz); /* we don't bother turning off the whole alarm mechanism here */ alarm(0); @@ -1495,7 +1495,7 @@ zfwrite(int fd, char *bf, off_t sz, int tmout) int ret; if (!tmout) - return write(fd, bf, sz); + return ztrapwrite(fd, bf, sz); if (setjmp(zfalrmbuf)) { alarm(0); @@ -1504,7 +1504,7 @@ zfwrite(int fd, char *bf, off_t sz, int tmout) } zfalarm(tmout); - ret = write(fd, bf, sz); + ret = ztrapwrite(fd, bf, sz); /* we don't bother turning off the whole alarm mechanism here */ alarm(0); @@ -2846,7 +2846,7 @@ zfclose(int leaveparams) if (!zfnopen) { /* Write the final status in case this is a subshell */ lseek(zfstatfd, zfsessno*sizeof(int), 0); - write(zfstatfd, zfstatusp+zfsessno, sizeof(int)); + ztrapwrite(zfstatfd, zfstatusp+zfsessno, sizeof(int)); close(zfstatfd); zfstatfd = -1; @@ -3123,7 +3123,7 @@ bin_zftp(char *name, char **args, char *ops, int func) /* Get the status in case it was set by a forked process */ int oldstatus = zfstatusp[zfsessno]; lseek(zfstatfd, 0, 0); - read(zfstatfd, zfstatusp, sizeof(int)*zfsesscnt); + ztrapread(zfstatfd, zfstatusp, sizeof(int)*zfsesscnt); if (zfsess->cfd != -1 && (zfstatusp[zfsessno] & ZFST_CLOS)) { /* got closed in subshell without us knowing */ zcfinish = 2; @@ -3212,7 +3212,7 @@ bin_zftp(char *name, char **args, char *ops, int func) * but only for the active session. */ lseek(zfstatfd, zfsessno*sizeof(int), 0); - write(zfstatfd, zfstatusp+zfsessno, sizeof(int)); + ztrapwrite(zfstatfd, zfstatusp+zfsessno, sizeof(int)); } return ret; } diff --git a/Src/Modules/zpty.c b/Src/Modules/zpty.c index d25c3a865..e76411a8b 100644 --- a/Src/Modules/zpty.c +++ b/Src/Modules/zpty.c @@ -536,7 +536,7 @@ ptywritestr(Ptycmd cmd, char *s, int len) for (; !errflag && !breaks && !retflag && !contflag && len; len -= written, s += written) { - if ((written = write(cmd->fd, s, len)) < 0 && cmd->nblock && + if ((written = ztrapwrite(cmd->fd, s, len)) < 0 && cmd->nblock && #ifdef EWOULDBLOCK errno == EWOULDBLOCK #else @@ -578,7 +578,7 @@ ptywrite(Ptycmd cmd, char **args, int nonl) int n; char buf[BUFSIZ]; - while ((n = read(0, buf, BUFSIZ)) > 0) + while ((n = ztrapread(0, buf, BUFSIZ)) > 0) if (ptywritestr(cmd, buf, n)) return 1; } diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index b2d075f91..b2a662072 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -313,11 +313,17 @@ static int breakread(int fd, char *buf, int n) { fd_set f; + int ret; FD_ZERO(&f); FD_SET(fd, &f); - return (select(fd + 1, (SELECT_ARG_2_T) & f, NULL, NULL, NULL) == -1 ? - EOF : read(fd, buf, n)); + + ALLOWTRAPS { + ret = (select(fd + 1, (SELECT_ARG_2_T) & f, NULL, NULL, NULL) == -1 ? + EOF : read(fd, buf, n)); + } DISALLOWTRAPS; + + return ret; } # define read breakread @@ -388,7 +394,7 @@ getkey(int keytmout) # else ioctl(SHTTY, TCSETA, &ti.tio); # endif - r = read(SHTTY, &cc, 1); + r = ztrapread(SHTTY, &cc, 1); # ifdef HAVE_TERMIOS_H tcsetattr(SHTTY, TCSANOW, &shttyinfo.tio); # else @@ -398,7 +404,10 @@ getkey(int keytmout) # endif #endif } - while ((r = read(SHTTY, &cc, 1)) != 1) { + for (;;) { + r = ztrapread(SHTTY, &cc, 1); + if (r == 1) + break; if (r == 0) { /* The test for IGNOREEOF was added to make zsh ignore ^Ds that were typed while commands are running. Unfortuantely @@ -1083,7 +1092,7 @@ zleaftertrap(Hookdef dummy, void *dat) static struct builtin bintab[] = { BUILTIN("bindkey", 0, bin_bindkey, 0, -1, 0, "evaMldDANmrsLR", NULL), BUILTIN("vared", 0, bin_vared, 1, 7, 0, NULL, NULL), - BUILTIN("zle", 0, bin_zle, 0, -1, 0, "lDANCLmMgGcRaU", NULL), + BUILTIN("zle", 0, bin_zle, 0, -1, 0, "lDANCLmMgGcRaUI", NULL), }; /* The order of the entries in this table has to match the *HOOK diff --git a/Src/Zle/zle_thingy.c b/Src/Zle/zle_thingy.c index 7e81e2f88..f5acb73b4 100644 --- a/Src/Zle/zle_thingy.c +++ b/Src/Zle/zle_thingy.c @@ -339,6 +339,7 @@ bin_zle(char *name, char **args, char *ops, int func) { 'R', bin_zle_refresh, 0, -1 }, { 'M', bin_zle_mesg, 1, 1 }, { 'U', bin_zle_unget, 1, 1 }, + { 'I', bin_zle_invalidate, 0, 0 }, { 0, bin_zle_call, 0, -1 }, }; struct opn const *op, *opp; @@ -396,10 +397,8 @@ bin_zle_refresh(char *name, char **args, char *ops, char func) char *s = statusline; int sl = statusll, ocl = clearlist; - if (!zleactive) { - zwarnnam(name, "can only be called from widget function", NULL, 0); + if (!zleactive) return 1; - } statusline = NULL; statusll = 0; if (*args) { @@ -656,6 +655,17 @@ bin_zle_call(char *name, char **args, char *ops, char func) return ret; } +/**/ +static int +bin_zle_invalidate(char *name, char **args, char *ops, char func) +{ + if (zleactive) { + trashzle(); + return 0; + } else + return 1; +} + /*******************/ /* initialiasation */ /*******************/ diff --git a/Src/builtin.c b/Src/builtin.c index afd140d3c..d1cea8393 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -3218,7 +3218,7 @@ zexit(int val, int from_signal) checkjobs(); /* check if any jobs are running/stopped */ if (stopmsg) { stopmsg = 2; - LASTALLOC_RETURN; + return; } } if (in_exit++ && from_signal) @@ -3240,7 +3240,7 @@ zexit(int val, int from_signal) } } if (sigtrapped[SIGEXIT]) - dotrap(SIGEXIT); + dotrap(SIGEXIT, 1); runhookdef(EXITHOOK, NULL); if (mypid != getpid()) _exit(val); @@ -3486,7 +3486,7 @@ bin_read(char *name, char **args, char *ops, int func) *bptr = readchar; val = 1; readchar = -1; - } else if ((val = read(readfd, bptr, nchars)) <= 0) + } else if ((val = ztrapread(readfd, bptr, nchars)) <= 0) break; /* decrement number of characters read from number required */ @@ -3500,7 +3500,7 @@ bin_read(char *name, char **args, char *ops, int func) if (!izle && !ops['u'] && !ops['p']) { /* dispose of result appropriately, etc. */ if (isem) - while (val > 0 && read(SHTTY, &d, 1) == 1 && d != '\n'); + while (val > 0 && ztrapread(SHTTY, &d, 1) == 1 && d != '\n'); else settyinfo(&shttyinfo); if (haso) { @@ -3733,6 +3733,7 @@ static int zread(int izle, int *readchar) { char cc, retry = 0; + int ret; if (izle) { int c = getkeyptr(0); @@ -3756,7 +3757,8 @@ zread(int izle, int *readchar) } for (;;) { /* read a character from readfd */ - switch (read(readfd, &cc, 1)) { + ret = ztrapread(readfd, &cc, 1); + switch (ret) { case 1: /* return the character read */ return STOUC(cc); diff --git a/Src/exec.c b/Src/exec.c index d0787f222..267625807 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -738,6 +738,7 @@ static int execsimple(Estate state) { wordcode code = *state->pc++; + int lv; if (errflag) return (lastval = 1); @@ -754,9 +755,13 @@ execsimple(Estate state) fputc('\n', xtrerr); fflush(xtrerr); } - return (lastval = (errflag ? errflag : cmdoutval)); + lv = (errflag ? errflag : cmdoutval); } else - return (lastval = (execfuncs[code - WC_CURSH])(state, 0)); + lv = (execfuncs[code - WC_CURSH])(state, 0); + + RUNTRAPS(); + + return lastval = lv; } /* Main routine for executing a list. * @@ -887,19 +892,19 @@ sublist_done: noerrexit = oldnoerrexit; if (sigtrapped[SIGDEBUG]) - dotrap(SIGDEBUG); + dotrap(SIGDEBUG, 1); /* Check whether we are suppressing traps/errexit * * (typically in init scripts) and if we haven't * * already performed them for this sublist. */ if (!noerrexit && !donetrap) { if (sigtrapped[SIGZERR] && lastval) { - dotrap(SIGZERR); + dotrap(SIGZERR, 1); donetrap = 1; } if (lastval && isset(ERREXIT)) { if (sigtrapped[SIGEXIT]) - dotrap(SIGEXIT); + dotrap(SIGEXIT, 1); if (mypid != getpid()) _exit(lastval); else @@ -1181,9 +1186,10 @@ execpline2(Estate state, wordcode pcode, else list_pipe_text[0] = '\0'; } - if (WC_PIPE_TYPE(pcode) == WC_PIPE_END) + if (WC_PIPE_TYPE(pcode) == WC_PIPE_END) { execcmd(state, input, output, how, last1 ? 1 : 2); - else { + RUNTRAPS(); + } else { int old_list_pipe = list_pipe; Wordcode next = state->pc + (*state->pc); wordcode code; @@ -1218,12 +1224,14 @@ execpline2(Estate state, wordcode pcode, entersubsh(how, 2, 0); close(synch[1]); execcmd(state, input, pipes[1], how, 0); + RUNTRAPS(); _exit(lastval); } } else { /* otherwise just do the pipeline normally. */ subsh_close = pipes[0]; execcmd(state, input, pipes[1], how, 0); + RUNTRAPS(); } zclose(pipes[1]); state->pc = next; diff --git a/Src/init.c b/Src/init.c index 341173889..290384c1a 100644 --- a/Src/init.c +++ b/Src/init.c @@ -170,7 +170,7 @@ loop(int toplevel, int justonce) } if (isset(SINGLECOMMAND) && toplevel) { if (sigtrapped[SIGEXIT]) - dotrap(SIGEXIT); + dotrap(SIGEXIT, 1); exit(lastval); } if (justonce) @@ -1107,6 +1107,7 @@ fallback_zleread(char *lp, char *rp, int ha) pptbuf = unmetafy(promptexpand(lp, 0, NULL, NULL), &pptlen); write(2, (WRITE_ARG_2_T)pptbuf, pptlen); free(pptbuf); + return (unsigned char *)shingetline(); } diff --git a/Src/input.c b/Src/input.c index 8f33e3631..e82d25011 100644 --- a/Src/input.c +++ b/Src/input.c @@ -141,7 +141,9 @@ shingetline(void) for (;;) { do { errno = 0; - c = fgetc(bshin); + ALLOWTRAPS { + c = fgetc(bshin); + } DISALLOWTRAPS; } while (c < 0 && errno == EINTR); if (c < 0 || c == '\n') { if (c == '\n') diff --git a/Src/jobs.c b/Src/jobs.c index a938e774b..28246d422 100644 --- a/Src/jobs.c +++ b/Src/jobs.c @@ -378,7 +378,7 @@ update_job(Job jn) zrefresh(); } if (sigtrapped[SIGCHLD] && job != thisjob) - dotrap(SIGCHLD); + dotrap(SIGCHLD, 0); /* When MONITOR is set, the foreground process runs in a different * * process group from the shell, so the shell will not receive * @@ -389,7 +389,7 @@ update_job(Job jn) if (sig == SIGINT || sig == SIGQUIT) { if (sigtrapped[sig]) { - dotrap(sig); + dotrap(sig, 0); /* We keep the errflag as set or not by dotrap. * This is to fulfil the promise to carry on * with the jobs if trap returns zero. @@ -878,7 +878,9 @@ waitforpid(pid_t pid) else kill(pid, SIGCONT); - child_suspend(SIGINT); + ALLOWTRAPS { + child_suspend(SIGINT); + } DISALLOWTRAPS; child_block(); } child_unblock(); @@ -900,7 +902,9 @@ waitjob(int job, int sig) while (!errflag && jn->stat && !(jn->stat & STAT_DONE) && !(interact && (jn->stat & STAT_STOPPED))) { - child_suspend(sig); + ALLOWTRAPS { + child_suspend(sig); + } DISALLOWTRAPS; /* Commenting this out makes ^C-ing a job started by a function stop the whole function again. But I guess it will stop something else from working properly, we have to find out @@ -1363,7 +1367,7 @@ bin_fg(char *name, char **argv, char *ops, int func) killjb(jobtab + job, SIGCONT); } if (func == BIN_WAIT) - waitjob(job, SIGINT); + waitjob(job, SIGINT); if (func != BIN_BG) { waitjobs(); retval = lastval2; diff --git a/Src/signals.c b/Src/signals.c index b397e1047..693337dbd 100644 --- a/Src/signals.c +++ b/Src/signals.c @@ -497,7 +497,7 @@ handler(int sig) case SIGHUP: if (sigtrapped[SIGHUP]) - dotrap(SIGHUP); + dotrap(SIGHUP, 0); else { stopmsg = 1; zexit(SIGHUP, 1); @@ -506,7 +506,7 @@ handler(int sig) case SIGINT: if (sigtrapped[SIGINT]) - dotrap(SIGINT); + dotrap(SIGINT, 0); else { if ((isset(PRIVILEGED) || isset(RESTRICTED)) && isset(INTERACTIVE) && noerrexit < 0) @@ -523,14 +523,14 @@ handler(int sig) case SIGWINCH: adjustwinsize(1); /* check window size and adjust */ if (sigtrapped[SIGWINCH]) - dotrap(SIGWINCH); + dotrap(SIGWINCH, 0); break; #endif case SIGALRM: if (sigtrapped[SIGALRM]) { int tmout; - dotrap(SIGALRM); + dotrap(SIGALRM, 0); if ((tmout = getiparam("TMOUT"))) alarm(tmout); /* reset the alarm */ @@ -549,7 +549,7 @@ handler(int sig) break; default: - dotrap(sig); + dotrap(sig, 0); break; } /* end of switch(sig) */ @@ -907,7 +907,9 @@ dotrapargs(int sig, int *sigtr, void *sigfn) * function will test for this, but this way we keep status flags * * intact without working too hard. Special cases (e.g. calling * * a trap for SIGINT after the error flag was set) are handled * - * by the calling code. (PWS 1995/06/08). */ + * by the calling code. (PWS 1995/06/08). * + * * + * This test is now replicated in dotrap(). */ if ((*sigtr & ZSIG_IGNORED) || !sigfn || errflag) return; @@ -953,15 +955,67 @@ dotrapargs(int sig, int *sigtr, void *sigfn) breaks = loops; } + /* + * If zle was running while the trap was executed, see if we + * need to restore the display. + */ + if (zleactive && resetneeded) + zrefresh(); + if (*sigtr != ZSIG_IGNORED) *sigtr &= ~ZSIG_IGNORED; } -/* Standard call to execute a trap for a given signal */ +/* != 0 if trap handlers can be called immediately */ + +/**/ +mod_export int trapsallowed; + +/* Queued traps and allocated length of queue. */ + +static int *trapqueue, trapqlen; + +/* Number of used slots in trap queue. */ + +/**/ +mod_export int trapqused; + +/* Standard call to execute a trap for a given signal. The second + * argument should be zero if we may need to put the trap on the queue + * and 1 if it may be called immediately. It should never be set to + * anything less than zero, that's used internally. */ /**/ void -dotrap(int sig) +dotrap(int sig, int now) { - dotrapargs(sig, sigtrapped+sig, sigfuncs[sig]); + /* Copied from dotrapargs(). */ + if ((sigtrapped[sig] & ZSIG_IGNORED) || !sigfuncs[sig] || errflag) + return; + + if (now || trapsallowed) { + if (now < 0) + RUNTRAPS(); + dotrapargs(sig, sigtrapped+sig, sigfuncs[sig]); + } else { + if (trapqlen == trapqused) + trapqueue = (int *) zrealloc(trapqueue, (trapqlen += 32)); + trapqueue[trapqused++] = sig; + } +} + +/**/ +mod_export void +doqueuedtraps(void) +{ + int sig, ota = trapsallowed; + + trapsallowed = 1; + while (trapqused) { + trapqused--; + sig = *trapqueue; + memcpy(trapqueue, trapqueue + 1, trapqused * sizeof(int)); + dotrap(sig, -1); + } + trapsallowed = ota; } diff --git a/Src/signals.h b/Src/signals.h index b6485e6b3..45978dd1e 100644 --- a/Src/signals.h +++ b/Src/signals.h @@ -56,8 +56,8 @@ # define sigismember(s,n) ((*(s) & (1 << ((n) - 1))) != 0) #endif /* ifndef POSIX_SIGNALS */ -#define child_block() signal_block(signal_mask(SIGCHLD)) -#define child_unblock() signal_unblock(signal_mask(SIGCHLD)) +#define child_block() signal_block(sigchld_mask) +#define child_unblock() signal_unblock(sigchld_mask) #define child_suspend(S) signal_suspend(SIGCHLD, S) /* ignore a signal */ @@ -92,3 +92,34 @@ } \ } \ } while (0) + + +/* Make some signal functions faster. */ + +#ifdef POSIX_SIGNALS +#define signal_block(S) \ + ((dummy_sigset1 = (S)), \ + sigprocmask(SIG_BLOCK, &dummy_sigset1, &dummy_sigset2), \ + dummy_sigset2) +#else +# ifdef BSD_SIGNALS +#define signal_block(S) sigblock(S) +# else +extern sigset_t signal_block _((sigset_t)); +# endif /* BSD_SIGNALS */ +#endif /* POSIX_SIGNALS */ + +#ifdef POSIX_SIGNALS +#define signal_unblock(S) \ + ((dummy_sigset1 = (S)), \ + sigprocmask(SIG_UNBLOCK, &dummy_sigset1, &dummy_sigset2), \ + dummy_sigset2) +#else +extern sigset_t signal_unblock _((sigset_t)); +#endif /* POSIX_SIGNALS */ + +#define RUNTRAPS() do { if (trapqused) doqueuedtraps(); } while (0) +#define ALLOWTRAPS do { RUNTRAPS(); trapsallowed++; do +#define DISALLOWTRAPS while (0); RUNTRAPS(); trapsallowed--; } while (0) +#define ALLOWTRAPS_RETURN(V) \ + do { RUNTRAPS(); trapsallowed--; return (V); } while (0) diff --git a/Src/utils.c b/Src/utils.c index b7b8d1295..e61e84a03 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -1417,13 +1417,39 @@ checkrmall(char *s) return (getquery("ny", 1) == 'y'); } +/**/ +mod_export int +ztrapread(int fd, char *buf, int len) +{ + int ret; + + ALLOWTRAPS { + ret = read(fd, buf, len); + } DISALLOWTRAPS; + + return ret; +} + +/**/ +mod_export int +ztrapwrite(int fd, char *buf, int len) +{ + int ret; + + ALLOWTRAPS { + ret = write(fd, buf, len); + } DISALLOWTRAPS; + + return ret; +} + /**/ int read1char(void) { char c; - while (read(SHTTY, &c, 1) != 1) { + while (ztrapread(SHTTY, &c, 1) != 1) { if (errno != EINTR || errflag || retflag || breaks || contflag) return -1; } @@ -1440,7 +1466,7 @@ noquery(int purge) ioctl(SHTTY, FIONREAD, (char *)&val); if (purge) { for (; val; val--) - read(SHTTY, &c, 1); + ztrapread(SHTTY, &c, 1); } #endif diff --git a/Src/zsh.h b/Src/zsh.h index cdf1ed489..c4642434b 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -1627,8 +1627,6 @@ struct heap { #endif ; -# define LASTALLOC_RETURN return - # define NEWHEAPS(h) do { Heap _switch_oldheaps = h = new_heaps(); do # define OLDHEAPS while (0); old_heaps(_switch_oldheaps); } while (0); -- cgit 1.4.1