Skip to content

zsh integration: use zsh/zselect for poll-loop sleeps (no fork)#6032

Open
jsamuel1 wants to merge 1 commit into
manaflow-ai:mainfrom
jsamuel1:shell-integration-fork-free-sleep
Open

zsh integration: use zsh/zselect for poll-loop sleeps (no fork)#6032
jsamuel1 wants to merge 1 commit into
manaflow-ai:mainfrom
jsamuel1:shell-integration-fork-free-sleep

Conversation

@jsamuel1

@jsamuel1 jsamuel1 commented Jun 13, 2026

Copy link
Copy Markdown

zsh integration: use zsh/zselect for poll-loop sleeps (no fork)

Problem

The shell integration starts two background watcher loops per pane:

  • _cmux_start_git_head_watch — polls .git/HEAD every second to refresh the branch/PR display
  • _cmux_start_pr_poll_loop — counts down its poll interval in 1-second steps

Both loops fork /bin/sleep once per second, indefinitely, for the life of the pane. With several panes open this is a continuous, low-level source of process churn. It's especially visible on managed machines where host security/EDR agents (CrowdStrike, FortiDLP, etc.) inspect every exec — each sleep fork fans out to every Endpoint Security client.

This is the same class of overhead the file already optimizes away for socket sends (zsh/net/unix, "~0.2ms vs ~3ms for fork+exec") and job-table checks (zsh/parameter).

Change

Add a _cmux_sleep_cs helper (argument in centiseconds) backed by the zsh/zselect builtin, whose -t timeout sleeps without forking. Falls back to /bin/sleep when the module is unavailable. Route the five in-shell sleep calls in the watcher loops through it.

Net effect: the steady-state per-pane sleep fork rate drops from ~1/sec to 0.

Subtlety worth a look

zselect with only -t and no fds returns status 1 on timeout. The helper therefore calls zselect and then return 0 explicitly — a naive zselect -t "$1" || sleep ... would fall through and double every wait.

