in io/iouring-wrapper.cpp [376:435]
ssize_t wait_and_fire_events(uint64_t timeout) override {
// Prepare own timeout
if (timeout > (uint64_t) std::numeric_limits<int64_t>::max()) {
timeout = std::numeric_limits<int64_t>::max();
}
auto ts = usec_to_timespec(timeout);
if (m_submit_wait_func(m_ring, &ts) != 0) {
return -1;
}
uint32_t head = 0;
unsigned i = 0;
io_uring_cqe* cqe;
io_uring_for_each_cqe(m_ring, head, cqe) {
i++;
auto ctx = (ioCtx*) io_uring_cqe_get_data(cqe);
if (!ctx) {
// Own timeout doesn't have user data
continue;
}
if (ctx == (ioCtx*) this) {
// Triggered by cancel_wait
eventfd_t val;
eventfd_read(m_eventfd, &val);
continue;
}
if (cqe->flags & IORING_CQE_F_NOTIF) {
// The cqe for notify, corresponding to IORING_CQE_F_MORE
if (unlikely(cqe->res != 0))
LOG_WARN("iouring: send_zc fall back to copying");
photon::thread_interrupt(ctx->th_id, EOK);
continue;
}
ctx->res = cqe->res;
if (!ctx->is_canceller && ctx->res == -ECANCELED) {
// An I/O was canceled because of:
// 1. IORING_OP_LINK_TIMEOUT. Leave the interrupt job to the linked timer later.
// 2. IORING_OP_POLL_REMOVE. The I/O is actually a polling.
// 3. IORING_OP_ASYNC_CANCEL. This OP is the superset of case 2.
ctx->res = -ETIMEDOUT;
continue;
} else if (ctx->is_canceller && ctx->res == -ECANCELED) {
// The linked timer itself is also a canceller. The reasons it got cancelled could be:
// 1. I/O finished in time
// 2. I/O was cancelled by IORING_OP_ASYNC_CANCEL
continue;
} else if (cqe->flags & IORING_CQE_F_MORE) {
continue;
}
photon::thread_interrupt(ctx->th_id, EOK);
}
io_uring_cq_advance(m_ring, i);
return 0;
}