fix(openfiles): share descriptors across cloned shell contexts#1181
Merged
Conversation
Test Results 5 files 40 suites 16m 32s ⏱️ Results for commit a4f0e7b. ♻️ This comment has been updated with latest results. |
Public API changes for crate: brush-coreRemoved itemsAdded itemsChanged itemsPerformance Benchmark Report
Code Coverage Report: Only Changed Files listed
Minimum allowed coverage is Test Summary: bash-completion test suite
|
Contributor
There was a problem hiding this comment.
Pull request overview
This PR addresses file-descriptor exhaustion in brush by switching cloned shell contexts to share inherited open file descriptors (instead of duplicating them), which is important because brush runs many “subshell-like” constructs as in-process tasks sharing one process-wide fd table.
Changes:
- Add compatibility regression tests that stress nested/concurrent constructs under a lowered
ulimit -n. - Rework
OpenFilecloning semantics to share underlying file/pipe descriptors viaArc, only duplicating when needed for external child processes. - Adjust redirection and command-spawn plumbing to align with shared-descriptor behavior (including making
OpenFile -> Stdioconversion fallible).
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| brush-shell/tests/cases/compat/fd_management.yaml | Adds regression cases to catch fd exhaustion under concurrency/nesting. |
| brush-core/src/shell/io.rs | Avoids cloning trace fd on each write; writes directly to the selected open file. |
| brush-core/src/shell/fs.rs | Stops duplicating /dev/fd/N opens; reuses the referenced fd’s OpenFile. |
| brush-core/src/openfiles.rs | Switches file/pipe handles to Arc sharing; updates child-process handoff to duplicate explicitly and makes Stdio conversion fallible. |
| brush-core/src/interp.rs | Updates redirection setup to share OpenFiles rather than try_clone()-duplicating them. |
| brush-core/src/commands.rs | Avoids cloning execution parameters for function invocation; executes with shared params reference. |
Brush runs subshells, command substitutions, background jobs, and
function-call contexts as in-process clones rather than fork(2) children,
all sharing one process-wide descriptor table. OpenFiles::clone() issued a
real dup(2) for every descriptor on every clone, so descriptors accumulated
super-linearly with nesting depth and concurrent fan-out. A single `nvm ls`
peaked at over 1000 simultaneous descriptors and hit EMFILE ("Too many open
files") on systems with a low limit such as macOS's default of 256.
Store file/pipe handles in OpenFile behind Arc so cloning shares the
descriptor (a refcount bump) with the same open-file-description semantics
dup would have provided; a real dup now happens only when handing a
descriptor to an external child process. Also drop the redundant per-call
params clone in shell-function invocation, which duplicated every inherited
descriptor for the duration of each function body.
nvm ls peak: ~1008 -> ~93 descriptors. As a side effect, OpenFile::clone can
no longer fail, so the "failed to duplicate open file" fallback no longer
triggers under descriptor pressure.
Part of #1173.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Make OpenFile->Stdio conversion fallible (TryFrom) so descriptor duplication failures surface instead of silently using /dev/null; remove the now-infallible try_clone and the TryCloneToStdio helper; gate the fd_management compat tests to non-wasi; tidy comments. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
reubeno
marked this pull request as ready for review
June 2, 2026 02:12
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Addresses file-descriptor exhaustion in
brushby mapping shell "FD" cloning to cloning anArc-shared OS resource, rather than duplicating the host fd.