Skip to content

Commit 3216e59

Browse files
committed
internal/gocommand: kill gracefully
We want the go command to get a chance to do its cleanups. Send it Interrupt before Kill. Fixes golang/go#37368. Change-Id: Id891d2f4f85aae30d2aaa19b9c854d2346ec6e1f Reviewed-on: https://go-review.googlesource.com/c/tools/+/220738 Run-TryBot: Heschi Kreinick <[email protected]> Reviewed-by: Rebecca Stambler <[email protected]>
1 parent 9534ad4 commit 3216e59

File tree

1 file changed

+31
-2
lines changed

1 file changed

+31
-2
lines changed

internal/gocommand/invoke.go

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"bytes"
66
"context"
77
"fmt"
8+
"os"
89
"os/exec"
910
"strings"
1011
"time"
@@ -49,7 +50,7 @@ func (i *Invocation) RunRaw(ctx context.Context) (stdout *bytes.Buffer, stderr *
4950
goArgs = append(goArgs, i.BuildFlags...)
5051
goArgs = append(goArgs, i.Args...)
5152
}
52-
cmd := exec.CommandContext(ctx, "go", goArgs...)
53+
cmd := exec.Command("go", goArgs...)
5354
stdout = &bytes.Buffer{}
5455
stderr = &bytes.Buffer{}
5556
cmd.Stdout = stdout
@@ -65,7 +66,7 @@ func (i *Invocation) RunRaw(ctx context.Context) (stdout *bytes.Buffer, stderr *
6566

6667
defer func(start time.Time) { log("%s for %v", time.Since(start), cmdDebugStr(cmd)) }(time.Now())
6768

68-
rawError = cmd.Run()
69+
rawError = runCmdContext(ctx, cmd)
6970
friendlyError = rawError
7071
if rawError != nil {
7172
// Check for 'go' executable not being found.
@@ -80,6 +81,34 @@ func (i *Invocation) RunRaw(ctx context.Context) (stdout *bytes.Buffer, stderr *
8081
return
8182
}
8283

84+
// runCmdContext is like exec.CommandContext except it sends os.Interrupt
85+
// before os.Kill.
86+
func runCmdContext(ctx context.Context, cmd *exec.Cmd) error {
87+
if err := cmd.Start(); err != nil {
88+
return err
89+
}
90+
resChan := make(chan error, 1)
91+
go func() {
92+
resChan <- cmd.Wait()
93+
}()
94+
95+
select {
96+
case err := <-resChan:
97+
return err
98+
case <-ctx.Done():
99+
}
100+
// Cancelled. Interrupt and see if it ends voluntarily.
101+
cmd.Process.Signal(os.Interrupt)
102+
select {
103+
case err := <-resChan:
104+
return err
105+
case <-time.After(time.Second):
106+
}
107+
// Didn't shut down in response to interrupt. Kill it hard.
108+
cmd.Process.Kill()
109+
return <-resChan
110+
}
111+
83112
func cmdDebugStr(cmd *exec.Cmd) string {
84113
env := make(map[string]string)
85114
for _, kv := range cmd.Env {

0 commit comments

Comments
 (0)