Skip to content

cmd/go: add a flag to use stdin as a cancellation side-channel #56163

@bcmills

Description

@bcmills

The go command executes a lot of subprocesses as it runs, including:

Some clients of the go command end up starting a command, letting it run a while, and then wanting to cancel its execution. For example, gopls may start running go list to evaluate a program being edited, but then cancel that command due to another edit to the files in the user's workspace or a failure in some other concurrent processing that renders the go list result irrelevant.

If the go process itself is forcibly terminated using os.Kill (via either (*os.Process).Kill or exec.CommandContext), its subprocesses may continue to execute for an arbitrarily long time, leaking resources and (on Windows, at least) potentially preventing cleanup of temporary files and directories.

On Unix platforms, we can instead request a clean shutdown using os.Interrupt. (The go command may or may not respond appropriately to that signal today, but in principle it can and that's what matters in terms of the public-facing API.) However, os.Interrupt does not work on Windows, and per discussion on #6720 and #46345 we don't know of a general way to make it work. (At the very least, it would require os/exec to make invasive and likely-incompatible assumptions about consoles and process groups.)

Since os.Kill leaks resources and os.Interrupt isn't always available, we need some other way to request cancellation of a running go command.

Fortunately, we have a way out: as far as I am aware, every platform that supports os/exec in Go also supports inter-process pipes, and cmd/go to my knowledge does not use stdin for anything today.


I propose that we add a new flag to the go command, -stdin=keepalive, that will cause it to read from (and discard bytes from) stdin until EOF, then make a best effort to cancel all subprocesses, clean up, and exit as soon as possible.

The choice of -stdin=keepalive leaves open the possibility of using stdin in other ways in the future, while being clear about both its role (“keepalive”) and mechanism (“stdin”).

(CC @golang/tools-team)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status

    Accepted

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions