Fix flaky FastTerminalReentrancyTest by avoiding PTY creation - #12970
Conversation
Force providers("exec") in the test's TerminalBuilder configuration so
that JLine creates a lightweight ExternalTerminal instead of a
PosixPtyTerminal via the FFM provider. With system(false), the FFM
provider calls CLibrary.openpty() which creates a real PTY pair; the
subsequent grapheme-cluster probe (ensureModesProbed) then blocks on the
idle PTY master for the full probe timeout, and the PTY's pump threads
can stall close() during teardown -- all of which makes the tests flaky
on slow CI machines. The exec provider's ExternalTerminal avoids all of
this: no PTY, no pump threads, and supportsGraphemeClusterMode() returns
false immediately.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
The native FileInputStream.read0() on the PTY master fd blocks indefinitely on some iterations despite VMIN=0/VTIME=0 attributes, rather than merely being slow. Co-Authored-By: Claude Opus 4.6 <[email protected]>
|
Upstream JLine bug filed: jline/jline3#2209 The root cause is a race condition in JLine's |
gnodet
left a comment
There was a problem hiding this comment.
Well-documented fix for the flaky FastTerminalReentrancyTest. The Javadoc clearly explains the root cause (FFM provider's openpty() creates a real PTY, and the grapheme-cluster probe's native blocking read races with the timeout), and .providers("exec") is the right minimal fix to force ExternalTerminal creation.
Identical change already reviewed and approved on the 4.0.x cherry-pick (#12971). No issues found.
This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.
Claude Code on behalf of Guillaume Nodet
Summary
providers("exec")in the test'sTerminalBuilderconfiguration so JLine creates a lightweightExternalTerminalinstead of aPosixPtyTerminalvia the FFM providerRoot cause
With
system(false),TerminalBuilder.doBuild()enters the non-system path which ignores thedumb(true)flag and iterates FFM/JNI/exec providers. The FFM provider callsCLibrary.openpty(), creating a real PTY pair (/dev/pts/N) and aPosixPtyTerminal.Then
build()callssupportsGraphemeClusterMode()→ensureModesProbed()→probeModes()→readTerminalResponse()→readProbeChar(). This sends DECRQM/DA1 escape sequences to the PTY and reads responses viaNonBlockingReader.read(timeout), which delegates toFileInputStream.read0()— a native blocking read on the PTY master fd.Although
VMIN=0, VTIME=0terminal attributes are set before probing (which should make reads return immediately when no data is available), there is a race: on some iterations, the native read blocks indefinitely instead of respecting the timeout. Thread dump from a local reproduction:The exec provider's
ExternalTerminalavoids all of this: no PTY, no pump threads, andsupportsGraphemeClusterMode()returnsfalsewithout any I/O.Failed builds: https://github.com/apache/maven/actions/runs/33349929091/job/99362003331
Test plan
mvn test -pl impl/maven-jline -Dtest=FastTerminalReentrancyTestpasses (5/5 tests, ~0.4s)impl/maven-jlinemodule tests pass🤖 Generated with Claude Code