@@ -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+
426498func (c * Container ) createExecFifo () (retErr error ) {
427499 rootuid , err := c .Config ().HostRootUID ()
428500 if err != nil {
0 commit comments