Source file
src/os/pidfd_linux.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package os
17
18 import (
19 "internal/syscall/unix"
20 "runtime"
21 "sync"
22 "syscall"
23 _ "unsafe"
24 )
25
26
27
28
29 func ensurePidfd(sysAttr *syscall.SysProcAttr) (*syscall.SysProcAttr, bool) {
30 if !pidfdWorks() {
31 return sysAttr, false
32 }
33
34 var pidfd int
35
36 if sysAttr == nil {
37 return &syscall.SysProcAttr{
38 PidFD: &pidfd,
39 }, false
40 }
41 if sysAttr.PidFD == nil {
42 newSys := *sysAttr
43 newSys.PidFD = &pidfd
44 return &newSys, false
45 }
46
47 return sysAttr, true
48 }
49
50
51
52 func getPidfd(sysAttr *syscall.SysProcAttr, needDup bool) (uintptr, bool) {
53 if !pidfdWorks() {
54 return 0, false
55 }
56
57 h := *sysAttr.PidFD
58 if needDup {
59 dupH, e := unix.Fcntl(h, syscall.F_DUPFD_CLOEXEC, 0)
60 if e != nil {
61 return 0, false
62 }
63 h = dupH
64 }
65 return uintptr(h), true
66 }
67
68
69 func pidfdFind(pid int) (uintptr, error) {
70 if !pidfdWorks() {
71 return 0, syscall.ENOSYS
72 }
73
74 h, err := unix.PidFDOpen(pid, 0)
75 if err != nil {
76 return 0, convertESRCH(err)
77 }
78 return h, nil
79 }
80
81
82
83 func (p *Process) pidfdWait() (*ProcessState, error) {
84
85
86
87
88
89
90
91 handle, status := p.handleTransientAcquire()
92 switch status {
93 case statusDone:
94
95
96
97 return nil, NewSyscallError("wait", syscall.ECHILD)
98 case statusReleased:
99 return nil, syscall.EINVAL
100 }
101 defer p.handleTransientRelease()
102
103 var (
104 info unix.SiginfoChild
105 rusage syscall.Rusage
106 )
107 err := ignoringEINTR(func() error {
108 return unix.Waitid(unix.P_PIDFD, int(handle), &info, syscall.WEXITED, &rusage)
109 })
110 if err != nil {
111 return nil, NewSyscallError("waitid", err)
112 }
113
114
115
116 p.doRelease(statusDone)
117
118 return &ProcessState{
119 pid: int(info.Pid),
120 status: info.WaitStatus(),
121 rusage: &rusage,
122 }, nil
123 }
124
125
126 func (p *Process) pidfdSendSignal(s syscall.Signal) error {
127 handle, status := p.handleTransientAcquire()
128 switch status {
129 case statusDone:
130 return ErrProcessDone
131 case statusReleased:
132 return errProcessReleased
133 }
134 defer p.handleTransientRelease()
135
136 return convertESRCH(unix.PidFDSendSignal(handle, s))
137 }
138
139
140 func pidfdWorks() bool {
141 return checkPidfdOnce() == nil
142 }
143
144
145 var checkPidfdOnce = sync.OnceValue(checkPidfd)
146
147
148
149
150
151
152
153
154 func checkPidfd() error {
155
156
157 if runtime.GOOS == "android" {
158 ignoreSIGSYS()
159 defer restoreSIGSYS()
160 }
161
162
163
164 fd, err := unix.PidFDOpen(syscall.Getpid(), 0)
165 if err != nil {
166 return NewSyscallError("pidfd_open", err)
167 }
168 defer syscall.Close(int(fd))
169
170
171 err = ignoringEINTR(func() error {
172 var info unix.SiginfoChild
173
174
175 return unix.Waitid(unix.P_PIDFD, int(fd), &info, syscall.WEXITED, nil)
176 })
177
178 if err != syscall.ECHILD {
179 return NewSyscallError("pidfd_wait", err)
180 }
181
182
183 if err := unix.PidFDSendSignal(fd, 0); err != nil {
184 return NewSyscallError("pidfd_send_signal", err)
185 }
186
187
188
189
190
191
192 if err := checkClonePidfd(); err != nil {
193 return err
194 }
195
196 return nil
197 }
198
199
200
201
202 func checkClonePidfd() error
203
204
205
206
207 func ignoreSIGSYS()
208
209
210 func restoreSIGSYS()
211
View as plain text