返回 DeepSeek-Reasonix
kill_other.go
根目录 / internal / proc / kill_other.go
1 //go:build !windows
2
3 package proc
4
5 import (
6 "os/exec"
7 "syscall"
8 )
9
10 // KillTree kills cmd's whole process group. StartTracked (and
11 // SetProcessGroupKill for children started outside it) put the child in a new
12 // session/process group, so the negative-pid signal reaches every descendant,
13 // including a launcher whose sub-daemon survives the parent, where a plain
14 // Process.Kill would only hit the direct child and orphan the grandchild.
15 func KillTree(cmd *exec.Cmd) {
16 if cmd == nil || cmd.Process == nil {
17 return
18 }
19 if err := syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL); err != nil {
20 _ = cmd.Process.Kill() // not a group leader — at least kill the child
21 }
22 }
23
24 // SetProcessGroupKill makes cmd start in its own session/process group so
25 // KillTree can reap its whole tree. The new session also keeps interactive
26 // children from taking over the caller's controlling terminal. Use it for
27 // children started outside StartTracked (e.g. a one-shot CombinedOutput). It is
28 // a no-op on Windows, where the Job Object that TrackTree/StartTracked assigns
29 // handles the tree instead.
30 func SetProcessGroupKill(cmd *exec.Cmd) {
31 if cmd.SysProcAttr == nil {
32 cmd.SysProcAttr = &syscall.SysProcAttr{}
33 }
34 cmd.SysProcAttr.Setsid = true
35 }
36
37 // StartTracked starts cmd in its own session/process group so KillTracked /
38 // KillTree can reap its whole tree. Off Windows the process group is the
39 // equivalent of the Windows Job Object; it returns a 0 handle, and KillTracked
40 // falls back to KillTree.
41 func StartTracked(cmd *exec.Cmd) (uintptr, error) {
42 SetProcessGroupKill(cmd)
43 return 0, cmd.Start()
44 }
45
46 // StartTrackedRequired uses the same process-group guarantee off Windows.
47 func StartTrackedRequired(cmd *exec.Cmd) (uintptr, error) { return StartTracked(cmd) }
48
49 // KillTracked terminates cmd's process tree; the handle is unused off Windows.
50 func KillTracked(cmd *exec.Cmd, _ uintptr) { KillTree(cmd) }
51
52 // FinishTracked is a no-op off Windows, where StartTracked owns no OS handle.
53 func FinishTracked(uintptr) {}
54
54 lines GO