pkg/pidfile, pkg/process: use single implementation for process alive

Using the implementation from pkg/pidfile for windows, as that implementation
looks to be handling more cases to check if a process is still alive (or to be
considered alive).

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn 2022-10-15 15:37:31 +02:00
parent 9d5e754caa
commit 55d15e9d05
No known key found for this signature in database
GPG key ID: 76698F39D527CE8C
6 changed files with 50 additions and 74 deletions

View file

@ -10,6 +10,7 @@ import (
"path/filepath"
"strconv"
"github.com/docker/docker/pkg/process"
"github.com/docker/docker/pkg/system"
)
@ -22,7 +23,7 @@ func checkPIDFileAlreadyExists(path string) error {
return err
}
pid, err := strconv.Atoi(string(bytes.TrimSpace(pidByte)))
if err == nil && processExists(pid) {
if err == nil && process.Alive(pid) {
return fmt.Errorf("pid file found, ensure docker is not running or delete %s", path)
}
return nil

View file

@ -1,15 +0,0 @@
//go:build darwin
// +build darwin
package pidfile // import "github.com/docker/docker/pkg/pidfile"
import (
"golang.org/x/sys/unix"
)
func processExists(pid int) bool {
// OS X does not have a proc filesystem.
// Use kill -0 pid to judge if the process exists.
err := unix.Kill(pid, 0)
return err == nil
}

View file

@ -1,17 +0,0 @@
//go:build !windows && !darwin
// +build !windows,!darwin
package pidfile // import "github.com/docker/docker/pkg/pidfile"
import (
"os"
"path/filepath"
"strconv"
)
func processExists(pid int) bool {
if _, err := os.Stat(filepath.Join("/proc", strconv.Itoa(pid))); err == nil {
return true
}
return false
}

View file

@ -1,30 +0,0 @@
package pidfile // import "github.com/docker/docker/pkg/pidfile"
import (
"golang.org/x/sys/windows"
)
func processExists(pid int) bool {
h, err := windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION, false, uint32(pid))
if err != nil {
return false
}
var c uint32
err = windows.GetExitCodeProcess(h, &c)
_ = windows.CloseHandle(h)
if err != nil {
// From the GetExitCodeProcess function (processthreadsapi.h) API docs:
// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getexitcodeprocess
//
// The GetExitCodeProcess function returns a valid error code defined by the
// application only after the thread terminates. Therefore, an application should
// not use STILL_ACTIVE (259) as an error code (STILL_ACTIVE is a macro for
// STATUS_PENDING (minwinbase.h)). If a thread returns STILL_ACTIVE (259) as
// an error code, then applications that test for that value could interpret it
// to mean that the thread is still running, and continue to test for the
// completion of the thread after the thread has terminated, which could put
// the application into an infinite loop.
return c == uint32(windows.STATUS_PENDING)
}
return true
}

View file

@ -1,5 +1,5 @@
//go:build linux || freebsd || darwin
// +build linux freebsd darwin
//go:build !windows
// +build !windows
package process
@ -7,18 +7,32 @@ import (
"bytes"
"fmt"
"os"
"path/filepath"
"runtime"
"strconv"
"golang.org/x/sys/unix"
)
// Alive returns true if process with a given pid is running.
func Alive(pid int) bool {
err := unix.Kill(pid, 0)
if err == nil || err == unix.EPERM {
return true
}
switch runtime.GOOS {
case "darwin":
// OS X does not have a proc filesystem. Use kill -0 pid to judge if the
// process exists. From KILL(2): https://www.freebsd.org/cgi/man.cgi?query=kill&sektion=2&manpath=OpenDarwin+7.2.1
//
// Sig may be one of the signals specified in sigaction(2) or it may
// be 0, in which case error checking is performed but no signal is
// actually sent. This can be used to check the validity of pid.
err := unix.Kill(pid, 0)
return false
// Either the PID was found (no error) or we get an EPERM, which means
// the PID exists, but we don't have permissions to signal it.
return err == nil || err == unix.EPERM
default:
_, err := os.Stat(filepath.Join("/proc", strconv.Itoa(pid)))
return err == nil
}
}
// Kill force-stops a process.

View file

@ -1,12 +1,35 @@
package process
import "os"
import (
"os"
"golang.org/x/sys/windows"
)
// Alive returns true if process with a given pid is running.
func Alive(pid int) bool {
_, err := os.FindProcess(pid)
return err == nil
h, err := windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION, false, uint32(pid))
if err != nil {
return false
}
var c uint32
err = windows.GetExitCodeProcess(h, &c)
_ = windows.CloseHandle(h)
if err != nil {
// From the GetExitCodeProcess function (processthreadsapi.h) API docs:
// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getexitcodeprocess
//
// The GetExitCodeProcess function returns a valid error code defined by the
// application only after the thread terminates. Therefore, an application should
// not use STILL_ACTIVE (259) as an error code (STILL_ACTIVE is a macro for
// STATUS_PENDING (minwinbase.h)). If a thread returns STILL_ACTIVE (259) as
// an error code, then applications that test for that value could interpret it
// to mean that the thread is still running, and continue to test for the
// completion of the thread after the thread has terminated, which could put
// the application into an infinite loop.
return c == uint32(windows.STATUS_PENDING)
}
return true
}
// Kill force-stops a process.