golang.org/x/build@v0.0.0-20240506185731-218518f32b70/cmd/gitmirror/gitmirror_linux.go (about) 1 // Copyright 2022 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "context" 9 "fmt" 10 "os" 11 "os/exec" 12 "syscall" 13 "time" 14 ) 15 16 func init() { 17 runCmdContext = runCmdContextLinux 18 } 19 20 // runCmdContextLinux runs cmd controlled by ctx, killing it and all its 21 // children if necessary. cmd.SysProcAttr must be unset. 22 func runCmdContextLinux(ctx context.Context, cmd *exec.Cmd) error { 23 if cmd.SysProcAttr != nil { 24 return fmt.Errorf("cmd.SysProcAttr must be nil") 25 } 26 cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} 27 if err := cmd.Start(); err != nil { 28 return err 29 } 30 resChan := make(chan error, 1) 31 go func() { 32 resChan <- cmd.Wait() 33 }() 34 35 select { 36 case err := <-resChan: 37 return err 38 case <-ctx.Done(): 39 } 40 // Canceled. Interrupt and see if it ends voluntarily. 41 cmd.Process.Signal(os.Interrupt) 42 select { 43 case <-resChan: 44 return ctx.Err() 45 case <-time.After(time.Second): 46 } 47 // Didn't shut down in response to interrupt. It may have child processes 48 // holding stdout/sterr open. Kill its process group hard. 49 syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL) 50 <-resChan 51 return ctx.Err() 52 }