//go:build !windows package proc import ( "errors" "os/exec" "syscall" "time" ) // unixGroup 用 POSIX 进程组实现整树终止:子进程经 Setpgid 成为新进程组组长 // (pgid == pid),向负 pgid 发信号即覆盖整个进程组的所有子孙。 type unixGroup struct { pgid int } func newGroup() Group { return &unixGroup{} } func (g *unixGroup) Prepare(cmd *exec.Cmd) { if cmd.SysProcAttr == nil { cmd.SysProcAttr = &syscall.SysProcAttr{} } cmd.SysProcAttr.Setpgid = true } func (g *unixGroup) Adopt(cmd *exec.Cmd) error { if cmd.Process == nil { return errors.New("proc: Adopt before Start") } // Setpgid 使子进程成为新进程组组长,pgid == pid。 g.pgid = cmd.Process.Pid return nil } func (g *unixGroup) TerminateGroup(done <-chan struct{}, grace time.Duration) { if g.pgid <= 0 { return } // 向负 pgid 发信号 = 向整个进程组(含所有子孙)发信号。忽略 ESRCH 等错误。 _ = syscall.Kill(-g.pgid, syscall.SIGTERM) select { case <-done: return case <-time.After(grace): _ = syscall.Kill(-g.pgid, syscall.SIGKILL) } } func (g *unixGroup) Close() {}