devpts: return immediately from a MIN=0 TIME=0 read with no input by karthik1729 · Pull Request #16089 · google/gvisor · GitHub
Skip to content

devpts: return immediately from a MIN=0 TIME=0 read with no input - #16089

Open
karthik1729 wants to merge 1 commit into
google:masterfrom
karthik1729:devpts-polling-read
Open

karthik1729 wants to merge 1 commit into
google:masterfrom
karthik1729:devpts-polling-read

Conversation

@karthik1729

Copy link
Copy Markdown

A read from the replica side of a pty with VMIN=0 and VTIME=0 (non-canonical mode) blocks when there is no input. POSIX says it must return 0 bytes at once. gVisor's inputQueueRead ignores VMIN and VTIME and returns ErrWouldBlock, so a blocking reader waits forever.

Impact. btop sets c_cc[VMIN] = 0 and c_cc[VTIME] = 0 when it turns canonical mode off, then reads stdin with while ((count = read(STDIN_FILENO, buf, sizeof(buf))) > 0). After the first key or mouse event it reads again and that second read never returns. Its drawing thread waits on the main thread, so the screen stops updating and the program has to be killed. Any program that polls input this way hangs the same way. A pty opened inside the sandbox is affected. A terminal that comes from the host (for example kubectl exec -it) is not.

Reproduce. In a container running under runsc, on a pty created inside the sandbox (for example with script):

stty -icanon min 0 time 0; dd bs=1 count=1 of=/dev/null; echo returned

On Linux returned prints at once. Under runsc it never prints.

Change. In inputQueueRead, when ICANON is off and both VMIN and VTIME are 0, return 0 bytes instead of ErrWouldBlock when the queue is empty. A non-zero VMIN still blocks. VTIME with a timeout is still not implemented and is left alone.

Testing.

  • Two new unit tests in devpts_test.go: the polling read returns 0 and still returns input that is available, and MIN=1 still returns ErrWouldBlock. I could not run Bazel here, so I have not run these two tests.
  • I built runsc and the containerd shim from the go branch (release-20260817.0 plus 26 commits) with this change, on three nodes (kernel 6.17, nested virtualization). btop on a pty created inside the sandbox kept drawing through a single mouse event, a mouse-motion burst and an arrow-key burst. The same source without the change froze on the first event in each run.

In non-canonical mode with VMIN=0 and VTIME=0, POSIX has read(2) return
whatever input is available at once, which is zero bytes when there is none.
The replica read path ignored VMIN and VTIME and returned ErrWouldBlock, so a
blocking reader waited forever.

btop turns canonical mode off with VMIN=0 and VTIME=0 and then reads stdin in a
loop until read returns 0. After the first key or mouse event its second read
blocked, and its drawing thread waited on the main thread for good, so the
screen stopped updating. Programs that poll input this way hang the same way.

Return 0 from inputQueueRead for that termios setting when the queue is empty,
and keep blocking when VMIN is non-zero.
@google-cla

google-cla Bot commented Oct 21, 2026

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant