Skip to content

Instantly share code, notes, and snippets.

@jsipprell
Created September 20, 2015 13:29
Show Gist options
  • Save jsipprell/cd150cd88614befc20c4 to your computer and use it in GitHub Desktop.
Save jsipprell/cd150cd88614befc20c4 to your computer and use it in GitHub Desktop.
cgroup deletion race test (based on libcontainer from docker 1.7)
// cgroup eventfd oom event_control tester
// To build: go build -o cgroupoom cgroupoom.go
package main
import (
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
"sync"
"syscall"
)
const (
cgroupMemory = "memory"
monitorNode = "cgroup.event_control"
oomNode = "memory.oom_control"
)
var (
cgroupRoot string
debug bool
)
func init() {
if os.Getenv("CGROUP_ROOT") == "" {
os.Setenv("CGROUP_ROOT", "/cgroup")
}
switch os.Getenv("DEBUG") {
case "0", "FALSE", "false", "NO", "no", "":
default:
debug = true
}
}
func monitorcgroup(cgroup string) (<-chan struct{}, error) {
cgRoot := filepath.Join(cgroupRoot, cgroupMemory, cgroup)
oomControl, err := os.Open(filepath.Join(cgRoot, oomNode))
if err != nil {
return nil, err
}
fd, _, syserr := syscall.RawSyscall(syscall.SYS_EVENTFD2, 0, syscall.FD_CLOEXEC, 0)
if syserr != 0 {
defer oomControl.Close()
return nil, syserr
}
eventfd := os.NewFile(fd, "eventfd")
data := fmt.Sprintf("%d %d", eventfd.Fd(), oomControl.Fd())
eventControlPath := filepath.Join(cgRoot, monitorNode)
if err = ioutil.WriteFile(eventControlPath, []byte(data), 0777); err != nil {
defer oomControl.Close()
defer eventfd.Close()
return nil, err
}
ch := make(chan struct{})
go func() {
var (
i int
err error
)
defer close(ch)
defer eventfd.Close()
defer oomControl.Close()
buf := make([]byte, 8)
for {
if i, err = eventfd.Read(buf); err != nil {
log.Printf("%d bytes, err=%v", i, err)
return
}
if st, err := os.Lstat(eventControlPath); os.IsNotExist(err) {
if debug {
log.Println(err)
}
return
} else if err != nil {
log.Fatal(err)
} else if debug {
log.Printf("%v: %#v", eventControlPath, st)
}
if debug {
log.Printf("%d bytes: %v", i, buf[:i])
}
ch <- struct{}{}
}
}()
return ch, nil
}
func main() {
var wg sync.WaitGroup
cgroupRoot = os.ExpandEnv("$CGROUP_ROOT")
if len(os.Args) < 2 {
fmt.Println("usage: cgroupoom <memory-cgroup-name/or-path>")
os.Exit(1)
}
for _, a := range os.Args[1:] {
wg.Add(1)
go func(cgroup string) {
defer wg.Done()
ch, err := monitorcgroup(cgroup)
if err != nil {
log.Fatalf("monitoring cgroup %q: %v", cgroup, err)
}
log.Printf("monitoring cgroup %q", cgroup)
ok := true
for ok {
_, ok = <-ch
if ok {
log.Printf("cgroup %q: OOM!", cgroup)
}
}
log.Printf("cgroup %q destroyed", cgroup)
}(a)
}
wg.Wait()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment