@@ -560,6 +560,22 @@ func (c *Manager) freeze(path string, state State) error {
560
560
}
561
561
}
562
562
563
+ func (c * Manager ) isCgroupEmpty () bool {
564
+ // In case of any error we return true so that we exit and don't leak resources
565
+ out := make (map [string ]interface {})
566
+ if err := readKVStatsFile (c .path , "cgroup.events" , out ); err != nil {
567
+ return true
568
+ }
569
+ if v , ok := out ["populated" ]; ok {
570
+ populated , ok := v .(uint64 )
571
+ if ! ok {
572
+ return true
573
+ }
574
+ return populated == 0
575
+ }
576
+ return true
577
+ }
578
+
563
579
// MemoryEventFD returns inotify file descriptor and 'memory.events' inotify watch descriptor
564
580
func (c * Manager ) MemoryEventFD () (int , uint32 , error ) {
565
581
fpath := filepath .Join (c .path , "memory.events" )
@@ -568,32 +584,72 @@ func (c *Manager) MemoryEventFD() (int, uint32, error) {
568
584
return 0 , 0 , errors .New ("failed to create inotify fd" )
569
585
}
570
586
wd , err := syscall .InotifyAddWatch (fd , fpath , unix .IN_MODIFY )
571
- if wd < 0 {
587
+ if err != nil {
588
+ syscall .Close (fd )
589
+ return 0 , 0 , fmt .Errorf ("failed to add inotify watch for %q: %w" , fpath , err )
590
+ }
591
+ // monitor to detect process exit/cgroup deletion
592
+ evpath := filepath .Join (c .path , "cgroup.events" )
593
+ if _ , err = syscall .InotifyAddWatch (fd , evpath , unix .IN_MODIFY ); err != nil {
572
594
syscall .Close (fd )
573
- return 0 , 0 , fmt .Errorf ("failed to add inotify watch for %q" , fpath )
595
+ return 0 , 0 , fmt .Errorf ("failed to add inotify watch for %q: %w " , evpath , err )
574
596
}
575
597
576
598
return fd , uint32 (wd ), nil
577
599
}
578
600
579
601
func (c * Manager ) EventChan () (<- chan Event , <- chan error ) {
580
602
ec := make (chan Event )
581
- errCh := make (chan error )
603
+ errCh := make (chan error , 1 )
582
604
go c .waitForEvents (ec , errCh )
583
605
584
- return ec , nil
606
+ return ec , errCh
585
607
}
586
608
587
- func (c * Manager ) waitForEvents (ec chan <- Event , errCh chan <- error ) {
588
- fd , wd , err := c .MemoryEventFD ()
609
+ func parseMemoryEvents (out map [string ]interface {}) (Event , error ) {
610
+ e := Event {}
611
+ if v , ok := out ["high" ]; ok {
612
+ e .High , ok = v .(uint64 )
613
+ if ! ok {
614
+ return Event {}, fmt .Errorf ("cannot convert high to uint64: %+v" , v )
615
+ }
616
+ }
617
+ if v , ok := out ["low" ]; ok {
618
+ e .Low , ok = v .(uint64 )
619
+ if ! ok {
620
+ return Event {}, fmt .Errorf ("cannot convert low to uint64: %+v" , v )
621
+ }
622
+ }
623
+ if v , ok := out ["max" ]; ok {
624
+ e .Max , ok = v .(uint64 )
625
+ if ! ok {
626
+ return Event {}, fmt .Errorf ("cannot convert max to uint64: %+v" , v )
627
+ }
628
+ }
629
+ if v , ok := out ["oom" ]; ok {
630
+ e .OOM , ok = v .(uint64 )
631
+ if ! ok {
632
+ return Event {}, fmt .Errorf ("cannot convert oom to uint64: %+v" , v )
633
+ }
634
+ }
635
+ if v , ok := out ["oom_kill" ]; ok {
636
+ e .OOMKill , ok = v .(uint64 )
637
+ if ! ok {
638
+ return Event {}, fmt .Errorf ("cannot convert oom_kill to uint64: %+v" , v )
639
+ }
640
+ }
641
+ return e , nil
642
+ }
589
643
590
- defer syscall . InotifyRmWatch ( fd , wd )
591
- defer syscall . Close ( fd )
644
+ func ( c * Manager ) waitForEvents ( ec chan <- Event , errCh chan <- error ) {
645
+ defer close ( errCh )
592
646
647
+ fd , _ , err := c .MemoryEventFD ()
593
648
if err != nil {
594
649
errCh <- err
595
650
return
596
651
}
652
+ defer syscall .Close (fd )
597
653
598
654
for {
599
655
buffer := make ([]byte , syscall .SizeofInotifyEvent * 10 )
@@ -604,48 +660,22 @@ func (c *Manager) waitForEvents(ec chan<- Event, errCh chan<- error) {
604
660
}
605
661
if bytesRead >= syscall .SizeofInotifyEvent {
606
662
out := make (map [string ]interface {})
607
- if err := readKVStatsFile (c .path , "memory.events" , out ); err == nil {
608
- e := Event {}
609
- if v , ok := out ["high" ]; ok {
610
- e .High , ok = v .(uint64 )
611
- if ! ok {
612
- errCh <- fmt .Errorf ("cannot convert high to uint64: %+v" , v )
613
- return
614
- }
663
+ if err := readKVStatsFile (c .path , "memory.events" , out ); err != nil {
664
+ // When cgroup is deleted read may return -ENODEV instead of -ENOENT from open.
665
+ if _ , statErr := os .Lstat (filepath .Join (c .path , "memory.events" )); ! os .IsNotExist (statErr ) {
666
+ errCh <- err
615
667
}
616
- if v , ok := out ["low" ]; ok {
617
- e .Low , ok = v .(uint64 )
618
- if ! ok {
619
- errCh <- fmt .Errorf ("cannot convert low to uint64: %+v" , v )
620
- return
621
- }
622
- }
623
- if v , ok := out ["max" ]; ok {
624
- e .Max , ok = v .(uint64 )
625
- if ! ok {
626
- errCh <- fmt .Errorf ("cannot convert max to uint64: %+v" , v )
627
- return
628
- }
629
- }
630
- if v , ok := out ["oom" ]; ok {
631
- e .OOM , ok = v .(uint64 )
632
- if ! ok {
633
- errCh <- fmt .Errorf ("cannot convert oom to uint64: %+v" , v )
634
- return
635
- }
636
- }
637
- if v , ok := out ["oom_kill" ]; ok {
638
- e .OOMKill , ok = v .(uint64 )
639
- if ! ok {
640
- errCh <- fmt .Errorf ("cannot convert oom_kill to uint64: %+v" , v )
641
- return
642
- }
643
- }
644
- ec <- e
645
- } else {
668
+ return
669
+ }
670
+ e , err := parseMemoryEvents (out )
671
+ if err != nil {
646
672
errCh <- err
647
673
return
648
674
}
675
+ ec <- e
676
+ if c .isCgroupEmpty () {
677
+ return
678
+ }
649
679
}
650
680
}
651
681
}
0 commit comments