aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKir Kolyshkin <kolyshkin@gmail.com>2023-11-16 01:42:39 -0800
committerMichael Pratt <mpratt@google.com>2024-02-21 21:27:03 +0000
commitcdf3249d74c4187bc0c1737e1bb6ab1aa52c0b6f (patch)
tree1d1d02c2e659731e51349dadc12eace835631c43 /src
parentccb6077d11e9e70cb17d3eaadaee4e673ee650c2 (diff)
downloadgo-cdf3249d74c4187bc0c1737e1bb6ab1aa52c0b6f.tar.xz
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 <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Ian Lance Taylor <iant@google.com> Reviewed-by: Than McIntosh <thanm@google.com>
Diffstat (limited to 'src')
-rw-r--r--src/internal/godebugs/table.go1
-rw-r--r--src/os/exec.go9
-rw-r--r--src/os/exec_unix.go10
-rw-r--r--src/os/pidfd_linux.go20
-rw-r--r--src/os/pidfd_other.go4
-rw-r--r--src/runtime/metrics/doc.go4
6 files changed, 45 insertions, 3 deletions
diff --git a/src/internal/godebugs/table.go b/src/internal/godebugs/table.go
index a0a0672966..4ac306b323 100644
--- a/src/internal/godebugs/table.go
+++ b/src/internal/godebugs/table.go
@@ -42,6 +42,7 @@ var All = []Info{
{Name: "multipartmaxparts", Package: "mime/multipart"},
{Name: "multipathtcp", Package: "net"},
{Name: "netdns", Package: "net", Opaque: true},
+ {Name: "osfinderr", Package: "os"},
{Name: "panicnil", Package: "runtime", Changed: 21, Old: "1"},
{Name: "randautoseed", Package: "math/rand"},
{Name: "tarinsecurepath", Package: "archive/tar"},
diff --git a/src/os/exec.go b/src/os/exec.go
index 42e8a399a9..7ef1fee595 100644
--- a/src/os/exec.go
+++ b/src/os/exec.go
@@ -86,10 +86,17 @@ func Getppid() int { return syscall.Getppid() }
// The Process it returns can be used to obtain information
// about the underlying operating system process.
//
-// On Unix systems, FindProcess always succeeds and returns a Process
+// On Unix systems other than Linux, FindProcess always succeeds and returns a Process
// for the given pid, regardless of whether the process exists. To test whether
// the process actually exists, see whether p.Signal(syscall.Signal(0)) reports
// an error.
+//
+// On Linux, FindProcess may either return ErrProcessGone for a non-existing
+// process (thus eliminating the need to use a signal to check if the process
+// exists), or work the same way as for other Unix systems, described above,
+// depending on the kernel version used and the system configuration. The old
+// behavior (of always succeeding) can be enforced by using GODEBUG setting
+// osfinderr=0.
func FindProcess(pid int) (*Process, error) {
return findProcess(pid)
}
diff --git a/src/os/exec_unix.go b/src/os/exec_unix.go
index 2c66a8be20..21d03da48e 100644
--- a/src/os/exec_unix.go
+++ b/src/os/exec_unix.go
@@ -106,8 +106,14 @@ func (p *Process) release() error {
}
func findProcess(pid int) (p *Process, err error) {
- // NOOP for unix.
- return newProcess(pid, unsetHandle), nil
+ h, err := pidfdFind(pid)
+ if err == ErrProcessDone {
+ return nil, err
+ }
+ // Ignore all other errors from pidfdFind,
+ // as the callers do not expect them, and
+ // we can use pid anyway.
+ return newProcess(pid, h), nil
}
func (p *ProcessState) userTime() time.Duration {
diff --git a/src/os/pidfd_linux.go b/src/os/pidfd_linux.go
index d6e1d53eee..cc67dfa05f 100644
--- a/src/os/pidfd_linux.go
+++ b/src/os/pidfd_linux.go
@@ -14,6 +14,7 @@
package os
import (
+ "internal/godebug"
"internal/syscall/unix"
"sync"
"syscall"
@@ -49,6 +50,25 @@ func getPidfd(sysAttr *syscall.SysProcAttr) uintptr {
return uintptr(*sysAttr.PidFD)
}
+var osfinderr = godebug.New("osfinderr")
+
+func pidfdFind(pid int) (uintptr, error) {
+ if !pidfdWorks() {
+ return unsetHandle, syscall.ENOSYS
+ }
+ if osfinderr.Value() == "0" {
+ osfinderr.IncNonDefault()
+ return unsetHandle, syscall.ENOSYS
+
+ }
+
+ h, err := unix.PidFDOpen(pid, 0)
+ if err == nil {
+ return h, nil
+ }
+ return unsetHandle, convertESRCH(err)
+}
+
func (p *Process) pidfdRelease() {
// Release pidfd unconditionally.
handle := p.handle.Swap(unsetHandle)
diff --git a/src/os/pidfd_other.go b/src/os/pidfd_other.go
index 1918acbec5..bb38c72404 100644
--- a/src/os/pidfd_other.go
+++ b/src/os/pidfd_other.go
@@ -16,6 +16,10 @@ func getPidfd(_ *syscall.SysProcAttr) uintptr {
return unsetHandle
}
+func pidfdFind(_ int) (uintptr, error) {
+ return unsetHandle, syscall.ENOSYS
+}
+
func (p *Process) pidfdRelease() {}
func (_ *Process) pidfdWait() (*ProcessState, error) {
diff --git a/src/runtime/metrics/doc.go b/src/runtime/metrics/doc.go
index fb2f44da29..d1c2f8aa25 100644
--- a/src/runtime/metrics/doc.go
+++ b/src/runtime/metrics/doc.go
@@ -290,6 +290,10 @@ Below is the full list of supported metrics, ordered lexicographically.
The number of non-default behaviors executed by the net package
due to a non-default GODEBUG=multipathtcp=... setting.
+ /godebug/non-default-behavior/osfinderr:events
+ The number of non-default behaviors executed by the os package
+ due to a non-default GODEBUG=osfinderr=... setting.
+
/godebug/non-default-behavior/panicnil:events
The number of non-default behaviors executed by the runtime
package due to a non-default GODEBUG=panicnil=... setting.