Skip to content

Commit b38f27f

Browse files
committed
libct: use pidfd and epoll to wait the init process exit
Signed-off-by: lfbzhm <[email protected]>
1 parent 7926726 commit b38f27f

File tree

2 files changed

+75
-10
lines changed

2 files changed

+75
-10
lines changed

delete.go

+3-10
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,16 @@ import (
55
"fmt"
66
"os"
77
"path/filepath"
8-
"time"
98

109
"github.com/opencontainers/runc/libcontainer"
1110
"github.com/urfave/cli"
12-
13-
"golang.org/x/sys/unix"
1411
)
1512

1613
func killContainer(container *libcontainer.Container) error {
17-
_ = container.Signal(unix.SIGKILL)
18-
for i := 0; i < 100; i++ {
19-
time.Sleep(100 * time.Millisecond)
20-
if err := container.Signal(unix.Signal(0)); err != nil {
21-
return container.Destroy()
22-
}
14+
if err := container.Kill(); err != nil {
15+
return err
2316
}
24-
return errors.New("container init still running")
17+
return container.Destroy()
2518
}
2619

2720
var deleteCommand = cli.Command{

libcontainer/container_linux.go

+72
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,78 @@ func (c *Container) signal(s os.Signal) error {
423423
return nil
424424
}
425425

426+
func (c *Container) killViaPidfd() error {
427+
pidfd, err := unix.PidfdOpen(c.initProcess.pid(), 0)
428+
if err != nil {
429+
return err
430+
}
431+
defer unix.Close(pidfd)
432+
433+
epollfd, err := unix.EpollCreate1(unix.EPOLL_CLOEXEC)
434+
if err != nil {
435+
return err
436+
}
437+
defer unix.Close(epollfd)
438+
439+
event := unix.EpollEvent{
440+
Events: unix.EPOLLIN,
441+
Fd: int32(pidfd),
442+
}
443+
if err := unix.EpollCtl(epollfd, unix.EPOLL_CTL_ADD, pidfd, &event); err != nil {
444+
return err
445+
}
446+
447+
// We don't need unix.PidfdSendSignal because go runtime will use it if possible.
448+
_ = c.Signal(unix.SIGKILL)
449+
450+
events := make([]unix.EpollEvent, 1)
451+
for {
452+
// Set the timeout to 10s, the same as the traditional unix.Signal solution.
453+
n, err := unix.EpollWait(epollfd, events, 10000)
454+
if err != nil {
455+
if err == unix.EINTR {
456+
continue
457+
}
458+
return err
459+
}
460+
461+
if n == 0 {
462+
return errors.New("container init still running")
463+
}
464+
465+
if n > 0 {
466+
event := events[0]
467+
if event.Fd == int32(pidfd) {
468+
return nil
469+
}
470+
}
471+
}
472+
}
473+
474+
func (c *Container) kill() error {
475+
_ = c.Signal(unix.SIGKILL)
476+
for i := 0; i < 100; i++ {
477+
time.Sleep(100 * time.Millisecond)
478+
if err := c.Signal(unix.Signal(0)); err != nil {
479+
return nil
480+
}
481+
}
482+
return errors.New("container init still running")
483+
}
484+
485+
// Kill kills the container and wait the init process exit.
486+
func (c *Container) Kill() error {
487+
if c.config.Namespaces.IsPrivate(configs.NEWPID) {
488+
err := c.killViaPidfd()
489+
if err == nil {
490+
return nil
491+
}
492+
493+
logrus.Debugf("pidfd & epoll failed with an error: %v, fall back to unix.Signal.\n", err)
494+
}
495+
return c.kill()
496+
}
497+
426498
func (c *Container) createExecFifo() (retErr error) {
427499
rootuid, err := c.Config().HostRootUID()
428500
if err != nil {

0 commit comments

Comments
 (0)