Skip to content

cbm_nanosleep never resumes after EINTR: every timed wait can be silently truncated #1616

Closed

Description

@moffermann

What

On POSIX cbm_nanosleep is raw nanosleep (src/foundation/compat.h:96), and all four call sites
pass rem = NULL and discard the return value:

  • src/foundation/subprocess.c:958 — cbm_spawn_backoff, the spawn-retry patience
  • src/daemon/bootstrap.c:274
  • src/daemon/runtime.c:275
  • src/foundation/diagnostics.c:464

nanosleep returns EINTR on any signal delivered to the calling thread, and unlike most blocking
calls it is not restarted by SA_RESTART — the remaining time is simply lost unless the caller
loops on rem. So every one of these waits can end early by an arbitrary amount, silently.

Why it matters

cbm_spawn_backoff is the clearest case. The comments around
CBM_SPAWN_RETRY_ATTEMPTS promise ~630 ms of patience on an ordinary build and ~5 s on a sanitized
one, and that is the whole point of the retry: ride out a burst of process creation instead of
failing a spawn that would have succeeded. A signal arriving mid-backoff cuts that budget to a
fraction of what the code says it is, and nothing reports it.

src/cli/hook_augment.c:133 installs a SIGALRM handler, so this is reachable and not theoretical.

Why this is an issue and not a PR

Suggested shape

Add cbm_nanosleep_full() (loop while nanosleep returns -1/EINTR, feeding rem back in;
Windows Sleep already has no interruptible failure mode) and move the call sites that want an
uninterruptible wait — starting with cbm_spawn_backoff — over to it. Leave the daemon pauses on
the interruptible primitive if that is the intent, with a comment saying so.

Found while reviewing the sanitized-build wiring in #1615; unrelated to that change.

Activity

  1. added
    bugSomething isn't working
    stability/performanceServer crashes, OOM, hangs, high CPU/memory
    priority/normalStandard review queue; useful PR with ordinary maintainer urgency.
    and removed
    windowsWindows-specific issues
    on Aug 18, 2026
  2. DeusData commented on Aug 18, 2026

    @DeusData
    Owner

    Thank you for distinguishing the real EINTR defect from the unrelated CI spawn failures. Current main still aliases cbm_nanosleep directly to POSIX nanosleep, and the production call sites discard both the return value and remainder, so the promised backoff duration can be truncated exactly as described.

    The proposed boundary is sound: add an explicit full-sleep helper that resumes only on EINTR, move cbm_spawn_backoff first, and leave shutdown or polling pauses on the interruptible primitive only where early wakeup is intentional and documented. This should be a focused reliability change, not a mechanical replacement of every call site. Thank you for doing the call-site analysis before suggesting the helper.

  3. added a commit that references this issue on Sep 2, 2026
  4. DeusData commented on Sep 2, 2026

    @DeusData
    Owner

    Fixed on main by c537bf0f ("fix(foundation): resume spawn backoff after EINTR"), merged as 14249349 via #1799. Thanks to @rarepops.

    cbm_spawn_backoff called cbm_nanosleep(&delay, NULL) — passing NULL for the remainder, so a signal arriving mid-sleep silently truncated the wait to however long had already elapsed. With the backoff at 10ms << shift up to shift 8, a 2.56-second retry delay could collapse to almost nothing, making the spawn retry loop tighten under exactly the memory pressure it exists to ride out.

    The new cbm_nanosleep_full() runs the canonical resume loop — nanosleep writes the unslept remainder back into the same timespec, which is passed straight back as the next request — so the documented budget is preserved across signals. Windows is unchanged (no EINTR), and only the spawn-backoff call site was switched; other sleeps deliberately stay interruptible.

    Covered by a POSIX regression in tests/test_subprocess.c that repeatedly interrupts the deterministic backoff with SIGALRM and asserts the full cumulative delay survives.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingpriority/normalStandard review queue; useful PR with ordinary maintainer urgency.stability/performanceServer crashes, OOM, hangs, high CPU/memory

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions