Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
PATCH: zpty polling
- X-seq: zsh-workers 24460
- From: Peter Stephenson <pws@xxxxxxx>
- To: zsh-workers@xxxxxxxxxx (Zsh hackers list)
- Subject: PATCH: zpty polling
- Date: Thu, 24 Jan 2008 18:40:05 +0000
- Mailing-list: contact zsh-workers-help@xxxxxxxxxx; run by ezmlm
"zpty -rt" is supposed to return if there's nothing to do, but it's half
implemented: it tests before the *first* read, but it can block if it's
read a character, needs another one, and fails to read it. This happens
in particular if there was no newline, since unless it's matching a
pattern it will wait for one. (I'm assuming throughout at that reads
are in blocking mode (the default), otherwise this behaviour is
irrelevant.)
I would guess nobody wants the current "poll but get stuck anyway"
behaviour, so this makes it always poll before reading. I've borrowed
the code from inside poll_read() to make it a bit more efficient;
actually, it ought to be good enough just to do the non-blocking read
bit without the select or FIONREAD before. I didn't dare do this when
the current system seems to be working.
-t will now interact differently with a pattern argument: it will no
longer block if there was something available but not what you wanted,
and then no more was available. This is already the behaviour when the
command exits. I don't think the previous behaviour was satisfactory
since there's a race: if no input at all was there, it would return 1
immediately, otherwise it would consume that input and block waiting for
the pattern.
I discovered this when thinking about writing a zsh front-end to
smbclient, which is a bit clumsy. Unfortunately a suitably recent
version of smbclient seems to be the only way to get at DFS filesystems
at the moment; mounting a CIFS share where the files are actually
provided by DFS doesn't yet work. If anyone happens to know of a better
way of doing this I'm all ears, otherwise if I come up with something
I'll post it. (Possibly I should be using non-blocking mode for this.)
Index: Doc/Zsh/mod_zpty.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/mod_zpty.yo,v
retrieving revision 1.6
diff -u -r1.6 mod_zpty.yo
--- Doc/Zsh/mod_zpty.yo 1 Apr 2005 12:04:22 -0000 1.6
+++ Doc/Zsh/mod_zpty.yo 24 Jan 2008 18:31:49 -0000
@@ -64,7 +64,10 @@
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
Index: Src/utils.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/utils.c,v
retrieving revision 1.175
diff -u -r1.175 utils.c
--- Src/utils.c 17 Dec 2007 18:34:25 -0000 1.175
+++ Src/utils.c 24 Jan 2008 18:31:53 -0000
@@ -1886,7 +1886,7 @@
}
/**/
-int
+mod_export int
setblock_fd(int turnonblocking, int fd, long *modep)
{
#ifdef O_NDELAY
Index: Src/Modules/zpty.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Modules/zpty.c,v
retrieving revision 1.36
diff -u -r1.36 zpty.c
--- Src/Modules/zpty.c 6 Jul 2007 21:52:40 -0000 1.36
+++ Src/Modules/zpty.c 24 Jan 2008 18:31:53 -0000
@@ -468,7 +468,7 @@
}
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 @@
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 @@
}
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;
--
Peter Stephenson <pws@xxxxxxx> Software Engineer
CSR PLC, Churchill House, Cambridge Business Park, Cowley Road
Cambridge, CB4 0WZ, UK Tel: +44 (0)1223 692070
Messages sorted by:
Reverse Date,
Date,
Thread,
Author