Source file
src/os/pidfd_linux_test.go
1
2
3
4
5 package os_test
6
7 import (
8 "errors"
9 "internal/syscall/unix"
10 "internal/testenv"
11 "os"
12 "os/exec"
13 "syscall"
14 "testing"
15 )
16
17 func TestFindProcessViaPidfd(t *testing.T) {
18 testenv.MustHaveGoBuild(t)
19 t.Parallel()
20
21 if err := os.CheckPidfdOnce(); err != nil {
22
23 t.Skipf("skipping: pidfd not available: %v", err)
24 }
25
26 p, err := os.StartProcess(testenv.GoToolPath(t), []string{"go"}, &os.ProcAttr{})
27 if err != nil {
28 t.Fatalf("starting test process: %v", err)
29 }
30 p.Wait()
31
32
33 proc, err := os.FindProcess(p.Pid)
34
35 if err != nil {
36 t.Fatalf("FindProcess: got error %v, want <nil>", err)
37 }
38
39 if proc == nil {
40 t.Fatal("FindProcess: got nil, want non-nil")
41 }
42 if proc.Status() != os.StatusDone {
43 t.Fatalf("got process status: %v, want %d", proc.Status(), os.StatusDone)
44 }
45
46
47
48 if err := proc.Kill(); err != os.ErrProcessDone {
49 t.Errorf("Kill: got %v, want %v", err, os.ErrProcessDone)
50 }
51 if err := proc.Signal(os.Kill); err != os.ErrProcessDone {
52 t.Errorf("Signal: got %v, want %v", err, os.ErrProcessDone)
53 }
54 if _, err := proc.Wait(); !errors.Is(err, syscall.ECHILD) {
55 t.Errorf("Wait: got %v, want %v", err, os.ErrProcessDone)
56 }
57
58 if err := proc.Release(); err != nil {
59 t.Fatalf("Release: got %v, want <nil>", err)
60 }
61 }
62
63 func TestStartProcessWithPidfd(t *testing.T) {
64 testenv.MustHaveGoBuild(t)
65 t.Parallel()
66
67 if err := os.CheckPidfdOnce(); err != nil {
68
69 t.Skipf("skipping: pidfd not available: %v", err)
70 }
71
72 var pidfd int
73 p, err := os.StartProcess(testenv.GoToolPath(t), []string{"go"}, &os.ProcAttr{
74 Sys: &syscall.SysProcAttr{
75 PidFD: &pidfd,
76 },
77 })
78 if err != nil {
79 t.Fatalf("starting test process: %v", err)
80 }
81 defer syscall.Close(pidfd)
82
83 if _, err := p.Wait(); err != nil {
84 t.Fatalf("Wait: got %v, want <nil>", err)
85 }
86
87
88 err = unix.PidFDSendSignal(uintptr(pidfd), syscall.Signal(0))
89 if !errors.Is(err, syscall.ESRCH) {
90 t.Errorf("SendSignal: got %v, want %v", err, syscall.ESRCH)
91 }
92 }
93
94
95 func TestPidfdLeak(t *testing.T) {
96 testenv.MustHaveExec(t)
97 exe, err := os.Executable()
98 if err != nil {
99 t.Fatal(err)
100 }
101
102
103
104
105 const count = 10
106 want := make([]int, count)
107 for i := range count {
108 var err error
109 want[i], err = syscall.Open(exe, syscall.O_RDONLY, 0)
110 if err != nil {
111 t.Fatal(err)
112 }
113 }
114
115
116 for _, d := range want {
117 syscall.Close(d)
118 }
119
120
121 for range 10 {
122
123
124
125 cmd := exec.Command("/noSuchExecutable")
126 cmd.Run()
127 }
128
129
130 got := make([]int, count)
131 for i := range count {
132 var err error
133 got[i], err = syscall.Open(exe, syscall.O_RDONLY, 0)
134 if err != nil {
135 t.Fatal(err)
136 }
137 }
138
139
140 for _, d := range got {
141 syscall.Close(d)
142 }
143
144 t.Logf("got %v", got)
145 t.Logf("want %v", want)
146
147
148 if got[count-1] > want[count-1]+5 {
149 t.Errorf("got descriptor %d, want %d", got[count-1], want[count-1])
150 }
151 }
152
View as plain text