Description
As observed on Linux, when a set_readiness()
happens, mio will write a 0x01 byte to a pipe, later observe the corresponding event on the pipe's read file descriptor in epoll_wait()
, read the 0x01 from the pipe, and return the event.
This Reddit comment from Carl Lerche indicates that this is not expected to happen when an epoll_wait()
is not in progress. For example, in a single-thread scenario this should not be seen, since a set_readiness()
could not happen concurrently with an in-progress epoll_wait()
. However, this pipe write does appear to happen outside of an epoll_wait()
, at least in some circumstances.
I've posted a small example program in this gist that shows the issue with mio 0.6.11. It registers a UDP socket and a mio::Registration
with mio, sends a UDP packet to the socket, receives the packet, then calls set_readiness()
. An strace shows the pipe write happening outside of an epoll_wait()
:
$ strace -f -s 1024 target/debug/mio-pipe
...
pipe2([5, 6], O_NONBLOCK|O_CLOEXEC) = 0
epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN|EPOLLET, {u32=4294967295, u64=18446744073709551615}}) = 0
epoll_ctl(4, EPOLL_CTL_ADD, 3, {EPOLLIN, {u32=0, u64=0}}) = 0
socket(PF_INET, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_IP) = 7
bind(7, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
sendto(7, "hello", 5, MSG_NOSIGNAL, {sa_family=AF_INET, sin_port=htons(2000), sin_addr=inet_addr("127.0.0.1")}, 16) = 5
epoll_wait(4, [{EPOLLIN, {u32=0, u64=0}}], 16, -1) = 1
recvfrom(3, "hello", 1500, 0, {sa_family=AF_INET, sin_port=htons(41815), sin_addr=inet_addr("127.0.0.1")}, [16]) = 5
write(1, "recv 5 bytes from 127.0.0.1:41815.\n", 35) = 35
write(6, "\1", 1) = 1
epoll_wait(4, [{EPOLLIN, {u32=4294967295, u64=18446744073709551615}}], 16, 0) = 1
read(5, "\1", 128) = 1
read(5, 0x7fff70ace168, 128) = -1 EAGAIN (Resource temporarily unavailable)
write(1, "mio::Registration readiness received.\n", 38) = 38
...
If this is indeed a bug, it's probably a low priority bug since functionality is not impacted.