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