diff --git a/src/runtime/virtcontainers/utils/utils.go b/src/runtime/virtcontainers/utils/utils.go index 9c0526da6d..bac62e8cfd 100644 --- a/src/runtime/virtcontainers/utils/utils.go +++ b/src/runtime/virtcontainers/utils/utils.go @@ -346,10 +346,6 @@ func waitProcessUsingWaitLoop(pid int, timeoutSecs uint, logger *logrus.Entry) b } } -func waitForProcessCompletion(pid int, timeoutSecs uint, logger *logrus.Entry) bool { - return waitProcessUsingWaitLoop(pid, timeoutSecs, logger) -} - // WaitLocalProcess waits for the specified process for up to timeoutSecs seconds. // // Notes: diff --git a/src/runtime/virtcontainers/utils/utils_darwin.go b/src/runtime/virtcontainers/utils/utils_darwin.go index 54b2124ce1..db1d9ea750 100644 --- a/src/runtime/virtcontainers/utils/utils_darwin.go +++ b/src/runtime/virtcontainers/utils/utils_darwin.go @@ -5,6 +5,12 @@ package utils +import "github.com/sirupsen/logrus" + func GetDevicePathAndFsTypeOptions(mountPoint string) (devicePath, fsType string, fsOptions []string, err error) { return } + +func waitForProcessCompletion(pid int, timeoutSecs uint, logger *logrus.Entry) bool { + return waitProcessUsingWaitLoop(pid, timeoutSecs, logger) +} diff --git a/src/runtime/virtcontainers/utils/utils_linux.go b/src/runtime/virtcontainers/utils/utils_linux.go index c223fb93bb..40c5c360ea 100644 --- a/src/runtime/virtcontainers/utils/utils_linux.go +++ b/src/runtime/virtcontainers/utils/utils_linux.go @@ -14,8 +14,10 @@ import ( "os" "strings" "syscall" + "time" "unsafe" + "github.com/sirupsen/logrus" "golang.org/x/sys/unix" ) @@ -151,3 +153,60 @@ func IsAPVFIOMediatedDevice(sysfsdev string) bool { } return false } + +func waitProcessUsingPidfd(pid int, timeoutSecs uint, logger *logrus.Entry) (bool, error) { + pidfd, err := unix.PidfdOpen(pid, 0) + + if err != nil { + if err == unix.ESRCH { + return false, nil + } + + return true, err + } + + defer unix.Close(pidfd) + var n int + + maxDelay := time.Duration(timeoutSecs) * time.Second + end := time.Now().Add(maxDelay) + + for { + remaining := time.Until(end).Milliseconds() + if remaining < 0 { + remaining = 0 + } + + n, err = unix.Poll([]unix.PollFd{{Fd: int32(pidfd), Events: unix.POLLIN}}, int(remaining)) + if err != unix.EINTR { + break + } + } + + if err != nil || n != 1 { + logger.Warnf("process %v still running after waiting %ds", pid, timeoutSecs) + return true, err + } + + for { + err := unix.Waitid(unix.P_PIDFD, pidfd, nil, unix.WEXITED, nil) + if err == unix.EINVAL { + err = unix.Waitid(unix.P_PID, pid, nil, unix.WEXITED, nil) + } + + if err != unix.EINTR { + break + } + } + return false, nil +} + +func waitForProcessCompletion(pid int, timeoutSecs uint, logger *logrus.Entry) bool { + pidRunning, err := waitProcessUsingPidfd(pid, timeoutSecs, logger) + + if err == unix.ENOSYS { + pidRunning = waitProcessUsingWaitLoop(pid, timeoutSecs, logger) + } + + return pidRunning +}