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 func (p *Process) pidfdWait() (*ProcessState, error) {
82
83
84
85
86
87
88
89 handle, status := p.handleTransientAcquire()
90 switch status {
91 case statusDone:
92
93
94
95 return nil, NewSyscallError("wait", syscall.ECHILD)
96 case statusReleased:
97 return nil, syscall.EINVAL
98 }
99 defer p.handleTransientRelease()
100
101 var (
102 info unix.SiginfoChild
103 rusage syscall.Rusage
104 )
105 err := ignoringEINTR(func() error {
106 return unix.Waitid(unix.P_PIDFD, int(handle), &info, syscall.WEXITED, &rusage)
107 })
108 if err != nil {
109 return nil, NewSyscallError("waitid", err)
110 }
111
112
113 p.handlePersistentRelease(statusDone)
114 return &ProcessState{
115 pid: int(info.Pid),
116 status: info.WaitStatus(),
117 rusage: &rusage,
118 }, nil
119 }
120
121 func (p *Process) pidfdSendSignal(s syscall.Signal) error {
122 handle, status := p.handleTransientAcquire()
123 switch status {
124 case statusDone:
125 return ErrProcessDone
126 case statusReleased:
127 return errors.New("os: process already released")
128 }
129 defer p.handleTransientRelease()
130
131 return convertESRCH(unix.PidFDSendSignal(handle, s))
132 }
133
134 func pidfdWorks() bool {
135 return checkPidfdOnce() == nil
136 }
137
138 var checkPidfdOnce = sync.OnceValue(checkPidfd)
139
140
141
142
143
144
145
146
147 func checkPidfd() error {
148
149
150 if runtime.GOOS == "android" {
151 ignoreSIGSYS()
152 defer restoreSIGSYS()
153 }
154
155
156
157 fd, err := unix.PidFDOpen(syscall.Getpid(), 0)
158 if err != nil {
159 return NewSyscallError("pidfd_open", err)
160 }
161 defer syscall.Close(int(fd))
162
163
164 err = ignoringEINTR(func() error {
165 return unix.Waitid(unix.P_PIDFD, int(fd), nil, syscall.WEXITED, nil)
166 })
167
168 if err != syscall.ECHILD {
169 return NewSyscallError("pidfd_wait", err)
170 }
171
172
173 if err := unix.PidFDSendSignal(fd, 0); err != nil {
174 return NewSyscallError("pidfd_send_signal", err)
175 }
176
177
178
179
180
181
182 if err := checkClonePidfd(); err != nil {
183 return err
184 }
185
186 return nil
187 }
188
189
190
191
192 func checkClonePidfd() error
193
194
195
196
197 func ignoreSIGSYS()
198
199
200 func restoreSIGSYS()
201
View as plain text