Skip to content

Commit 6e8ff2d

Browse files
authored
Fix macOS pty race with dropped output (#7278)
Signed-off-by: Spike Curtis <spike@coder.com>
1 parent e2d8bda commit 6e8ff2d

File tree

1 file changed

+18
-10
lines changed

1 file changed

+18
-10
lines changed

pty/start_other.go

+18-10
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,25 @@ func startPty(cmd *exec.Cmd, opt ...StartOption) (retPTY *otherPty, proc Process
5050
}
5151
return nil, nil, xerrors.Errorf("start: %w", err)
5252
}
53-
// Now that we've started the command, and passed the TTY to it, close our
54-
// file so that the other process has the only open file to the TTY. Once
55-
// the process closes the TTY (usually on exit), there will be no open
56-
// references and the OS kernel returns an error when trying to read or
57-
// write to our PTY end. Without this, reading from the process output
58-
// will block until we close our TTY.
59-
if err := opty.tty.Close(); err != nil {
60-
_ = cmd.Process.Kill()
61-
return nil, nil, xerrors.Errorf("close tty: %w", err)
53+
if runtime.GOOS == "linux" {
54+
// Now that we've started the command, and passed the TTY to it, close
55+
// our file so that the other process has the only open file to the TTY.
56+
// Once the process closes the TTY (usually on exit), there will be no
57+
// open references and the OS kernel returns an error when trying to
58+
// read or write to our PTY end. Without this (on Linux), reading from
59+
// the process output will block until we close our TTY.
60+
//
61+
// Note that on darwin, reads on the PTY don't block even if we keep the
62+
// TTY file open, and keeping it open seems to prevent race conditions
63+
// where we lose output. Couldn't find official documentation
64+
// confirming this, but I did find a thread of someone else's
65+
// observations: https://developer.apple.com/forums/thread/663632
66+
if err := opty.tty.Close(); err != nil {
67+
_ = cmd.Process.Kill()
68+
return nil, nil, xerrors.Errorf("close tty: %w", err)
69+
}
70+
opty.tty = nil // remove so we don't attempt to close it again.
6271
}
63-
opty.tty = nil // remove so we don't attempt to close it again.
6472
oProcess := &otherProcess{
6573
pty: opty.pty,
6674
cmd: cmd,

0 commit comments

Comments
 (0)