@@ -423,6 +423,78 @@ func (c *Container) signal(s os.Signal) error {
423
423
return nil
424
424
}
425
425
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
+
426
498
func (c * Container ) createExecFifo () (retErr error ) {
427
499
rootuid , err := c .Config ().HostRootUID ()
428
500
if err != nil {
0 commit comments