-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathterminator.go
101 lines (92 loc) · 2.8 KB
/
terminator.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package terminator
import (
"context"
"fmt"
"time"
"github.com/cockroachdb/errors"
"github.com/shirou/gopsutil/v4/process"
)
// Kill is the same as KillWithContext with background context.
func Kill(pid int) error {
return KillWithContext(context.Background(), pid)
}
// KillWithContext kills process with PID `pid` using context `ctx`.
func KillWithContext(ctx context.Context, pid int) error {
select {
case <-ctx.Done():
return errors.Wrap(ctx.Err(), fmt.Sprintf("Kill process with PID %v", pid))
default:
break
}
proc, err := process.NewProcess(int32(pid))
if err != nil {
return errors.Wrap(err, fmt.Sprintf("Kill process with PID %v", pid))
}
return errors.Wrap(proc.Kill(), fmt.Sprintf("Kill process with PID %v", pid))
}
// WaitForProcStop returns when process with PID `pid` is no longer running or `ctx` deadline exceedes.
func WaitForProcStop(ctx context.Context, pid int) {
proc, err := process.NewProcess(int32(pid))
if err != nil {
return
}
ticker := time.NewTicker(time.Millisecond * 100)
for {
select {
case <-ticker.C:
if running, _ := proc.IsRunning(); !running {
return
}
case <-ctx.Done():
return
}
}
}
// FlatChildTree returns gopsutil Process instances of all descendants of a process with the specified PID `pid`.
//
// The first element is deepest descendant. The last one is a progenitor or closest child.
//
// If the `withRoot` argument is set to true, add root process to the end.
func FlatChildTree(pid int, withRoot bool) ([]*process.Process, error) {
tree := []*process.Process{}
proc, err := process.NewProcess(int32(pid))
if err != nil {
return tree, errors.Wrap(err, "Get flat child process tree")
}
err = flatChildTree(proc, &tree, withRoot)
if err != nil {
return tree, errors.Wrap(err, "Get flat child process tree")
}
return tree, nil
}
// flatChildTree populates the `tree` argument with gopsutil Process instances of all descendants of the specified
// process `proc`.
//
// The first element in the tree is deepest descendant. The last one is a progenitor or closest child.
//
// If the `withRoot` argument is set to true, add the root process to the end.
func flatChildTree(proc *process.Process, tree *[]*process.Process, withRoot bool) error {
children, err := proc.Children()
if errors.Is(err, process.ErrorNoChildren) {
return nil
}
if err != nil {
return errors.Wrap(err, fmt.Sprintf("Get flat process tree for PID %v", proc.Pid))
}
// Iterate for each child process in reverse order.
for i := len(children) - 1; i >= 0; i-- {
child := children[i]
// Call self to collect descendants.
err := flatChildTree(child, tree, false)
if err != nil {
return err
}
// Add the child after it's descendants.
*tree = append(*tree, child)
}
// Add the root process to the end.
if withRoot {
*tree = append(*tree, proc)
}
return nil
}