--- libev/ev_iouring.c 2019/12/27 22:16:10 1.12 +++ libev/ev_iouring.c 2019/12/28 03:29:50 1.13 @@ -402,7 +402,12 @@ struct io_uring_sqe *sqe = iouring_sqe_get (EV_A); sqe->opcode = IORING_OP_POLL_REMOVE; sqe->fd = fd; - sqe->user_data = -1; + /* Jens Axboe notified me that user_data is not what is documented, but is + * some kind of unique ID that has to match, otherwise the request cannot + * be removed. Since we don't *really* have that, we pass in the old + * generation counter - if that fails, too bad, it will hopefully be removed + * at close time and then be ignored. */ + sqe->user_data = (uint32_t)fd | ((__u64)(uint32_t)anfds [fd].egen << 32); iouring_sqe_submit (EV_A_ sqe); /* increment generation counter to avoid handling old events */ @@ -453,11 +458,6 @@ uint32_t gen = cqe->user_data >> 32; int res = cqe->res; - /* ignore fd removal events, if there are any. TODO: verify */ - /* TODO: yes, this triggers */ - if (cqe->user_data == (__u64)-1) - return; - assert (("libev: io_uring fd must be in-bounds", fd >= 0 && fd < anfdmax)); /* documentation lies, of course. the result value is NOT like @@ -467,6 +467,7 @@ */ /* ignore event if generation doesn't match */ + /* other than skipping removal events, */ /* this should actually be very rare */ if (ecb_expect_false (gen != (uint32_t)anfds [fd].egen)) return;