123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990 |
- // +build linux
- package libcontainer
- import (
- "fmt"
- "io/ioutil"
- "os"
- "path/filepath"
- "syscall"
- )
- const oomCgroupName = "memory"
- type PressureLevel uint
- const (
- LowPressure PressureLevel = iota
- MediumPressure
- CriticalPressure
- )
- func registerMemoryEvent(cgDir string, evName string, arg string) (<-chan struct{}, error) {
- evFile, err := os.Open(filepath.Join(cgDir, evName))
- if err != nil {
- return nil, err
- }
- fd, _, syserr := syscall.RawSyscall(syscall.SYS_EVENTFD2, 0, syscall.FD_CLOEXEC, 0)
- if syserr != 0 {
- evFile.Close()
- return nil, syserr
- }
- eventfd := os.NewFile(fd, "eventfd")
- eventControlPath := filepath.Join(cgDir, "cgroup.event_control")
- data := fmt.Sprintf("%d %d %s", eventfd.Fd(), evFile.Fd(), arg)
- if err := ioutil.WriteFile(eventControlPath, []byte(data), 0700); err != nil {
- eventfd.Close()
- evFile.Close()
- return nil, err
- }
- ch := make(chan struct{})
- go func() {
- defer func() {
- close(ch)
- eventfd.Close()
- evFile.Close()
- }()
- buf := make([]byte, 8)
- for {
- if _, err := eventfd.Read(buf); err != nil {
- return
- }
- // When a cgroup is destroyed, an event is sent to eventfd.
- // So if the control path is gone, return instead of notifying.
- if _, err := os.Lstat(eventControlPath); os.IsNotExist(err) {
- return
- }
- ch <- struct{}{}
- }
- }()
- return ch, nil
- }
- // notifyOnOOM returns channel on which you can expect event about OOM,
- // if process died without OOM this channel will be closed.
- func notifyOnOOM(paths map[string]string) (<-chan struct{}, error) {
- dir := paths[oomCgroupName]
- if dir == "" {
- return nil, fmt.Errorf("path %q missing", oomCgroupName)
- }
- return registerMemoryEvent(dir, "memory.oom_control", "")
- }
- func notifyMemoryPressure(paths map[string]string, level PressureLevel) (<-chan struct{}, error) {
- dir := paths[oomCgroupName]
- if dir == "" {
- return nil, fmt.Errorf("path %q missing", oomCgroupName)
- }
- if level > CriticalPressure {
- return nil, fmt.Errorf("invalid pressure level %d", level)
- }
- levelStr := []string{"low", "medium", "critical"}[level]
- return registerMemoryEvent(dir, "memory.pressure_level", levelStr)
- }
|