@@ -377,9 +377,13 @@ func (c *Container) start(process *Process) (retErr error) {
377377
378378// Signal sends a specified signal to container's init.
379379//
380- // When s is SIGKILL and the container does not have its own PID namespace, all
381- // the container's processes are killed. In this scenario, the libcontainer
380+ // When s is SIGKILL:
381+ // 1. If the container does not have its own PID namespace, all the
382+ // container's processes are killed. In this scenario, the libcontainer
382383// user may be required to implement a proper child reaper.
384+ // 2. Otherwise, we just send the SIGKILL signal to the init process,
385+ // but we don't wait for the init process to disappear. If you want to
386+ // wait, please use c.KillAndWaitExit instead.
383387func (c * Container ) Signal (s os.Signal ) error {
384388 c .m .Lock ()
385389 defer c .m .Unlock ()
@@ -431,6 +435,81 @@ func (c *Container) signal(s os.Signal) error {
431435 return nil
432436}
433437
438+ func (c * Container ) killViaPidfd () error {
439+ pidfd , err := unix .PidfdOpen (c .initProcess .pid (), 0 )
440+ if err != nil {
441+ return err
442+ }
443+ defer unix .Close (pidfd )
444+
445+ epollfd , err := unix .EpollCreate1 (unix .EPOLL_CLOEXEC )
446+ if err != nil {
447+ return err
448+ }
449+ defer unix .Close (epollfd )
450+
451+ event := unix.EpollEvent {
452+ Events : unix .EPOLLIN ,
453+ Fd : int32 (pidfd ),
454+ }
455+ if err := unix .EpollCtl (epollfd , unix .EPOLL_CTL_ADD , pidfd , & event ); err != nil {
456+ return err
457+ }
458+
459+ if err := unix .PidfdSendSignal (pidfd , unix .SIGKILL , nil , 0 ); err != nil {
460+ return err
461+ }
462+
463+ events := make ([]unix.EpollEvent , 1 )
464+ for {
465+ // Set the timeout to 10s, the same as in kill below.
466+ n , err := unix .EpollWait (epollfd , events , 10000 )
467+ if err != nil {
468+ if err == unix .EINTR {
469+ continue
470+ }
471+ return err
472+ }
473+
474+ if n == 0 {
475+ return errors .New ("container init still running" )
476+ }
477+
478+ if n > 0 {
479+ event := events [0 ]
480+ if event .Fd == int32 (pidfd ) {
481+ return nil
482+ }
483+ }
484+ }
485+ }
486+
487+ func (c * Container ) kill () error {
488+ _ = c .Signal (unix .SIGKILL )
489+ for i := 0 ; i < 100 ; i ++ {
490+ time .Sleep (100 * time .Millisecond )
491+ if err := c .Signal (unix .Signal (0 )); err != nil {
492+ return nil
493+ }
494+ }
495+ return errors .New ("container init still running" )
496+ }
497+
498+ // EnsureKilled kills the container and waits for the kernel to finish killing it.
499+ func (c * Container ) EnsureKilled () error {
500+ // When a container doesn't have a private pidns, we have to kill all processes
501+ // in the cgroup, it's more simpler to use `cgroup.kill` or `unix.Kill`.
502+ if c .config .Namespaces .IsPrivate (configs .NEWPID ) {
503+ err := c .killViaPidfd ()
504+ if err == nil {
505+ return nil
506+ }
507+
508+ logrus .Debugf ("pidfd & epoll failed, falling back to unix.Signal: %v" , err )
509+ }
510+ return c .kill ()
511+ }
512+
434513func (c * Container ) createExecFifo () (retErr error ) {
435514 rootuid , err := c .config .HostRootUID ()
436515 if err != nil {
0 commit comments