libct: simplify exec fifo wait using poll(2)#5271
Conversation
e91e67c to
1889c08
Compare
| // or the init process has exited. It does not consume the data — it only | ||
| // returns once a subsequent read on f will not block indefinitely. | ||
| func waitForFifoReady(f *os.File, pid int) error { | ||
| pidFd, err := unix.PidfdOpen(pid, 0) |
There was a problem hiding this comment.
You can use https://pkg.go.dev/os#Process.WithHandle here:
proc, _ := os.FindProcess(pid) // or add process() to parentProcess interface
var readyErr error
err := proc.WithHandle(func(pidfd uintptr) {
readyErr = waitForReadyPidfd(f, int(pidfd))
})
if err != nil { // pidfd not supported
return waitForFifoReadyPolling(f, pid)
}This works better because WithHandle will only call the function if pidfd is fully supported by the kernel (there are many kernels with different nuances and you can rely on the Go runtime check).
There was a problem hiding this comment.
os.Process.WithHandle became available in Go 1.26 but runc's go.mod is currently at go 1.25.0. We'll need to bump the version or I can continue using raw unix.PidfOpen for now.
There was a problem hiding this comment.
Maybe add a // TODO: switch to os.Process.WithHandle once go < 1.26 is no longer supported. or somesuch.
kolyshkin
left a comment
There was a problem hiding this comment.
Thanks for working on this! Left a few comments, but overall this looks good.
|
this is nice one |
73c4cd4 to
460ea7f
Compare
460ea7f to
72a9bd5
Compare
72a9bd5 to
79e2c6d
Compare
lifubang
left a comment
There was a problem hiding this comment.
Great refactoring work! LGTM overall, with a few minor nits.
| // ENOSYS: kernel < 5.3, no pidfd_open at all. | ||
| // ESRCH: process is already gone — fall through to the polling path, | ||
| // which will detect the dead process on its first liveness check. | ||
| // Other errors (EINVAL, EMFILE, etc.) are unexpected; bail. |
There was a problem hiding this comment.
Maybe we need to deal with EMFILE, for example in dind.
So I think we should fall through to the polling path anyway once we got an error:
func waitForFifoReady(f *os.File, pid int) error {
// TODO: switch to os.Process.WithHandle once go < 1.26 is no longer supported.
pidFd, err := unix.PidfdOpen(pid, 0)
if err == nil {
defer unix.Close(pidFd)
return waitForFifoReadyPidfd(f, pidFd)
}
// fall through to the polling path.
return waitForFifoReadyPolling(f, pid)
}There was a problem hiding this comment.
those errors wouldn't warrant a hard fail. got it
| if err != nil { | ||
| return fmt.Errorf("poll exec fifo: %w", err) | ||
| } | ||
| if n > 0 && pfd[0].Revents&unix.POLLIN != 0 { |
There was a problem hiding this comment.
Maybe we can add a POLLHUP check to reduce a system.Stat call in some situations:
if n > 0 && pfd[0].Revents&(unix.POLLIN|unix.POLLHUP) != 0 {79e2c6d to
78c6c52
Compare
| if n > 0 && pfd[0].Revents&(unix.POLLIN|unix.POLLHUP) != 0 { | ||
| return nil | ||
| } | ||
| // If init is dead, fall |
There was a problem hiding this comment.
nit: The line break here splits "fall through", which reads awkwardly. Suggest merging this comment into a single line.
78c6c52 to
2cc449c
Compare
2cc449c to
7785938
Compare
Please avoid modifying unrelated lines in your last force push.
ed376c2 to
02b8153
Compare
02b8153 to
5f365bd
Compare
Replace the goroutine + channel + 100ms time.After + blocking open in handleFifo with a poll(2) loop on a non-blocking open. Use pidfd_open(2) where available to wait for init exit without timeout, falling back to /proc state checks with 100ms timeout on older kernels. Fixes opencontainers#5251 Signed-off-by: Mohammed Aminu Futa <mohammedfuta2000@gmail.com> Signed-off-by: lifubang <lifubang@acmcoder.com>
5f365bd to
937d887
Compare
|
@opencontainers/runc-maintainers PTAL |
Replace the goroutine + channel + 100ms time.After + blocking-open in handleFifo with a poll(2) loop on a non-blocking-open. Use pidfd_open(2) where available to wait for init exit without timeout, falling back to /proc state checks with 100ms timeout on older kernels. Allowing us to wait on both write to execfifo and state of init process simultaneously.
Fixes #5251