From 4692255528e1e501d6791d0395e4d89e14dcdb73 Mon Sep 17 00:00:00 2001 From: Serhii Mariiekha Date: Sun, 26 Apr 2026 00:00:57 +0200 Subject: [PATCH] Fix libxev poller callback leaks and re-enable poller tests Addresses #424 and #426 by preventing stale completion reuse across fd lifecycles and draining ready callbacks in run_xev_tick. Re-enables the gated runtime poller tests. --- src/runtime/run_xev_bridge.zig | 5 +++++ src/runtime/tests/test_poller.c | 21 ++++----------------- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/src/runtime/run_xev_bridge.zig b/src/runtime/run_xev_bridge.zig index 22e890c..1c1c79e 100644 --- a/src/runtime/run_xev_bridge.zig +++ b/src/runtime/run_xev_bridge.zig @@ -272,11 +272,13 @@ fn readPollCallback( const wg = s.write_g; s.read_g = null; s.write_g = null; + if (rg != null or wg != null) callbacks_fired += 1; cb(fd, 3, rg, wg); return .disarm; }; const rg = s.read_g; s.read_g = null; + if (rg != null) callbacks_fired += 1; cb(fd, 1, rg, null); } return .disarm; @@ -348,6 +350,9 @@ export fn run_xev_tick() c_int { if (!loop_initialized) return 0; if (registered_count <= 0) return 0; + // Drain all currently-ready completions in this tick. On kqueue, a single + // no_wait run can report only one completion even when multiple fds are + // already ready; bounded draining ensures fairness and avoids dropped wakeups. callbacks_fired = 0; var previous_callbacks: u32 = 0; var i: u8 = 0; diff --git a/src/runtime/tests/test_poller.c b/src/runtime/tests/test_poller.c index 7fd2144..fccc85e 100644 --- a/src/runtime/tests/test_poller.c +++ b/src/runtime/tests/test_poller.c @@ -398,23 +398,10 @@ void run_test_poller(void) { TEST_SUITE("run_poller"); RUN_TEST(test_poller_has_waiters); RUN_TEST(test_poller_open_close); -#ifdef _WIN32 - RUN_TEST(test_poller_pipe_read); RUN_TEST(test_poller_close_while_waiting); -#else - /* Gated on #426: hangs on Linux x86_64 CI due to libxev epoll state leaking - * across tests (passes in isolation and on macOS). Re-enable once #426 is fixed. */ - /* RUN_TEST(test_poller_close_while_waiting); */ - /* Gated on #426: hangs on macOS CI due to libxev kqueue state leaking from - * prior tests (passes in isolation). Re-enable once #426 is fixed. */ - /* RUN_TEST(test_poller_pipe_read); */ - /* Gated on #426: passes in isolation, but running it in the same suite as - * test_poller_pipe_read in either order causes the second test to hang due - * to inter-test libxev state leak. Re-enable once #426 is fixed. */ - /* RUN_TEST(test_poller_write_park); */ - /* Gated on #424: libxev kqueue adapter only fires one fd's callback per - * tick when multiple fds are ready, so this test hangs. Re-enable once - * the adapter is fixed. */ - /* RUN_TEST(test_poller_multiple_fds); */ + RUN_TEST(test_poller_pipe_read); +#ifndef _WIN32 + RUN_TEST(test_poller_write_park); #endif + RUN_TEST(test_poller_multiple_fds); }