Testing

  • zsh -n passes on the modified file.
  • zselect -t 100 sleeps ~1.00s fork-free in a backgrounded subshell with redirected std streams + stdin from /dev/null (the watchers' exact context).
  • Fallback path (_CMUX_HAS_ZSELECT=0) sleeps correctly via /bin/sleep.
  • Process-group kill teardown (_cmux_halt_pr_poll_loop) is unaffected — zselect, like sleep, is interrupted by the signal.

I did not wire this into the VM-based test suite in tests/ since those run against a built app; happy to add coverage if you'd like a specific form.

Scope

zsh only. bash has no equivalent non-forking sleep builtin (macOS ships bash 3.2), so cmux-bash-integration.bash is intentionally left unchanged.


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.


Summary by cubic

Use zsh/zselect for watcher loop sleeps to avoid forking \bin\sleep. This removes the steady 1/sec fork per pane and reduces process churn on EDR-heavy machines.

  • Refactors
    • Added _cmux_sleep_cs (centiseconds) using zsh/zselect -t; returns 0 on timeout; falls back to /bin/sleep.
    • Routed sleeps in _cmux_start_git_head_watch, _cmux_start_pr_poll_loop, and probe timeout waits through the helper; preserves signal interruption.
    • Scope: zsh only.

Written for commit c37af7c. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Refactor
    • Optimized zsh shell integration timing operations to improve performance and reduce system resource usage in monitoring processes.

The git-HEAD and PR-status watchers run one background loop per pane and
fork /bin/sleep once per second indefinitely. On a busy machine with many
panes this is a measurable, continuous source of process churn — which
also multiplies under host security/EDR agents that inspect every exec.

Replace the in-shell `sleep` calls with a `_cmux_sleep_cs` helper backed by
the `zsh/zselect` builtin (its `-t` timeout sleeps without forking), falling
back to /bin/sleep when the module is unavailable. This mirrors the existing
zsh/net/unix and zsh/parameter module-over-fork optimizations already in this
file.

Note: zselect with only -t and no fds returns status 1 on timeout, so the
helper calls it then returns 0 explicitly rather than falling through to the
/bin/sleep fallback (which would otherwise double the wait).

Verified: `zsh -n` passes; zselect -t 100 sleeps ~1.00s fork-free in a
backgrounded subshell with redirected std streams; fallback path sleeps
correctly when the module is absent.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 13, 2026

Copy link
Copy Markdown

@jsamuel1 is attempting to deploy a commit to the Manaflow Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2e1cd703-87b4-4f4a-b36e-65b821a1867f

📥 Commits

Reviewing files that changed from the base of the PR and between 1e3b103 and c37af7c.

📒 Files selected for processing (1)
  • Resources/shell-integration/cmux-zsh-integration.zsh

📝 Walkthrough

Walkthrough

This PR optimizes timing waits in monitoring loops by replacing sleep calls with a fork-free zselect-based utility. A new _cmux_sleep_cs function accepts centisecond delays and uses zsh/zselect when available, reducing process overhead in PR probe timeouts and periodic polling.

Changes

Fork-free sleep optimization for polling loops

Layer / File(s) Summary
Fork-free sleep infrastructure
Resources/shell-integration/cmux-zsh-integration.zsh
Capability detection sets _CMUX_HAS_ZSELECT and _cmux_sleep_cs function uses zselect -t when available with fallback to sleep and explicit handling to avoid doubling wait time on zselect timeout returns.
Polling and timeout loop integration
Resources/shell-integration/cmux-zsh-integration.zsh
PR probe TERM→KILL sequence, PR status poll loop, and git HEAD watch loop replace sleep 1 / sleep 0.2 calls with _cmux_sleep_cs 100 / _cmux_sleep_cs 20 equivalents.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Possibly related PRs

  • manaflow-ai/cmux#4959: Both PRs modify the PR probe/poll and git HEAD monitoring logic in Resources/shell-integration/cmux-zsh-integration.zsh—this PR swaps sleep calls for _cmux_sleep_cs/zselect, while the related PR changes those same loops to abort/skip starting when the zsh job table is saturated.

Poem

🐰 Behold the zsh loops, sleek and light,
No fork-exec forks through the night,
With zselect quick, we save the cost,
Each centisecond found, not lost!
Process joy, without the overhead—
The rabbit's gift: efficiency spread.

🚥 Pre-merge checks | ✅ 21
✅ Passed checks (21 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and specifically describes the main change: using zsh/zselect for poll-loop sleeps to eliminate forking, which is the primary objective of the PR.
Description check ✅ Passed The PR description comprehensively covers the problem statement, solution, implementation details, testing approach, and scope. It follows the template structure with sections for summary, testing, and includes detailed technical context.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Swift Actor Isolation ✅ Passed PR #6032 only modifies Resources/shell-integration/cmux-zsh-integration.zsh for zsh polling sleeps; no Swift files/actor-isolation code touched.
Cmux Swift Blocking Runtime ✅ Passed PR change is confined to Resources/shell-integration/cmux-zsh-integration.zsh (adds _cmux_sleep_cs using zsh/zselect); no Swift production blocking/timing primitives are introduced.
Cmux Expensive Synchronous Load ✅ Passed PR #6032 only modifies Resources/shell-integration/cmux-zsh-integration.zsh per GitHub “Files changed”; no Swift loader changes, so the swift-expensive-sync-load rule isn’t triggered.
Cmux Cache Substitution Correctness ✅ Passed PR #6032 changes only Resources/shell-integration/cmux-zsh-integration.zsh; no Swift/TypeScript/JavaScript persistence/history/undo/snapshot cache-substitution changes detected.
Cmux No Hacky Sleeps ✅ Passed Rule file allows existing delay code not worsened; in cmux-zsh-integration.zsh watcher loops now use _cmux_sleep_cs (zselect -t) with same 100cs/20cs waits; only fallback uses sleep.
Cmux Algorithmic Complexity ✅ Passed zsh PR adds O(1) _cmux_sleep_cs using zsh/zselect -t and replaces watcher sleep calls; no new collection scans, joins, or repeated sorting/filtering introduced.
Cmux Swift Concurrency ✅ Passed PR #6032 changes only Resources/shell-integration/cmux-zsh-integration.zsh (no .swift files in diff), so it can’t introduce/expand legacy Swift async patterns.
Cmux Swift @Concurrent ✅ Passed PR #6032 only modifies Resources/shell-integration/cmux-zsh-integration.zsh (zsh); no Swift files/classes/functions are changed, so the Swift @concurrent rule is not applicable.
Cmux Swift File And Package Boundaries ✅ Passed PR #6032 changes only Resources/shell-integration/cmux-zsh-integration.zsh (+25/-5); no Swift files were modified, so swift-file-package-boundaries rules can’t be violated.
Cmux Swift Logging ✅ Passed PR #6032 changes only Resources/shell-integration/cmux-zsh-integration.zsh; no Swift/app/runtime code or logging statements were added/modified.
Cmux User-Facing Error Privacy ✅ Passed Inspected Resources/shell-integration/cmux-zsh-integration.zsh: added _cmux_sleep_cs/zselect sleep logic only; no new user-facing error/alert/output strings (no vendor/upstream messages).
Cmux Full Internationalization ✅ Passed PR #6032 only changes Resources/shell-integration/cmux-zsh-integration.zsh (adds _cmux_sleep_cs using zsh/zselect); no Swift/web UI or i18n catalog changes.
Cmux Swiftui State Layout ✅ Passed PR #6032 changes only Resources/shell-integration/cmux-zsh-integration.zsh (adds _cmux_sleep_cs, no Swift/SwiftUI state/layout changes).
Cmux Architecture Rethink ✅ Passed PR #6032 changes only Resources/shell-integration/cmux-zsh-integration.zsh (zsh sleep optimization); no Swift/architecture diff, so swift-architectural-rethink rule isn’t triggered.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR change is confined to Resources/shell-integration/cmux-zsh-integration.zsh (zsh/zselect sleep helper); no Swift/NSWindow/WindowGroup auxiliary close-shortcut code changes detected.
Cmux Source Artifacts ✅ Passed PR #6032 changes only Resources/shell-integration/cmux-zsh-integration.zsh (adds _cmux_sleep_cs); no generated/temp/build/DerivedData or scratch artifact paths added.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps

greptile-apps Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR replaces /bin/sleep forks in the two background watcher loops (_cmux_start_git_head_watch, _cmux_start_pr_poll_loop) with a _cmux_sleep_cs helper backed by zsh/zselect -t, eliminating all steady-state sleep forks per open pane.

  • Adds _cmux_sleep_cs (centiseconds argument) that calls zselect -t when the module is available and explicitly returns 0 to neutralise zselect's status-1-on-timeout behaviour; falls back to /bin/sleep via zsh float arithmetic when the module is absent.
  • Replaces all five in-loop sleep calls (poll-interval countdown, SIGTERM/SIGKILL grace windows, and the git-HEAD polling tick) with _cmux_sleep_cs calls using equivalent centisecond values.

Confidence Score: 5/5

Safe to merge — the change is a pure performance optimisation of existing sleep calls with no behavioural side-effects.

Every modified call site replaces an identical-duration /bin/sleep with _cmux_sleep_cs; the helper handles the zselect status-1-on-timeout edge case correctly with an explicit return 0; the float-arithmetic fallback ($(( $1 / 100.0 ))) is valid zsh and produces correct values for both argument values used (100 and 20); the module availability flag is set once at startup and is inherited correctly by the disowned background subshells; no new polling or synchronisation patterns are introduced.

No files require special attention.

Important Files Changed

Filename Overview
Resources/shell-integration/cmux-zsh-integration.zsh Adds _cmux_sleep_cs helper and routes all five poll-loop sleep calls through it; logic is correct, zselect return-code subtlety is handled, fallback arithmetic is sound.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Shell integration loads] --> B{zmodload zsh/zselect}
    B -- success --> C[_CMUX_HAS_ZSELECT=1]
    B -- fail --> D[_CMUX_HAS_ZSELECT=0]

    C & D --> E[_cmux_sleep_cs N called]

    E --> F{_CMUX_HAS_ZSELECT?}
    F -- yes --> G[zselect -t N]
    G --> H[return 0 explicitly - no fork]
    F -- no --> I[sleep via /bin/sleep fallback]

    H & I --> J[Caller continues]

    subgraph Watchers
        K[_cmux_start_git_head_watch poll tick]
        L[_cmux_start_pr_poll_loop countdown tick]
        M[_cmux_run_pr_probe_with_timeout TERM/KILL grace]
    end

    J --> Watchers
Loading

Reviews (1): Last reviewed commit: "zsh integration: use zsh/zselect for pol..." | Re-trigger Greptile

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