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  }