Files
runc/libcontainer/notify_v2_linux.go
Kir Kolyshkin a75076b4a4 Switch to opencontainers/cgroups
This removes libcontainer/cgroups packages and starts
using those from github.com/opencontainers/cgroups repo.

Mostly generated by:

  git rm -f libcontainer/cgroups

  find . -type f -name "*.go" -exec sed -i \
    's|github.com/opencontainers/runc/libcontainer/cgroups|github.com/opencontainers/cgroups|g' \
    {} +

  go get github.com/opencontainers/cgroups@v0.0.1
  make vendor
  gofumpt -w .

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2025-02-28 15:20:33 -08:00

86 lines
2.3 KiB
Go

package libcontainer
import (
"fmt"
"os"
"path/filepath"
"unsafe"
"github.com/opencontainers/cgroups/fscommon"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)
func registerMemoryEventV2(cgDir, evName, cgEvName string) (<-chan struct{}, error) {
fd, err := unix.InotifyInit()
if err != nil {
return nil, fmt.Errorf("unable to init inotify: %w", err)
}
// watching oom kill
evFd, err := unix.InotifyAddWatch(fd, filepath.Join(cgDir, evName), unix.IN_MODIFY)
if err != nil {
unix.Close(fd)
return nil, fmt.Errorf("unable to add inotify watch: %w", err)
}
// Because no `unix.IN_DELETE|unix.IN_DELETE_SELF` event for cgroup file system, so watching all process exited
cgFd, err := unix.InotifyAddWatch(fd, filepath.Join(cgDir, cgEvName), unix.IN_MODIFY)
if err != nil {
unix.Close(fd)
return nil, fmt.Errorf("unable to add inotify watch: %w", err)
}
ch := make(chan struct{})
go func() {
var (
buffer [unix.SizeofInotifyEvent + unix.PathMax + 1]byte
offset uint32
)
defer func() {
unix.Close(fd)
close(ch)
}()
for {
n, err := unix.Read(fd, buffer[:])
if err == unix.EINTR { //nolint:errorlint // unix errors are bare
continue
}
if err != nil {
err = os.NewSyscallError("read", err)
logrus.Warnf("unable to read event data from inotify, got error: %v", err)
return
}
if n < unix.SizeofInotifyEvent {
logrus.Warnf("we should read at least %d bytes from inotify, but got %d bytes.", unix.SizeofInotifyEvent, n)
return
}
offset = 0
for offset <= uint32(n-unix.SizeofInotifyEvent) {
rawEvent := (*unix.InotifyEvent)(unsafe.Pointer(&buffer[offset]))
offset += unix.SizeofInotifyEvent + rawEvent.Len
if rawEvent.Mask&unix.IN_MODIFY != unix.IN_MODIFY {
continue
}
switch int(rawEvent.Wd) {
case evFd:
oom, err := fscommon.GetValueByKey(cgDir, evName, "oom_kill")
if err != nil || oom > 0 {
ch <- struct{}{}
}
case cgFd:
pids, err := fscommon.GetValueByKey(cgDir, cgEvName, "populated")
if err != nil || pids == 0 {
return
}
}
}
}
}()
return ch, nil
}
// notifyOnOOMV2 returns channel on which you can expect event about OOM,
// if process died without OOM this channel will be closed.
func notifyOnOOMV2(path string) (<-chan struct{}, error) {
return registerMemoryEventV2(path, "memory.events", "cgroup.events")
}