termios & non-blocking I/O

Terry Lambert tlambert2 at mindspring.com
Wed Apr 9 16:25:41 PDT 2003


Alex Semenyaka wrote:
> Yes it is permissable, it is just in the disagreement with the behaviour
> when MIN>0 and TIME=0.  Don't you think the behaviour in the (TIME=0, MIN>0)
> and (TIME>0, MIN=0) should be consistent somehow?

Consistent with what?

The cases are:

	MIN	TIME
1)	>0	>0	Interbyte timer; after 1 byte received, timer
			is started; if MIN bytes received before timer
			is statisfied, return.  If another byte is
			received, timer is reset; if timer expires,
			read is satisfied.
2)	>0	=0	Pending read is not satisfied until MIN bytes
			received.
3)	=0	>0	NOT interbyte timer; read is satisfied on a
			single byte received or timer expired.
4)	=0	=0	Polling read; available bytes up to number of
			requested bytes is returned, and read is always
			satisfied.

The specification further indicates that the resolution on the TIME
timer is .1 *SECOND*.

This basically means that, if it is handled in the kernel, case #1
could *block all other threads indefinitely*, up to .1S * MIN, which
for MIN=100, TIME=1 is *10 FULL SECONDS*.  That's *obviously*
unacceptable.  I think it is impossible to implement case #1 correctly
with NBIO enabled, and would convert it to case #4, and implement the
TIME in user space in libc_r.

Case #2 is still not correctly handled at all by your proposed change;
libc_r work is required to avoid stalling until input is present; the
correct return on NBIO is pretty obviously "EAGAIN,-1"; HOWEVER, you
may have received *some* input data, but not MIN worth of input data;
returning some number < MIN violates the interface contract; so does
losing the data.

Case #3 is a full read timer for one byte; also not correctly handled
in the face of the proposed change.  For a TIME=100, we are talking
about stalling all threads for 100 seconds; the correct return is

Case #4 is polling I/O; it's trivial to implement in libc_r.


I think the big issue here is the "short read" case in #2.  The
correct thing, to me, would be to return the number of bytes read
on the NBIO descriptor, and let the libc_r figure out that that
number is less than the number requested.


> Then, changing the kernel behavour is simple, straightforward and also
> PERFECTLY permissable while tracing the situation with the descriptor mode
> in libc_r is not so simple. To be fair such tracing might be a difficult
> task.

Rule of thumb: If it adds latency, which is always annoying; if
it can add an arbitray number of seconds of latency, it's
unacceptable.


> No, sorry, you have missed my point. Sure I do NOT propose to block
> the input when TIME>0. I propose to return -1/EAGAIN (as in the
> MIN>0 case) instead of 0 (as it is done now). That is what I called
> "the second way". And in this case both libc_r and program can
> easely distinct between EOF and nothing-to-read situation and handle
> them properly. Also all other threads will not be stucked.

The problem with this is case #2 with some number of characters less
than MIN.  For example, let us propose a MIN of 10, with 3 characters
pending input at the time the read is called; you have two cases:

#1	TIME>0		I argue that this is impossible to implement
			in the presence of NBIO, since you can not
			return both the value of the short read, and
			the fact that the timer would result in a
			block, simultaneously.  Best approach is to
			cause an error, EAGAIN,-1.

#2	TIME=0		I argue that the value of the short read should
			be returned, rather than an error.  At least in
			this approach, you can identify in libc_r that
			a short read has occurred, and that the thread
			must be rescheduled in order to complete the
			remaining read, up to MIN.

These cases are somewhat contrived, in that use of MIN/TIME values,
in other words non-canonical input processing, is at odds with the
threads model.  At best, combining them provides for the ability to
poll (#4: an incredibly bad thing in a threads environment, since a
user space scheduler will not necessarily ever schedule another thread
to run, if there is a polling thread), and the ability to ask for "X
or more characters, up to Y, where MIN=Z and the character count to
read(2)=Y" (#2).

Probably the only legitimate use in the presence of threads is #2, to
get "allowed and expected bounded read lengths", and that's the one
you want to change so that it won't work any more.

-- Terry


More information about the freebsd-threads mailing list