questions about select and non-blocking I/O
Steve Sutphen
steve at alberta.UUCP
Sun Jul 14 17:55:16 AEST 1985
I hope I don't loose my wizards wings over this one. I have been
looking at the rather inelegant code for /etc/telnetd (the same
arguments apply to rlogind and likely the user-interfaces) and have a
couple of questions about `select' (there are several bugs in the
server which I am fixing and they will be posted soon). Here is the
skeleton of the relevant code - I have interspersed my questions in
the code preceeded by a > in column 1.
telnet(net, pty)
{
ioctl(net, FIONBIO, &on); /* set non-blocking I/O */
ioctl(pty, FIONBIO, &on);
for (;;) {
int ibits = 0, obits = 0;
register int c;
/*
* Never look for input if there's still
* stuff in the corresponding output buffer
*/
if (net_queue_not_empty())
obits |= (1 << net);
else
ibits |= (1 << pty);
if (pty_queue_not_empty())
obits |= (1 << pty);
else
ibits |= (1 << net);
if (ncc < 0 && pcc < 0)
break;
select(16, &ibits, &obits, 0, 0);
if (ibits == 0 && obits == 0) {
sleep(5);
continue;
}
> This `sleep' seems really silly - select is perfectly capable of
> waiting for one of the events to come ready. Since none of the
> conditions will change before we get here again I would think that a
> select call with a "wait_until_something_is_ready" (i.e. &NULL) would
> have much less overhead (one would have to check the return code for
> interrrupted system call).
/* Something to read from the network... */
if (ibits & (1 << net)) {
ncc = read(net, netibuf, BUFSIZ);
if (ncc < 0 && errno == EWOULDBLOCK)
ncc = 0;
> doesn't anyone trust `select' to tell the truth? I don't see why we
> need to check for EWOULDBLOCK here since select told us we could do
> the read. Or is there a race condition lurking about.
else {
if (ncc <= 0)
break;
netip = netibuf;
}
}
/* Something to read from the pty... */
if (ibits & (1 << pty)) {
. . . (like above) . . .
}
if (pcc > 0)
copy_pty_chars_to_pty_queue();
if ((obits & (1 << f)) && net_queue_not_empty())
netflush(); /* write to network */
> Since netflush can handle the EWOULDBLOCK condition on the write I
> am not sure that we really need to mess with the select checking of
> `obits'. It would seem like less overhead to just try the output here,
> otherwise the essence of the program flow is:
> ask select if we can read
> read
> ask select if we can write
> write
> if we trust non-blocking I/O (which was set on!!) then we should be
> able to just go ahead and write. Either that or else we didn't need to
> set the non-blocking attribute (and check it!!).
if (ncc > 0)
telrcv(); /* copy net chars to net_queue */
if ((obits & (1 << p)) && pty_queue_not_empty())
ptyflush(); /* write to pty */
}
cleanup();
}
So what is the verdict? is this code as bad as it looks or have I
overlooked the obvious and get my wings clipped.
ihnp4!alberta!steve
More information about the Comp.unix.wizards
mailing list