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
70 func pidfdFind(pid int) (uintptr, error) {
71 if !pidfdWorks() {
72 return 0, syscall.ENOSYS
73 }
74
75 h, err := unix.PidFDOpen(pid, 0)
76 if err != nil {
77 return 0, convertESRCH(err)
78 }
79 return h, nil
80 }
81
82
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 )
108 err := ignoringEINTR(func() error {
109 return unix.Waitid(unix.P_PIDFD, int(handle), &info, syscall.WEXITED, &rusage)
110 })
111 if err != nil {
112 return nil, NewSyscallError("waitid", err)
113 }
114
115
116
117 p.doRelease(statusDone)
118
119 return &ProcessState{
120 pid: int(info.Pid),
121 status: info.WaitStatus(),
122 rusage: &rusage,
123 }, nil
124 }
125
126
127 func (p *Process) pidfdSendSignal(s syscall.Signal) error {
128 handle, status := p.handleTransientAcquire()
129 switch status {
130 case statusDone:
131 return ErrProcessDone
132 case statusReleased:
133 return errors.New("os: process already released")
134 }
135 defer p.handleTransientRelease()
136
137 return convertESRCH(unix.PidFDSendSignal(handle, s))
138 }
139
140
141 func pidfdWorks() bool {
142 return checkPidfdOnce() == nil
143 }
144
145
146 var checkPidfdOnce = sync.OnceValue(checkPidfd)
147
148
149
150
151
152
153
154
155 func checkPidfd() error {
156
157
158 if runtime.GOOS == "android" {
159 ignoreSIGSYS()
160 defer restoreSIGSYS()
161 }
162
163
164
165 fd, err := unix.PidFDOpen(syscall.Getpid(), 0)
166 if err != nil {
167 return NewSyscallError("pidfd_open", err)
168 }
169 defer syscall.Close(int(fd))
170
171
172 err = ignoringEINTR(func() error {
173 return unix.Waitid(unix.P_PIDFD, int(fd), nil, syscall.WEXITED, nil)
174 })
175
176 if err != syscall.ECHILD {
177 return NewSyscallError("pidfd_wait", err)
178 }
179
180
181 if err := unix.PidFDSendSignal(fd, 0); err != nil {
182 return NewSyscallError("pidfd_send_signal", err)
183 }
184
185
186
187
188
189
190 if err := checkClonePidfd(); err != nil {
191 return err
192 }
193
194 return nil
195 }
196
197
198
199
200 func checkClonePidfd() error
201
202
203
204
205 func ignoreSIGSYS()
206
207
208 func restoreSIGSYS()
209
View as plain text