The select() mechanism can be confusing in multithreaded programs, especially on multiprocessors. Because select() returns the state of a descriptor, instead of an event notification, two threads blocked in select() could awaken at the same time, and would need additional synchronization to avoid handling the same descriptor. Our event-based API should make writing threaded applications more natural, because (with the SO_WAKEUP_ONE option described in Section 4) it delivers each event at most once. We have not yet explored this area in detail.
Our existing API requires each thread in a process to call declare_interest() for each descriptor that it is interested in. This requirement might add excessive overhead for a multi-threaded program using a large pool of interchangeable worker threads. We could augment the API with another system call:
int declare_processwide_interest(int fd, int interestmask, int *statemask);
The result of this system call would be the equivalent of invoking declare_interest() in every existing and future thread of the calling process. (It might also implicitly set SO_WAKEUP_ONE for the descriptor.) After this call, any thread of the process could wait for events on this descriptor using get_next_event().
An application handling thousands of descriptors might want to set event-delivery priorities, to control the order in which the kernel delivers events. In another paper [3], we introduced the resource container abstraction, which (among other benefits) allows an application to set kernel-level priorities for descriptor processing. In that paper we showed how an event-based API, such as the one presented here, is a useful component of end-to-end priority control in networked applications. We look forward to gaining experience with the combination of priority control and an event-based API in complex applications.