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 "errors"
20 "internal/syscall/unix"
21 "runtime"
22 "sync"
23 "syscall"
24 "unsafe"
25 )
26
27
28
29
30 func ensurePidfd(sysAttr *syscall.SysProcAttr) (*syscall.SysProcAttr, bool) {
31 if !pidfdWorks() {
32 return sysAttr, false
33 }
34
35 var pidfd int
36
37 if sysAttr == nil {
38 return &syscall.SysProcAttr{
39 PidFD: &pidfd,
40 }, false
41 }
42 if sysAttr.PidFD == nil {
43 newSys := *sysAttr
44 newSys.PidFD = &pidfd
45 return &newSys, false
46 }
47
48 return sysAttr, true
49 }
50
51
52
53 func getPidfd(sysAttr *syscall.SysProcAttr, needDup bool) (uintptr, bool) {
54 if !pidfdWorks() {
55 return 0, false
56 }
57
58 h := *sysAttr.PidFD
59 if needDup {
60 dupH, e := unix.Fcntl(h, syscall.F_DUPFD_CLOEXEC, 0)
61 if e != nil {
62 return 0, false
63 }
64 h = dupH
65 }
66 return uintptr(h), true
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 const _P_PIDFD = 3
83
84 func (p *Process) pidfdWait() (*ProcessState, error) {
85
86
87
88
89
90
91
92 handle, status := p.handleTransientAcquire()
93 switch status {
94 case statusDone:
95
96
97
98 return nil, NewSyscallError("wait", syscall.ECHILD)
99 case statusReleased:
100 return nil, syscall.EINVAL
101 }
102 defer p.handleTransientRelease()
103
104 var (
105 info unix.SiginfoChild
106 rusage syscall.Rusage
107 e syscall.Errno
108 )
109 for {
110 _, _, e = syscall.Syscall6(syscall.SYS_WAITID, _P_PIDFD, handle, uintptr(unsafe.Pointer(&info)), syscall.WEXITED, uintptr(unsafe.Pointer(&rusage)), 0)
111 if e != syscall.EINTR {
112 break
113 }
114 }
115 if e != 0 {
116 return nil, NewSyscallError("waitid", e)
117 }
118
119
120 p.handlePersistentRelease(statusDone)
121 return &ProcessState{
122 pid: int(info.Pid),
123 status: info.WaitStatus(),
124 rusage: &rusage,
125 }, nil
126 }
127
128 func (p *Process) pidfdSendSignal(s syscall.Signal) error {
129 handle, status := p.handleTransientAcquire()
130 switch status {
131 case statusDone:
132 return ErrProcessDone
133 case statusReleased:
134 return errors.New("os: process already released")
135 }
136 defer p.handleTransientRelease()
137
138 return convertESRCH(unix.PidFDSendSignal(handle, s))
139 }
140
141 func pidfdWorks() bool {
142 return checkPidfdOnce() == nil
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 for {
172 _, _, err = syscall.Syscall6(syscall.SYS_WAITID, _P_PIDFD, fd, 0, syscall.WEXITED, 0, 0)
173 if err != syscall.EINTR {
174 break
175 }
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