github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/mergeCode/runc/libcontainer/notify_linux.go (about) 1 // +build linux 2 3 package libcontainer 4 5 import ( 6 "fmt" 7 "io/ioutil" 8 "os" 9 "path/filepath" 10 "syscall" 11 ) 12 13 const oomCgroupName = "memory" 14 15 type PressureLevel uint 16 17 const ( 18 LowPressure PressureLevel = iota 19 MediumPressure 20 CriticalPressure 21 ) 22 23 func registerMemoryEvent(cgDir string, evName string, arg string) (<-chan struct{}, error) { 24 evFile, err := os.Open(filepath.Join(cgDir, evName)) 25 if err != nil { 26 return nil, err 27 } 28 fd, _, syserr := syscall.RawSyscall(syscall.SYS_EVENTFD2, 0, syscall.FD_CLOEXEC, 0) 29 if syserr != 0 { 30 evFile.Close() 31 return nil, syserr 32 } 33 34 eventfd := os.NewFile(fd, "eventfd") 35 36 eventControlPath := filepath.Join(cgDir, "cgroup.event_control") 37 data := fmt.Sprintf("%d %d %s", eventfd.Fd(), evFile.Fd(), arg) 38 if err := ioutil.WriteFile(eventControlPath, []byte(data), 0700); err != nil { 39 eventfd.Close() 40 evFile.Close() 41 return nil, err 42 } 43 ch := make(chan struct{}) 44 go func() { 45 defer func() { 46 close(ch) 47 eventfd.Close() 48 evFile.Close() 49 }() 50 buf := make([]byte, 8) 51 for { 52 if _, err := eventfd.Read(buf); err != nil { 53 return 54 } 55 // When a cgroup is destroyed, an event is sent to eventfd. 56 // So if the control path is gone, return instead of notifying. 57 if _, err := os.Lstat(eventControlPath); os.IsNotExist(err) { 58 return 59 } 60 ch <- struct{}{} 61 } 62 }() 63 return ch, nil 64 } 65 66 // notifyOnOOM returns channel on which you can expect event about OOM, 67 // if process died without OOM this channel will be closed. 68 func notifyOnOOM(paths map[string]string) (<-chan struct{}, error) { 69 dir := paths[oomCgroupName] 70 if dir == "" { 71 return nil, fmt.Errorf("path %q missing", oomCgroupName) 72 } 73 74 return registerMemoryEvent(dir, "memory.oom_control", "") 75 } 76 77 func notifyMemoryPressure(paths map[string]string, level PressureLevel) (<-chan struct{}, error) { 78 dir := paths[oomCgroupName] 79 if dir == "" { 80 return nil, fmt.Errorf("path %q missing", oomCgroupName) 81 } 82 83 if level > CriticalPressure { 84 return nil, fmt.Errorf("invalid pressure level %d", level) 85 } 86 87 levelStr := []string{"low", "medium", "critical"}[level] 88 return registerMemoryEvent(dir, "memory.pressure_level", levelStr) 89 }