By default, if there are multiple threads in a single process blocked in epoll_wait on the same epoll file description (whether or not they are referenced by the same descriptor or e.g. a dup'd one), all threads should unblock and all receive the events. I'm not aware of any real programs that depend on this behavior, but it is the (perhaps unfortunate) behavior in Linux. e.g. see https://idea.popcount.org/2017-02-20-epoll-is-fundamentally-broken-12/
At the moment, the case where a thread is woken up this way, but no events are ready (because they are consumed), is unhandled and Shadow crashes with a failed utility_assert. We hit this case in arti when compiled with tokio.
It'd probably be better to have such threads just block again without returning to user-space. Experimentally this seems to result in the correct behavior in arti+tokio, though is technically incorrect.
To handle this properly, we probably need to allocate events for each thread blocked on the epoll description, rather than just once.
By default, if there are multiple threads in a single process blocked in
epoll_waiton the sameepollfile description (whether or not they are referenced by the same descriptor or e.g. a dup'd one), all threads should unblock and all receive the events. I'm not aware of any real programs that depend on this behavior, but it is the (perhaps unfortunate) behavior in Linux. e.g. see https://idea.popcount.org/2017-02-20-epoll-is-fundamentally-broken-12/At the moment, the case where a thread is woken up this way, but no events are ready (because they are consumed), is unhandled and Shadow crashes with a failed
utility_assert. We hit this case in arti when compiled with tokio.It'd probably be better to have such threads just block again without returning to user-space. Experimentally this seems to result in the correct behavior in arti+tokio, though is technically incorrect.
To handle this properly, we probably need to allocate events for each thread blocked on the
epolldescription, rather than just once.