From b5570971efc9cd3f41f2f89bdd287a72866edaf7 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Fri, 25 Jan 2008 16:48:22 +0000 Subject: 24460: make zpty -rt more consistent by polling before every byte --- ChangeLog | 6 ++++++ Doc/Zsh/mod_zpty.yo | 5 ++++- Src/Modules/zpty.c | 46 +++++++++++++++++++++++++++++++++++++++++----- Src/utils.c | 2 +- 4 files changed, 52 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index d3035a1a4..47f5f51ba 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2008-01-25 Peter Stephenson + + * 24460: Doc/Zsh/mod_zpty.yo, Src/utils.c, Src/Modules/zpty.c: + make "zpty -rt" more consistent by polling before every byte, + not just the first. + 2008-01-25 Clint Adams * 24464: Completion/Unix/Command/_git: remove trailing whitespace. diff --git a/Doc/Zsh/mod_zpty.yo b/Doc/Zsh/mod_zpty.yo index 39347c116..5a5459179 100644 --- a/Doc/Zsh/mod_zpty.yo +++ b/Doc/Zsh/mod_zpty.yo @@ -64,7 +64,10 @@ is tt(2) if this is because the command has finished. If the tt(-r) option is combined with the tt(-t) option, tt(zpty) tests whether output is available before trying to read. If no output is -available, tt(zpty) immediately returns the status tt(1). +available, tt(zpty) immediately returns the status tt(1). When used +with a var(pattern), the behaviour on a failed poll is similar to +when the command has exited: the return value is zero if at least +one character could still be read even if the pattern failed to match. ) item(tt(zpty) tt(-t) var(name))( The tt(-t) option without the tt(-r) option can be used to test diff --git a/Src/Modules/zpty.c b/Src/Modules/zpty.c index 7e140102e..9bd14985e 100644 --- a/Src/Modules/zpty.c +++ b/Src/Modules/zpty.c @@ -468,7 +468,7 @@ checkptycmd(Ptycmd cmd) } static int -ptyread(char *nam, Ptycmd cmd, char **args) +ptyread(char *nam, Ptycmd cmd, char **args, int noblock) { int blen, used, seen = 0, ret = 0; char *buf; @@ -509,6 +509,45 @@ ptyread(char *nam, Ptycmd cmd, char **args) cmd->read = -1; } do { + if (noblock && cmd->read == -1) { + int pollret; + /* + * Check there is data available. Borrowed from + * poll_read() in utils.c and simplified. + */ +#ifdef HAVE_SELECT + fd_set foofd; + struct timeval expire_tv; + expire_tv.tv_sec = 0; + expire_tv.tv_usec = 0; + FD_ZERO(&foofd); + FD_SET(cmd->fd, &foofd); + pollret = select(cmd->fd+1, + (SELECT_ARG_2_T) &foofd, NULL, NULL, &expire_tv); +#else +#ifdef FIONREAD + if (ioctl(cmd->fd, FIONREAD, (char *) &val) == 0) + pollret = (val > 0); +#endif +#endif + + if (pollret < 0) { + /* + * See read_poll() for this. + * Last despairing effort to poll: attempt to + * set nonblocking I/O and actually read the + * character. cmd->read stores the character read. + */ + long mode; + + if (setblock_fd(0, cmd->fd, &mode)) + pollret = read(cmd->fd, &cmd->read, 1); + if (mode != -1) + fcntl(cmd->fd, F_SETFL, mode); + } + if (pollret == 0) + break; + } if (!ret) { checkptycmd(cmd); if (cmd->fin) @@ -648,12 +687,9 @@ bin_zpty(char *nam, char **args, Options ops, UNUSED(int func)) } if (p->fin) return 2; - if (OPT_ISSET(ops,'t') && p->read == -1 && - !read_poll(p->fd, &p->read, 0, 0)) - return 1; return (OPT_ISSET(ops,'r') ? - ptyread(nam, p, args + 1) : + ptyread(nam, p, args + 1, OPT_ISSET(ops,'t')) : ptywrite(p, args + 1, OPT_ISSET(ops,'n'))); } else if (OPT_ISSET(ops,'d')) { Ptycmd p; diff --git a/Src/utils.c b/Src/utils.c index 85646d827..edf1ea288 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -1886,7 +1886,7 @@ zstrtol(const char *s, char **t, int base) } /**/ -int +mod_export int setblock_fd(int turnonblocking, int fd, long *modep) { #ifdef O_NDELAY -- cgit 1.4.1