Skip to content

Commit

Permalink
libct: use pidfd and epoll to wait the init process exit
Browse files Browse the repository at this point in the history
Signed-off-by: lfbzhm <[email protected]>
  • Loading branch information
lifubang committed Nov 9, 2024
1 parent 7824bc5 commit ff50bed
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 10 deletions.
13 changes: 3 additions & 10 deletions delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,16 @@ import (
"fmt"
"os"
"path/filepath"
"time"

"github.com/opencontainers/runc/libcontainer"
"github.com/urfave/cli"

"golang.org/x/sys/unix"
)

func killContainer(container *libcontainer.Container) error {
_ = container.Signal(unix.SIGKILL)
for i := 0; i < 100; i++ {
time.Sleep(100 * time.Millisecond)
if err := container.Signal(unix.Signal(0)); err != nil {
return container.Destroy()
}
if err := container.Kill(); err != nil {
return err
}
return errors.New("container init still running")
return container.Destroy()
}

var deleteCommand = cli.Command{
Expand Down
72 changes: 72 additions & 0 deletions libcontainer/container_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,78 @@ func (c *Container) signal(s os.Signal) error {
return nil
}

func (c *Container) killViaPidfd() error {
pidfd, err := unix.PidfdOpen(c.initProcess.pid(), 0)
if err != nil {
return err
}
defer unix.Close(pidfd)

epollfd, err := unix.EpollCreate1(unix.EPOLL_CLOEXEC)
if err != nil {
return err
}
defer unix.Close(epollfd)

event := unix.EpollEvent{
Events: unix.EPOLLIN,
Fd: int32(pidfd),
}
if err := unix.EpollCtl(epollfd, unix.EPOLL_CTL_ADD, pidfd, &event); err != nil {
return err
}

// We don't need unix.PidfdSendSignal because go runtime will use it if possible.
_ = c.Signal(unix.SIGKILL)

events := make([]unix.EpollEvent, 1)
for {
// Set the timeout to 10s, the same as the traditional unix.Signal solution.
n, err := unix.EpollWait(epollfd, events, 10000)
if err != nil {
if err == unix.EINTR {
continue
}
return err
}

if n == 0 {
return errors.New("container init still running")
}

if n > 0 {
event := events[0]
if event.Fd == int32(pidfd) {
return nil
}
}
}
}

func (c *Container) kill() error {
_ = c.Signal(unix.SIGKILL)
for i := 0; i < 100; i++ {
time.Sleep(100 * time.Millisecond)
if err := c.Signal(unix.Signal(0)); err != nil {
return nil
}
}
return errors.New("container init still running")
}

// Kill kills the container and wait the init process exit.
func (c *Container) Kill() error {
if c.config.Namespaces.IsPrivate(configs.NEWPID) {
err := c.killViaPidfd()
if err == nil {
return nil
}

logrus.Debugf("pidfd & epoll failed with an error: %v, fall back to unix.Signal.\n", err)
}
return c.kill()
}

func (c *Container) createExecFifo() (retErr error) {
rootuid, err := c.Config().HostRootUID()
if err != nil {
Expand Down

0 comments on commit ff50bed

Please sign in to comment.