termios & non-blocking I/O

Bruce Evans bde at zeta.org.au
Tue Apr 8 12:33:35 PDT 2003


On Tue, 8 Apr 2003, Yar Tikhiy wrote:

> ...
> Let's consider a non-blocking file descriptor that correspons to a
> terminal in raw mode.  Let's also assume read(2) is issued on it
> when there is no data to read.
>
> If for this terminal MIN > 0 and TIME == 0, read(2) will return -1
> and set errno to EAGAIN.
>
> OTOH, if MIN == 0 and TIME > 0, read(2) will return 0.
>
> While not in disagreement with POSIX[1], such a behaviour has at
> least one unwelcome consequence:  If a program has been compiled
> with ``-pthread'', the TIME counter won't work on terminal descriptors
> that are in blocking mode from the program's point of view -- read(2)
> will instantly return 0 on them.  That is because the following
> scenario will happen:

The spec is not very clear, but I think it means to say to return
-1/EAGAIN (it says that first).

I seem to have help break this in FreeBSD-1.  Rev.1.17 of tty.c fixed
the complementary bug of returning EWOULDBLOCK after a timeout, and
rev.1.32 (the last commit to tty.c in FreeBSD-1) "finished" implementing
MIN/TIME and didn't handle this case quite right.  The MIN/TIME changes
are all collected together with no history in rev.1.8 of tty.c in
FreeBSD-2.

> 1) libc_r sets non-blocking mode on a descriptor as soon as a device
> is opened (that is how i/o in user-land threads work);
> 2) the program sets the TIME counter through tcsetattr(3);
> 3) the program issues read(2), which ends up in the actual read()
> syscall, which in turn returns 0 to libc_r (assuming there is no
> data to read);
> 4) libc_r thinks this is the EOF indicator, so it instantly returns
> 0 to the program;
> 5) the program breaks.
>
> Notice, that MIN works right with libc_r since read() syscall will
> return -1/EAGAIN, which is correctly understood by libc_r: it will
> block the current thread until there is data to read.

Does it keep the fd in non-blocking mode and wait for the data using
select() or similar?  This wouldn't work so well for TIME because
select() doesn't really understand MIN/TIME; in particular, TIME
has no effect on select() in the MIN == 0 && TIME > 0 case.  I
think libc_r would have to duplicate most of the kernel's MIN/TIME
stuff to fake things properly.  It correctly doesn't go near this.

Bruce


More information about the freebsd-arch mailing list