Skip to content

Commit cdf3249

Browse files
kolyshkinprattmic
authored andcommitted
os: make FindProcess use pidfd on Linux
Amend FindProcess to use pidfdFind, and make it return ErrProcessDone if pidfdFind is used and the process is not found. Since this is a change in API, introduce GODEBUG osfinderr=0 setting to disable the feature. Change-Id: I724c6f622f0c99f21a70b864cf7cf2b8836869ee Reviewed-on: https://go-review.googlesource.com/c/go/+/542699 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> Reviewed-by: Than McIntosh <[email protected]>
1 parent ccb6077 commit cdf3249

File tree

7 files changed

+50
-3
lines changed

7 files changed

+50
-3
lines changed

doc/godebug.md

+5
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,11 @@ for example,
126126
see the [runtime documentation](/pkg/runtime#hdr-Environment_Variables)
127127
and the [go command documentation](/cmd/go#hdr-Build_and_test_caching).
128128

129+
### Go 1.23
130+
131+
Go 1.23 enabled Linux pidfd support for process lookup. This feature can be
132+
disabled by using the [`osfinderr` setting](/pkg/os#FindProcess).
133+
129134
### Go 1.22
130135

131136
Go 1.22 adds a configurable limit to control the maximum acceptable RSA key size

src/internal/godebugs/table.go

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ var All = []Info{
4242
{Name: "multipartmaxparts", Package: "mime/multipart"},
4343
{Name: "multipathtcp", Package: "net"},
4444
{Name: "netdns", Package: "net", Opaque: true},
45+
{Name: "osfinderr", Package: "os"},
4546
{Name: "panicnil", Package: "runtime", Changed: 21, Old: "1"},
4647
{Name: "randautoseed", Package: "math/rand"},
4748
{Name: "tarinsecurepath", Package: "archive/tar"},

src/os/exec.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,17 @@ func Getppid() int { return syscall.Getppid() }
8686
// The Process it returns can be used to obtain information
8787
// about the underlying operating system process.
8888
//
89-
// On Unix systems, FindProcess always succeeds and returns a Process
89+
// On Unix systems other than Linux, FindProcess always succeeds and returns a Process
9090
// for the given pid, regardless of whether the process exists. To test whether
9191
// the process actually exists, see whether p.Signal(syscall.Signal(0)) reports
9292
// an error.
93+
//
94+
// On Linux, FindProcess may either return ErrProcessGone for a non-existing
95+
// process (thus eliminating the need to use a signal to check if the process
96+
// exists), or work the same way as for other Unix systems, described above,
97+
// depending on the kernel version used and the system configuration. The old
98+
// behavior (of always succeeding) can be enforced by using GODEBUG setting
99+
// osfinderr=0.
93100
func FindProcess(pid int) (*Process, error) {
94101
return findProcess(pid)
95102
}

src/os/exec_unix.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,14 @@ func (p *Process) release() error {
106106
}
107107

108108
func findProcess(pid int) (p *Process, err error) {
109-
// NOOP for unix.
110-
return newProcess(pid, unsetHandle), nil
109+
h, err := pidfdFind(pid)
110+
if err == ErrProcessDone {
111+
return nil, err
112+
}
113+
// Ignore all other errors from pidfdFind,
114+
// as the callers do not expect them, and
115+
// we can use pid anyway.
116+
return newProcess(pid, h), nil
111117
}
112118

113119
func (p *ProcessState) userTime() time.Duration {

src/os/pidfd_linux.go

+20
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
package os
1515

1616
import (
17+
"internal/godebug"
1718
"internal/syscall/unix"
1819
"sync"
1920
"syscall"
@@ -49,6 +50,25 @@ func getPidfd(sysAttr *syscall.SysProcAttr) uintptr {
4950
return uintptr(*sysAttr.PidFD)
5051
}
5152

53+
var osfinderr = godebug.New("osfinderr")
54+
55+
func pidfdFind(pid int) (uintptr, error) {
56+
if !pidfdWorks() {
57+
return unsetHandle, syscall.ENOSYS
58+
}
59+
if osfinderr.Value() == "0" {
60+
osfinderr.IncNonDefault()
61+
return unsetHandle, syscall.ENOSYS
62+
63+
}
64+
65+
h, err := unix.PidFDOpen(pid, 0)
66+
if err == nil {
67+
return h, nil
68+
}
69+
return unsetHandle, convertESRCH(err)
70+
}
71+
5272
func (p *Process) pidfdRelease() {
5373
// Release pidfd unconditionally.
5474
handle := p.handle.Swap(unsetHandle)

src/os/pidfd_other.go

+4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ func getPidfd(_ *syscall.SysProcAttr) uintptr {
1616
return unsetHandle
1717
}
1818

19+
func pidfdFind(_ int) (uintptr, error) {
20+
return unsetHandle, syscall.ENOSYS
21+
}
22+
1923
func (p *Process) pidfdRelease() {}
2024

2125
func (_ *Process) pidfdWait() (*ProcessState, error) {

src/runtime/metrics/doc.go

+4
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,10 @@ Below is the full list of supported metrics, ordered lexicographically.
290290
The number of non-default behaviors executed by the net package
291291
due to a non-default GODEBUG=multipathtcp=... setting.
292292
293+
/godebug/non-default-behavior/osfinderr:events
294+
The number of non-default behaviors executed by the os package
295+
due to a non-default GODEBUG=osfinderr=... setting.
296+
293297
/godebug/non-default-behavior/panicnil:events
294298
The number of non-default behaviors executed by the runtime
295299
package due to a non-default GODEBUG=panicnil=... setting.

0 commit comments

Comments
 (0)