LWP experience -- comments on "select()"

Beau James ultra!beau at ames.arc.nasa.gov
Thu Jul 6 04:15:25 AEST 1989


In SunSpots v8n60, Mike Schwartz writes (regarding select() and LWPs):

--> When the I/O is complete, the UNIX process gets a SIGIO, and the LWP
--> package must decide which thread(s) to awaken.  But as it is currently
--> implemented, every thread that is waiting on SIGIO gets reawakened.
--> The result is that the semantics of select are not correctly
--> implemented -- a thread could return from select with no I/O available,
--> and before the timeout has expired.  This breaks existing applications
--> that you are trying to convert to use LWPs (as I was doing in one
--> case).

If the goal is to have an application that will not pend on an I/O
operation, then the applications were "broken" anyway.  The only way to
eliminate the possibility of waiting on I/O is to use non-blocking I/O,
and be prepared to handle an EWOULDBLOCK, even when using select().

A simple select() construct looks something like:

	select(data available to read?);
	read();

To never block on I/O, the select() outline should be:

	for(;;) {
		select(data available to read?);
		if (read() > 0)
			break;
		else if (errno == EWOULDBLOCK)
			continue;
		else
			abort();
	}

Otherwise, there is a timing window.  The window looks to be only one line
of code wide in the user process: small, but still an open window.  And in
reality, the window is wider.

When the kernel processes the select() call, and the selected-for
condition is true, the user process is simply scheduled to resume.  By the
time the user process actually runs, lots of other kernel activity and
possibly lots of other user processes may have run.  The selected
condition may have changed before the user process has a chance to take
action, even for files/devices being used exclusively by one process.

Example: a tty input buffer may get flushed by the kernel under certain
overflow conditions.  So data may have been readable at the time of
select(), but not be there at the read().

In a situation where several processes are sharing the same file/device,
it's quite likely that the select() condition will change out from under
some of the.  The semantics of select() are to wake up all the processes
awaiting the same condition, so the first one that runs may change the
condition (e.g. read all the available data, or fill the output buffer)
before the second gets a chance.

It WOULD be a bit more efficient if the LWP library only woke up
"interested" threads.  But there may be more than one thread selecting on
the same fd/condition - so the application code still has to deal with the
situation as above.

Beau



More information about the Comp.sys.sun mailing list