mirror of
https://github.com/containerd/containerd.git
synced 2026-11-06 05:17:02 +00:00
A terminal exec or init process has no processIO. The shim keeps a writer on the stdin FIFO (openStdin) so the console's stdin copier never sees a premature EOF, and keeps the console master in `console`. delete closed the closers only under `if io != nil`, which is never true on the terminal path, and never closed the console. When a client exits without calling CloseIO, the stdin copier therefore stays blocked on the FIFO and the FIFO handles, the console master and the goroutine stay alive until a later garbage collection finalizes the dropped process object, and for as long as the client holds its own writer on the FIFO, past that too. Release the I/O on every path and through one owner. delete shuts the console down, drains, then closes closers, console and io regardless of io; a process deleted from the created state never ran setExited, so this is its only shutdown. CopyConsole returns a console that owns its teardown: shutdown and deregistration from the epoller happen once, while the fd is still open, and Close then closes the master, wakes a writer parked on it, and closes the stdin FIFO reader, which ends a copier blocked reading stdin. The copier, the setup-error path, ShutdownConsole and both deletes go through it, so a bare Close can no longer leave a copier asleep, and a late ShutdownConsole is a no-op instead of a deregistration by a fd number that a newer console may own. CopyConsole also closes the received master when registering it fails and the stdout FIFO writer when opening its reader fails. Six regression tests cover the delete ordering, the setup-error paths, the copier wake-up and the fd reuse; each fails before its part of this change. Assisted-by: Claude Code Signed-off-by: Jacob Gabrielson <jacob.gabrielson@docker.com>