fix(harness): prevent pipe deadlock in LocalFilesystemWithShell.execute - #2839
Open
zzz-ghost wants to merge 1 commit into
Open
fix(harness): prevent pipe deadlock in LocalFilesystemWithShell.execute#2839zzz-ghost wants to merge 1 commit into
zzz-ghost wants to merge 1 commit into
Conversation
Drain stdout/stderr on daemon threads concurrently with Process.waitFor. Previously a child writing more than the OS pipe buffer (~4 KB on Windows, 64 KB on Linux) blocked in write() while the parent blocked in waitFor(), deadlocking until the command was forcibly killed and misreported as a timeout (exit 124). Mirrors the fix already applied to ShellCommandTool in agentscope-core. Adds a regression test that prints ~70 KB from the shell and asserts the command completes with exit 0 and full output. Fixes agentscope-ai#2838
zzz-ghost
force-pushed
the
fix/2838-execute-pipe-deadlock
branch
from
August 25, 2026 08:17
f8ae46b to
7fb5e9a
Compare
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Author
|
Note: the two earlier |
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.
What this PR does
Fixes a pipe deadlock in
LocalFilesystemWithShell.execute(): the child process's stdout/stderr are now drained on daemon threads concurrently withProcess.waitFor(), instead of only after it returns.Root cause
Previously
execute()calledProcess.waitFor(timeout)first and readgetInputStream()/getErrorStream()only afterwards. If the child wrote more than the OS pipe buffer (≈4 KB on Windows, 64 KB default on Linux), it blocked inwrite()forever while the parent blocked inwaitFor()— a classic pipe deadlock. Every such command was misreported as a timeout (exit 124) and forcibly killed, even though it would have finished in well under a second.Fix
ByteArrayOutputStream) immediately afterProcessBuilder.start(), thenwaitFor(timeout), then join the drainers — destroying the process first on timeout so the drainers terminate.ShellCommandToolinagentscope-core("Start asynchronous stream readers immediately to prevent pipe buffer deadlock"), whichLocalFilesystemWithShellwas missed by.maxOutputBytestruncation.Testing
New regression test
execute_outputLargerThanOsPipeBufferCompletesWithoutDeadlockprints ~70 KB via shell builtins (works on bothshandcmd.exe, no Python needed):Verified on Windows 10 (≈4 KB pipe buffer); the threshold (68–72 KB) also exceeds the 64 KB Linux default pipe buffer, so the test covers both platforms.
Fixes #2838