diff --git a/src/os/exec_test.go b/src/os/exec_test.go index b49dd0dd914..07a06ec0ff3 100644 --- a/src/os/exec_test.go +++ b/src/os/exec_test.go @@ -6,7 +6,6 @@ package os_test import ( "internal/testenv" - "math" "os" "os/signal" "runtime" @@ -76,28 +75,3 @@ func TestProcessReleaseTwice(t *testing.T) { t.Fatalf("second Release: got err %v, want %v", err, want) } } - -// Lookup of a process that does not exist at time of lookup. -func TestProcessAlreadyDone(t *testing.T) { - if runtime.GOOS == "windows" { - t.Skip("Windows does not support lookup of non-existant process") - } - if runtime.GOARCH == "wasm" { - t.Skip("Wait not supported om wasm port") - } - - // Theoretically MaxInt32 is a valid PID, but the chance of it actually - // being used is extremely unlikely. - p, err := os.FindProcess(math.MaxInt32) - if err != nil { - t.Fatalf("FindProcess(math.MaxInt32) got err %v, want nil", err) - } - - if ps, err := p.Wait(); err != os.ErrProcessDone { - t.Errorf("Wait() got err %v (ps %+v), want ErrProcessDone", err, ps) - } - - if err := p.Release(); err != nil { - t.Errorf("Release() got err %v, want nil", err) - } -} diff --git a/src/os/exec_unix_test.go b/src/os/exec_unix_test.go index 69bcdbdad18..81d8e1cfee6 100644 --- a/src/os/exec_unix_test.go +++ b/src/os/exec_unix_test.go @@ -7,8 +7,11 @@ package os_test import ( + "errors" "internal/testenv" + "math" . "os" + "runtime" "syscall" "testing" ) @@ -27,6 +30,33 @@ func TestErrProcessDone(t *testing.T) { } } +// Lookup of a process that does not exist at time of lookup. +func TestProcessAlreadyDone(t *testing.T) { + // Theoretically MaxInt32 is a valid PID, but the chance of it actually + // being used is extremely unlikely. + pid := math.MaxInt32 + if runtime.GOOS == "solaris" || runtime.GOOS == "illumos" { + // Solaris/Illumos have a lower limit, above which wait returns + // EINVAL (see waitid in usr/src/uts/common/os/exit.c in + // illumos). This is configurable via sysconf(_SC_MAXPID), but + // we'll just take the default. + pid = 30000-1 + } + + p, err := FindProcess(pid) + if err != nil { + t.Fatalf("FindProcess(math.MaxInt32) got err %v, want nil", err) + } + + if ps, err := p.Wait(); !errors.Is(err, syscall.ECHILD) { + t.Errorf("Wait() got err %v (ps %+v), want %v", err, ps, syscall.ECHILD) + } + + if err := p.Release(); err != nil { + t.Errorf("Release() got err %v, want nil", err) + } +} + func TestUNIXProcessAlive(t *testing.T) { testenv.MustHaveGoBuild(t) t.Parallel() diff --git a/src/os/pidfd_linux.go b/src/os/pidfd_linux.go index c71c366de63..0404c4ff64b 100644 --- a/src/os/pidfd_linux.go +++ b/src/os/pidfd_linux.go @@ -74,7 +74,10 @@ func (p *Process) pidfdWait() (*ProcessState, error) { handle, status := p.handleTransientAcquire() switch status { case statusDone: - return nil, ErrProcessDone + // Process already completed Wait, or was not found by + // pidfdFind. Return ECHILD for consistency with what the wait + // syscall would return. + return nil, NewSyscallError("wait", syscall.ECHILD) case statusReleased: return nil, syscall.EINVAL } diff --git a/src/os/pidfd_linux_test.go b/src/os/pidfd_linux_test.go index 2f567eed409..837593706ba 100644 --- a/src/os/pidfd_linux_test.go +++ b/src/os/pidfd_linux_test.go @@ -5,8 +5,10 @@ package os_test import ( + "errors" "internal/testenv" "os" + "syscall" "testing" ) @@ -47,7 +49,7 @@ func TestFindProcessViaPidfd(t *testing.T) { if err := proc.Signal(os.Kill); err != os.ErrProcessDone { t.Errorf("Signal: got %v, want %v", err, os.ErrProcessDone) } - if _, err := proc.Wait(); err != os.ErrProcessDone { + if _, err := proc.Wait(); !errors.Is(err, syscall.ECHILD) { t.Errorf("Wait: got %v, want %v", err, os.ErrProcessDone) } // Release never returns errors on Unix.