runtime: use pidfd to wait for processes on Linux

Use pidfd_open and poll on newer versions of Linux to wait
for the process to exit. For older versions use existing wait logic

Fixes: #5617

Signed-off-by: Alexandru Matei <alexandru.matei@uipath.com>
This commit is contained in:
Alexandru Matei 2022-11-21 12:05:43 +02:00
parent e9ba0c11d0
commit d04d45ea05
3 changed files with 65 additions and 4 deletions

View File

@ -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:

View File

@ -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)
}

View File

@ -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
}