The epoll backend. Linux only.
It arms a descriptor, and when epoll reports it ready it performs the transfer itself and posts the finished result. A self-wake eventfd, registered in the epoll set, lets a submission on any thread break the reactor thread out of epoll_wait.
Notes:
- Operations (epoll_op_t) live in a fixed pool sized from the reactor ring magnitude, with an intrusive free list. No need for growth as we're limited by the magnitude of the reactor.
- Several operations can share one descriptor (two fibers reading and writing the same socket, many fibers accepting on one listener). They are grouped in a per-fd list (epoll_op_list_t) and the fd is registered once with the union of their interests. epoll_event.data.ptr carries the list, so a readiness event resolves to the fd's ops with no search. The wait loop then walks the list and completes those whose direction is ready. The wake fd is distinguished by a NULL data pointer (a real list pointer is never NULL).
- The fd -> list mapping is a hashmap (check the serene/rt/impl/hashmap.h). The fd integer is stuffed straight into the key's data field (it fits in a pointer), so the map needs no separate key storage; a custom control hashes and compares data by value instead of dereferencing it.
Definition in file epoll.c.