Skip to content

Keep EIO completion notifications active - #2

Draft
pauljccode wants to merge 1 commit into
masterfrom
fix/eio-completion-notifications
Draft

pauljccode wants to merge 1 commit into
masterfrom
fix/eio-completion-notifications

Conversation

@pauljccode

@pauljccode pauljccode commented Oct 4, 2026 •

Copy link
Copy Markdown
Owner

An I/O completion can be stranded when a worker notifies the event loop between eio_done_poll stopping the async watcher and eio_async_cb restarting it. ev_async_start clears the pending notification, leaving a completed request queued without an event-loop callback.

Keep the watcher active while polling. Retain the required done-poll callback as a no-op because bundled libeio invokes it unconditionally.

Verification:

  1. Download check-eio-notifications.py and eio-notification-probe.c from the reproducer directory into the same directory. The runner requires Python 3, a C compiler, make and tar; it builds the bundled libeio 1.0.2 and libev 4.33.
  2. Run python3 check-eio-notifications.py /path/to/mettle baseline against master (4dd76ae), then repeat with candidate against this branch. The probe extracts the actual callbacks and forces the worker to finish in the stop/start interval.
  3. Confirm that both notifications are sent in each case, but only the corrected callbacks deliver both completions:
mode=stop-start notifications=2 completed=1 pending=1
mode=keep-active notifications=2 completed=2 pending=0

The race reproducer passed on Linux, Intel macOS and Apple Silicon macOS. Mettle Verify passed all eight Ruby/platform jobs, each with 65 examples and zero failures.

Combined acceptance passed 51 Linux and 46 native Intel macOS examples with verified candidate payloads. That run also includes the process cleanup fix and the now-merged Framework CI fixes; it is integration evidence, not an isolated run of this PR. The deterministic probe above isolates this change.

Upstream: rapid7/mettle#299. The attached fork acceptance run used upstream defaults rather than the candidate and was cancelled. Its macOS dependency-setup failure is addressed by Framework #21965.

Keep the async watcher active while libeio drains its queue. A worker
can finish between stopping and restarting the watcher, and
 ev_async_start clears that pending notification.

Retain the required done-poll callback as a no-op; bundled libeio
invokes it unconditionally.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant