From fb23905e639b8a7aabca05416f3ecbc0a233a7be Mon Sep 17 00:00:00 2001 From: Martin Vogel Date: Wed, 11 Nov 2026 00:43:14 +0100 Subject: [PATCH] test(daemon): pin the idle maintenance-probe cadence The frontend maintenance monitor probes for a maintenance request on every cycle, and each probe try-acquires the maintenance marker lock (on Windows that revalidates the whole ancestor directory chain). The quiet no-maintenance cadence was raised from 10 ms to 250 ms because the 10 ms loop burned a large share of a core for the life of every MCP session, but nothing pinned that cadence: a regression back to the hot loop would pass every suite. The monitor now sleeps on a local idle_ms in its ABSENT branch and, under CBM_ENABLE_TEST_SEAMS only, records that exact value immediately before sleeping on it (cleared by cbm_daemon_frontend_test_observer_reset). The new test starts an idle monitor, waits until a value is recorded, stops the monitor and asserts the recorded sleep is at least 250 ms. Once set, the recorded value is stable, so the verdict depends on neither elapsed time nor scheduler cadence; the deadline is only a hang guard. Production builds carry no seam code and sleep the same 250 ms as before. The original test counted presence observations inside a 100 ms window, which asserts a transient timing window; it is replaced by the recorded cadence above. Refs #2093 Distilled from #2215. Co-authored-by: lorenzozanee Signed-off-by: Martin Vogel --- src/daemon/frontend.c | 12 +++++++++++- src/daemon/frontend.h | 4 ++++ tests/test_daemon_frontend.c | 27 +++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/daemon/frontend.c b/src/daemon/frontend.c index e76c920b6..fa81cc06d 100644 --- a/src/daemon/frontend.c +++ b/src/daemon/frontend.c @@ -121,9 +121,11 @@ static atomic_uint_fast64_t frontend_test_worker_observation_count = ATOMIC_VAR_ static atomic_uint_fast64_t frontend_test_worker_idle_count = ATOMIC_VAR_INIT(0); static atomic_uint_fast64_t frontend_test_routed_cancellation_count = ATOMIC_VAR_INIT(0); static atomic_uint_fast32_t frontend_test_replay_budget_ms = ATOMIC_VAR_INIT(0); +static atomic_uint_fast32_t frontend_test_monitor_idle_sleep = ATOMIC_VAR_INIT(0); void cbm_daemon_frontend_test_observer_reset(bool hold_monitor) { atomic_store_explicit(&frontend_test_monitor_observation_count, 0, memory_order_release); + atomic_store_explicit(&frontend_test_monitor_idle_sleep, 0, memory_order_release); atomic_store_explicit(&frontend_test_worker_observation_count, 0, memory_order_release); atomic_store_explicit(&frontend_test_worker_idle_count, 0, memory_order_release); atomic_store_explicit(&frontend_test_monitor_is_waiting, false, memory_order_release); @@ -157,6 +159,10 @@ uint64_t cbm_daemon_frontend_test_routed_cancellations(void) { uint32_t cbm_daemon_frontend_test_replay_timeout_ms(void) { return (uint32_t)atomic_load_explicit(&frontend_test_replay_budget_ms, memory_order_acquire); } + +uint32_t cbm_daemon_frontend_test_monitor_idle_sleep_ms(void) { + return (uint32_t)atomic_load_explicit(&frontend_test_monitor_idle_sleep, memory_order_acquire); +} #endif static cbm_version_cohort_maintenance_presence_t frontend_observe_maintenance( @@ -187,7 +193,11 @@ static void *frontend_maintenance_monitor_worker(void *opaque) { cbm_version_cohort_maintenance_presence_t presence = frontend_observe_maintenance(monitor->manager, true); if (presence == CBM_VERSION_COHORT_MAINTENANCE_ABSENT) { - cbm_usleep(FRONTEND_MAINTENANCE_IDLE_POLL_MS * 1000U); + uint32_t idle_ms = FRONTEND_MAINTENANCE_IDLE_POLL_MS; +#if defined(CBM_ENABLE_TEST_SEAMS) && CBM_ENABLE_TEST_SEAMS + atomic_store_explicit(&frontend_test_monitor_idle_sleep, idle_ms, memory_order_release); +#endif + cbm_usleep(idle_ms * 1000U); continue; } diff --git a/src/daemon/frontend.h b/src/daemon/frontend.h index 8ee33d276..4629644bb 100644 --- a/src/daemon/frontend.h +++ b/src/daemon/frontend.h @@ -83,6 +83,10 @@ uint64_t cbm_daemon_frontend_test_routed_cancellations(void); * settings requests. Recovery tests use distinct connect and startup budgets * and compare. */ uint32_t cbm_daemon_frontend_test_replay_timeout_ms(void); +/* Milliseconds the maintenance monitor last slept in its no-maintenance + * (ABSENT) branch, recorded from the exact value passed to the sleep; zero + * until the first idle cycle after reset. Pins the idle probe cadence. */ +uint32_t cbm_daemon_frontend_test_monitor_idle_sleep_ms(void); #endif /* Takes ownership of client and borrows cohort_manager for the complete call. diff --git a/tests/test_daemon_frontend.c b/tests/test_daemon_frontend.c index aa49bf4c7..7e5c540ba 100644 --- a/tests/test_daemon_frontend.c +++ b/tests/test_daemon_frontend.c @@ -1641,6 +1641,32 @@ TEST(daemon_frontend_idle_uses_one_maintenance_observer) { ASSERT_TRUE(fixture_closed); PASS(); } + +/* An idle monitor must not repeatedly perform the expensive presence probe + * while no maintenance request exists (#2093). The monitor records the exact + * value it sleeps on in its no-maintenance branch; once recorded that value is + * stable, so the verdict depends on neither elapsed time nor scheduler cadence. + * The deadline below is only a hang guard. */ +TEST(daemon_frontend_idle_maintenance_probe_is_bounded) { + frontend_maintenance_fixture_t fixture; + ASSERT_TRUE(frontend_maintenance_fixture_start(&fixture, "idle-cadence")); + + cbm_daemon_frontend_test_observer_reset(false); + cbm_daemon_maintenance_monitor_t *monitor = cbm_daemon_maintenance_monitor_start( + fixture.manager, NULL, NULL, EXIT_SUCCESS, "idle cadence test"); + ASSERT_TRUE(monitor != NULL); + uint64_t deadline = cbm_now_ms() + 10000U; + while (cbm_now_ms() < deadline && cbm_daemon_frontend_test_monitor_idle_sleep_ms() == 0) { + cbm_usleep(1000); + } + uint32_t idle_sleep_ms = cbm_daemon_frontend_test_monitor_idle_sleep_ms(); + ASSERT_TRUE(cbm_daemon_maintenance_monitor_stop(&monitor)); + frontend_maintenance_fixture_finish(&fixture); + + ASSERT_TRUE(idle_sleep_ms != 0); + ASSERT_GTE(idle_sleep_ms, 250); + PASS(); +} #endif #ifndef _WIN32 @@ -1982,6 +2008,7 @@ SUITE(daemon_frontend) { RUN_TEST(daemon_frontend_rejects_non_notification_cancellation_shapes); #if defined(CBM_ENABLE_TEST_SEAMS) && CBM_ENABLE_TEST_SEAMS RUN_TEST(daemon_frontend_idle_uses_one_maintenance_observer); + RUN_TEST(daemon_frontend_idle_maintenance_probe_is_bounded); #endif #ifndef _WIN32 RUN_TEST(daemon_frontend_maintenance_exits_while_stdio_reader_is_blocked);