Fixes #5349. Ignore non-readable poll events during ANSI shutdown#5353
Conversation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
tig
left a comment
There was a problem hiding this comment.
The fix is clean and well-targeted. Here's my review:
Summary
Good PR. The fix correctly addresses a hang during ANSI shutdown by checking revents for POLLIN instead of treating any poll wake-up (e.g., POLLHUP, POLLERR, POLLNVAL) as readable data. Previously, poll() returning > 0 was enough to signal "input available," which could cause a read attempt on a closed/errored fd — leading to a hang.
Findings
The logic change is correct and the tests exercise both the happy path and the error-event path using real pipes + P/Invoke. Two minor observations:
-
Test: double-close risk — In
IsInputAvailable_ReturnsFalse_WhenPollReportsNonReadableEvent,pipeFds[0]is closed inside thetryblock (the test's setup step), but thefinallyblock doesn't guard against closing it again. Currently fine becausefinallyonly closespipeFds[1], but if someone refactors this, it's fragile. Minor — not blocking. -
Test: platform skip pattern — The early-return skip pattern works but isn't self-documenting in test output (xUnit won't distinguish "skipped" from "passed"). A
Skipattribute orAssert.Skip()would make CI results clearer. Minor — not blocking.
No bugs, no security issues, no logic errors. The change is minimal, correct, and well-tested.
Fixes
Proposed Changes
UnixIOHelper.IsInputAvailable ()to returntrueonly whenpoll()reportsPOLLINUnixIOHelperTeststo cover both a readable poll event and a non-readable poll event on Unix-like platformsPOLLHUP/POLLERR/POLLNVAL-only wakeups as readable inputRoot Cause
AnsiInput.FlushInput ()usesUnixIOHelper.IsInputAvailable ()to decide whether to keep draining input during shutdown.On Unix/macOS,
poll()can wake up with non-readable events such asPOLLHUPorPOLLNVALwithoutPOLLIN. The old helper treated anypoll() > 0result as readable input, so shutdown could attempt another read even though no readable data was available. If that happened whileMainLoopCoordinator.Stop ()was waiting for the input task to exit,app.Dispose ()could hang.OSS Comparison
This fix matches the defensive pattern used by other mature terminal codebases:
prompt_toolkitfixed the same class of closed/unpollable-stdin bugs by treating EOF/unpollable stdin as terminal closure and unregistering the readerkittycurrently has an active bug in the same family where non-readable poll events are effectively treated as readablelnav,vim,zshZLE, andarcanall gate reads onPOLLINand handle hangup/error events separatelyThat makes this change consistent with established terminal I/O practice: only read when
POLLINis set.Verification
dotnet build --no-restoredotnet test --project Tests/UnitTestsParallelizable --no-build --filter-class "*UnixIOHelperTests"dotnet test --project Tests/UnitTestsParallelizable --no-build --filter-class "*AllDriverTests"dotnet test --project Tests/UnitTestsParallelizable --no-build --filter-class "*RunTests"No new warnings were introduced in the touched files. The build still reports an existing unrelated
IntegrationTestsanalyzer warning (AD0001).To pull down this PR locally: