diff options
| author | Mikael Magnusson <mikachu@gmail.com> | 2026-06-15 18:18:38 +0200 |
|---|---|---|
| committer | Mikael Magnusson <mikachu@gmail.com> | 2026-07-04 19:56:26 +0200 |
| commit | 4b4ebccaa9666c608f18f73c5b8102cbfc8e8deb (patch) | |
| tree | 824833e121c1784a0f23770b3d7f9af612c7bc09 | |
| parent | unposted: complete more media file types (diff) | |
| download | zsh-4b4ebccaa9666c608f18f73c5b8102cbfc8e8deb.tar zsh-4b4ebccaa9666c608f18f73c5b8102cbfc8e8deb.tar.gz zsh-4b4ebccaa9666c608f18f73c5b8102cbfc8e8deb.tar.bz2 zsh-4b4ebccaa9666c608f18f73c5b8102cbfc8e8deb.tar.lz zsh-4b4ebccaa9666c608f18f73c5b8102cbfc8e8deb.tar.xz zsh-4b4ebccaa9666c608f18f73c5b8102cbfc8e8deb.tar.zst zsh-4b4ebccaa9666c608f18f73c5b8102cbfc8e8deb.zip | |
54783: improve checkptycmd
With the previous (and now fallback) version of checkptycmd(), doing
this:
zpty foo 'while read; do echo hi; done'
zpty (or zpty -t foo)
would hang forever, which seems counterintuitive to the purpose of
listing processes (or testing if a process is running).
| -rw-r--r-- | ChangeLog | 5 | ||||
| -rw-r--r-- | Src/Modules/zpty.c | 61 | ||||
| -rw-r--r-- | Test/V08zpty.ztst | 12 |
3 files changed, 78 insertions, 0 deletions
@@ -1,3 +1,8 @@ +2026-07-04 Mikael Magnusson <mikachu@gmail.com> + + * 54783: Src/Modules/zpty.c, Test/V08zpty.ztst: improve + checkptycmd + 2026-07-03 Oliver Kiddle <opk@zsh.org> * unposted: Completion/X/Command/_mplayer, Completion/X/Command/_xv: diff --git a/Src/Modules/zpty.c b/Src/Modules/zpty.c index 6e201e76b..2f9b80f40 100644 --- a/Src/Modules/zpty.c +++ b/Src/Modules/zpty.c @@ -37,6 +37,13 @@ #endif #endif +#ifdef HAVE_POLL_H +# include <poll.h> +#endif +#if defined(HAVE_POLL) && !defined(POLLIN) +# undef HAVE_POLL +#endif + /* The number of bytes we normally read when given no pattern and the * upper bound on the number of bytes we read (even if we are give a * pattern). */ @@ -529,6 +536,59 @@ deleteallptycmds(void) /**** a better process handling would be nice */ +#ifdef HAVE_POLL +static void +checkptycmd(Ptycmd cmd) +{ + struct pollfd pfd; + + if (cmd->fin) + return; + pfd.fd = cmd->fd; + pfd.events = POLLIN; + pfd.revents = 0; + if (poll(&pfd, 1, 0) <= 0) + return; /* no events: slave still open, not finished */ + if (pfd.revents & POLLIN) + return; /* data available, not finished */ + /* POLLHUP without POLLIN: slave closed, no data */ + cmd->fin = 1; + zclose(cmd->fd); +} +#elif defined(FIONREAD) +static void +checkptycmd(Ptycmd cmd) +{ + int val = 0, select_ret = 0; + + if (cmd->fin) + return; +#ifdef HAVE_SELECT + { + fd_set fds; + struct timeval tv; + int ret; + + FD_ZERO(&fds); + FD_SET(cmd->fd, &fds); + tv.tv_sec = 0; + tv.tv_usec = 0; + ret = select(cmd->fd + 1, (SELECT_ARG_2_T) &fds, NULL, NULL, &tv); + if (ret > 0 && FD_ISSET(cmd->fd, &fds)) { + /* either there are bytes, or the process exited */ + select_ret = 1; + } + } +#endif + if (ioctl(cmd->fd, FIONREAD, (char *) &val) == 0 && val > 0) + return; /* data available, not finished */ + /* No data (or ioctl failed): check if process is dead */ + if (select_ret || kill(cmd->pid, 0) < 0) { + cmd->fin = 1; + zclose(cmd->fd); + } +} +#else static void checkptycmd(Ptycmd cmd) { @@ -545,6 +605,7 @@ checkptycmd(Ptycmd cmd) } cmd->read = (int) c; } +#endif static int ptyread(char *nam, Ptycmd cmd, char **args, int noblock, int mustmatch) diff --git a/Test/V08zpty.ztst b/Test/V08zpty.ztst index 057db2e18..cad6bb9bd 100644 --- a/Test/V08zpty.ztst +++ b/Test/V08zpty.ztst @@ -25,3 +25,15 @@ zpty -d cat 0:zpty with a process that does not set up the terminal: write via stdin >a line of text + + zpty loop 'while read; do echo hello; done' + zpty -w loop hi + zpty -rt loop | tr -d $'\r' + zpty -w loop hi + zpty -t loop + zpty -rt loop | tr -d $'\r' + zpty -rt loop + zpty -d loop +0:zpty doesn't duplicate data +>hello +>hello |
