1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-10-28 05:00:59 +01:00

Sven: 13108: Handle traps synchronously

pws: 13109, 13111: clear up zle display when output produced in trap.
This commit is contained in:
Peter Stephenson 2000-11-11 19:50:27 +00:00
parent 89d480f57d
commit c292a3ae50
15 changed files with 387 additions and 202 deletions

View file

@ -1,3 +1,15 @@
2000-11-11 Peter Stephenson <pws@pwstephenson.fsnet.co.uk>
* 13109, 13111: Doc/Zsh/mod_zle.yo, Src/Zle/zle_main.c,
Src/Zle/zle_thingy.c, Src/signals.c: `zle -I' allows trap code
to clear up display when output occurs in a trap.
* Sven: 13108: Src/Modules/zftp.c, Src/Modules/zpty.c,
Src/Zle/zle_main.c, Src/builtin.c, Src/exec.c, Src/init.c,
Src/input.c, Src/jobs.c, Src/signals.c, Src/signals.h,
Src/utils.c, Src/zsh.h: Execute user traps synchronously if it is
unsafe to execute it directly from the signal handler.
2000-11-09 Clint Adams <schizo@debian.org>
* 13125: Completion/User/_mailboxes: evaluate the mailboxes

View file

@ -198,6 +198,7 @@ xitem(tt(zle) tt(-C) var(widget) var(completion-widget) var(function))
xitem(tt(zle) tt(-R) [ tt(-c) ] [ var(display-string) ] [ var(string) ... ])
xitem(tt(zle) tt(-M) var(string))
xitem(tt(zle) tt(-U) var(string))
xitem(tt(zle) tt(-I))
xitem(tt(zle) var(widget) tt([ -n) var(num) tt(]) tt([ -N ]) var(args) ...)
item(tt(zle))(
The tt(zle) builtin performs a number of different actions concerning
@ -263,6 +264,11 @@ cleared.
Note that this option is only useful for widgets that do not exit
immediately after using it because the strings displayed will be erased
immediately after return from the widget.
This command can safely be called outside user defined widgets; if zle is
active, the display will be refreshed, while if zle is not active, the
command has no effect. In this case there will usually be no other
arguments. The status is zero if zle was active, else one.
)
item(tt(-M) var(string))(
As with the tt(-R) option, the var(string) will be displayed below the
@ -281,6 +287,28 @@ the last string pushed onto the stack will be processed first. However,
the characters in each var(string) will be processed in the order in which
they appear in the string.
)
item(tt(-I))(
Unusually, this option is only useful em(outside) ordinary widget functions.
It invalidates the current zle display in preparation for output; usually
this will be from a trap function. It has no effect if zle is not
active. When a trap exits, the shell checks to see if the display needs
restoring, hence the following will print output in such a way as not to
disturb the line being edited:
example(TRAPUSR1() {
# Invalidate zle display
zle -I
# Show output
print Hello
})
Note that there are better ways of manipulating the display from within zle
widgets. In general, the trap function may need to test whether zle is
loaded before using this method; if it is not, there is no point in loading
it specially since the line editor will not be active.
The status is zero if zle was active, else one.
)
item(var(widget) tt([ -n) var(num) tt(]) tt([ -N ]) var(args) ...)(
Invoke the specified widget. This can only be done when ZLE is
active; normally this will be within a user-defined widget.

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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 ?
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

View file

@ -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 */
/*******************/

View file

@ -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);

View file

@ -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;

View file

@ -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();
}

View file

@ -141,7 +141,9 @@ shingetline(void)
for (;;) {
do {
errno = 0;
ALLOWTRAPS {
c = fgetc(bshin);
} DISALLOWTRAPS;
} while (c < 0 && errno == EINTR);
if (c < 0 || c == '\n') {
if (c == '\n')

View file

@ -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);
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))) {
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

View file

@ -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)
{
/* 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;
}

View file

@ -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)

View file

@ -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

View file

@ -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);