//go:build !windows package compose import ( "os/exec" "syscall" "time" ) const gracefulTerminationBound = 500 * time.Millisecond const finalTerminationBound = 2 * time.Second func configureProcess(command *exec.Cmd) { command.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} } type unixProcessLifetime struct { command *exec.Cmd } func startProcess(command *exec.Cmd) (processLifetime, error) { if err := command.Start(); err != nil { return nil, err } return unixProcessLifetime{command: command}, nil } func (process unixProcessLifetime) terminate(done <-chan error) error { return terminateProcess(process.command, done) } func (unixProcessLifetime) close() error { return nil } func terminateProcess(command *exec.Cmd, done <-chan error) error { if command.Process == nil { return nil } _ = syscall.Kill(-command.Process.Pid, syscall.SIGINT) select { case <-done: return nil case <-time.After(gracefulTerminationBound): } _ = syscall.Kill(-command.Process.Pid, syscall.SIGKILL) _ = command.Process.Kill() select { case <-done: return nil case <-time.After(finalTerminationBound): return ErrProcessReap } }