LWN.net Logo

select() actually IS edge triggered

select() actually IS edge triggered

Posted Mar 14, 2003 14:08 UTC (Fri) by paulsheer (guest, #3925)
Parent article: Edge-triggered interfaces are too difficult?

Yes, select() for some devices IS edge triggered.
If select() marks a file descriptor available for
read/writeing (on some devices on some OS's) it WON'T mark
it again. You HAVE to read/write from it if you requested
for event notificatin for that file descriptor.

Therefore, in my select_tut man page (see recent
man page package from Linux doc), I make it clear
never to ask for event notification on a file
descriptor unless you intend to respond with a
read or write. Some devices work level triggered,
but programs that count on this may break.

The programs that do not use select() properly
should be fixed.

The whole point of the new system call (or it
ought to be the whole point) is that old select()
programs can simply #ifdef HAVE_EPOLL and get
the benefit or O(better) file descriptor event
handling -- with little or no other changes.

(This has nothing to do with what the standards
might say. Most programs are coded to run on
machines, not on standards :-)



(Log in to post comments)

select() actually IS edge triggered

Posted Mar 15, 2003 8:18 UTC (Sat) by IkeTo (subscriber, #2122) [Link]

> (This has nothing to do with what the standards
> might say. Most programs are coded to run on
> machines, not on standards :-)

Except perhaps to determine who is broken and thus must change. :-)

BTW, I see the implementation of Linux select() as to call a "poll method" of the device driver at the beginning to ask what is the current device status, and then, if it is not ready, to wait on a wait queue which is woken up by various device driver routines via the poll_wait() interface. Upon wake up the device is checked again for ready operations. Under this implementation I see no reason why a device can be edge-triggered: the device driver simply has to do much more work to make it edge-trigger without introducing a lot of race conditions.

On the other hand, if there are really device out there that *is* edge triggered on select(), then the advice that "one must read/write the fd if you select() it" is not sufficient. Instead, the advice should be "one must set the fd to non-blocking and read/write all the ready fds until it returns -1 with errno=EAGAIN or errno=EINTR, or you no longer need to read and write the fd, in which case you must no longer select() on them". Personally I've never seen a single scenario when the latter is needed. The former is always needed, for the simple reason that if you never read/write a fd that you select(), then once the fd is ready, it is always ready and break select(), so select() becomes a very expensive form of busy-polling.

select() actually IS edge triggered

Posted Mar 16, 2003 8:12 UTC (Sun) by Ross (subscriber, #4065) [Link]

Yep, if you are using select() to do nonblocking operations without setting the socket to nonblocking mode, your code will break. Believe me, I've done it :) It won't happen predictably, but it can happen. Basically treat the output from select() as a hint, and then try the operation until you get EAGAIN (or EWOULDBLOCK or whatever), and be prepared to handle the case where the very first call returns that error.

select() actually IS edge triggered

Posted Mar 16, 2003 8:41 UTC (Sun) by IkeTo (subscriber, #2122) [Link]

> Yep, if you are using select() to do nonblocking operations
> without setting the socket to nonblocking mode, your code will
> break.

Seen it only when I've got many threads/processes waiting for the same socket/fd. Then all threads wake up but only one can get the event that occurred. This is even documented in the accept() system call (perhaps because it always bite people making a multiprocess server). Of course you must respect the guarantee of select: only the first read() or write() is guaranteed to be non-blocking, and they may not write all the data you want to write, or read the whole buffer that you give it. Then you must wait for select() to tell you that it is ready again. But if you do respect them, I have never seen it failed, despite that I use it rather regularly. Perhaps the advice is a good safe-guard, but if any type of device or file has that behaviour (without saying that it does not work with select), then it is broken and should be reported as bugs.

BTW, your problem is just the opposite to the problem that paulsheer mentioned. What he says is that select might not return even if some fd is ready---because it has been returned in previous call of select. You say just the opposite: select might return even if no fd is ready. This should never happen, unlike the problem mentioned by paulsheer, which seems to be a gray area in the man page.

select() actually IS edge triggered

Posted Mar 16, 2003 19:00 UTC (Sun) by Ross (subscriber, #4065) [Link]

Yes, I have seen this happen "in real life" on several systems including Linux. The information given by select() is just a "snapshot" in time. You seem to be claiming that this is something new with edge triggered notification. It's not.

You point out the case I'm talking about: accept(), but the problem isn't caused by reading or writing more than once. In fact, if you use blocking sockets, there is no way to avoid the problem.

Specifically, I was talking about connections which are canceled between the call to select() and the call to accept(). The problem in general is that things can change between those two system calls.

If a connection is made to a server with a blocking listen socket the server will be notified of that new connection by select(). But the client can then cancel the connection before the server calls accept(). If there are no other waiting connections, the server will block until another connection is made. This is a classic race condition like the signal right before select() race and the alarm() without sigsetjmp() race). Most systems do not prevent this from happening (though a few will keep dead sockets in the accept queue so they can be handled as errors by accept).

Copyright © 2013, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds