Skip to content

v3.0.2 – Fixed stuck I/O awaiters and improved epoll state handling

Choose a tag to compare

@g2px1 g2px1 released this 27 Oct 21:40
· 191 commits to main since this release

Release notes:
This release resolves a critical coroutine wake-up issue in the epoll integration layer that caused consistent 2-second stalls on TCP writes and potential hangs on subsequent reads.

🧩 Core Fixes

  • Removed stale I/O flags (is_writing_now, is_reading_now): these flags caused sockets to skip re-arming EPOLLIN/EPOLLOUT after the first await, resulting in lost wakeups.

  • Simplified Awaiter design:

    • AwaiterWrite and AwaiterRead now always re-register interest (EPOLL_CTL_MOD) on every new co_await.
    • Awaiter state is tracked solely via SocketHeader::first (read waiter) and SocketHeader::second (write waiter).
    • No more “flag handshake” between awaiters and poller.
  • Poller cleanup: each EPOLLIN/EPOLLOUT event now resumes the corresponding coroutine directly and clears the slot atomically; no more dependency on clear_writing() or clear_reading().

⚙️ Behavioral Impact

  • Eliminates the consistent ~2000 ms latency observed after connect() due to missed EPOLLOUT.
  • Prevents future deadlocks on repeated async_read() calls in persistent TCP sessions.
  • Slightly increases epoll_ctl(EPOLL_CTL_MOD) calls, but ensures strict correctness and deterministic wake-ups under ET mode.

✅ Summary

v3.0.2 focuses on reliability and correctness of coroutine I/O scheduling.
Event re-arming is now explicit and safe, guaranteeing that every await resumes exactly once with no race or delay.