That goroutine is launched at the end of Cmd.Start <https://golang.org/src/os/exec/exec.go?s=11514:11541#L446>, rather than in exec.CommandContext. That makes sense: you don't want to start the time bomb until the process has been assigned a pid.
Cmd.Run just does Cmd.Start followed by Cmd.Wait, so I can redo that logic: cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true} err := cmd.Start() if err == nil { waitDone := make(chan struct{}) go func() { select { case <-ctx.Done(): unix.Kill(-cmd.Process.Pid, os.Kill.(syscall.Signal)) case <-waitDone: } }() err = cmd.Wait() close(waitDone) } That seems to do the trick - thank you. -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/c6c72dda-ca85-4e3d-8780-1c049297e97do%40googlegroups.com.