Stop orphaning wine subprocesses when vintner is killed by PID

Every wrapped tool invocation (cl/link/msbuild/etc via wine, plus the
native cmd/findstr shims) now starts its child in its own process
group and forwards SIGINT/SIGTERM to that group, escalating to
SIGKILL after a 5s grace period if it doesn't exit.

Previously, interactive Ctrl-C happened to work by accident (the
child inherited the terminal's foreground process group and got the
signal directly), but anything that signals vintner by PID alone - a
CI job's timeout, a supervisor's `kill <pid>` - never reached the
wine/wineserver tree underneath it, which got reparented to init and
kept running: wasted CPU, held file locks, stray FIFOs/temp files.

Verified two ways: a unit test (signals_test.go) that starts a
detached `sleep 30`, signals the test process itself, and checks the
child actually dies; and a real end-to-end run - killed an in-flight
`msbuild` driver build by PID mid-compile and confirmed no orphaned
msbuild/cl/link/vintner process was left behind (wineserver and its
persistent service processes are expected to survive, by design - see
pipeDrainGrace's doc comment).
This commit is contained in:
Cheviiot
2026-07-25 10:34:45 +10:00
parent 4b3aacfdf7
commit 98ee39018a
4 changed files with 127 additions and 1 deletions
+7 -1
View File
@@ -29,7 +29,13 @@ func execInherit(args []string) int {
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
setNewProcessGroup(cmd)
if err := cmd.Start(); err != nil {
return 127
}
stopSignals := forwardSignals(cmd.Process)
defer stopSignals()
if err := cmd.Wait(); err != nil {
if exitErr, ok := err.(*exec.ExitError); ok {
return exitErr.ExitCode()
}