github.com/georgethebeatle/containerd@v0.2.5/supervisor/monitor_linux.go (about) 1 package supervisor 2 3 import ( 4 "sync" 5 "syscall" 6 7 "github.com/Sirupsen/logrus" 8 "github.com/docker/containerd/archutils" 9 "github.com/docker/containerd/runtime" 10 ) 11 12 // NewMonitor starts a new process monitor and returns it 13 func NewMonitor() (*Monitor, error) { 14 m := &Monitor{ 15 receivers: make(map[int]interface{}), 16 exits: make(chan runtime.Process, 1024), 17 ooms: make(chan string, 1024), 18 } 19 fd, err := archutils.EpollCreate1(0) 20 if err != nil { 21 return nil, err 22 } 23 m.epollFd = fd 24 go m.start() 25 return m, nil 26 } 27 28 // Monitor represents a runtime.Process monitor 29 type Monitor struct { 30 m sync.Mutex 31 receivers map[int]interface{} 32 exits chan runtime.Process 33 ooms chan string 34 epollFd int 35 } 36 37 // Exits returns the channel used to notify of a process exit 38 func (m *Monitor) Exits() chan runtime.Process { 39 return m.exits 40 } 41 42 // OOMs returns the channel used to notify of a container exit due to OOM 43 func (m *Monitor) OOMs() chan string { 44 return m.ooms 45 } 46 47 // Monitor adds a process to the list of the one being monitored 48 func (m *Monitor) Monitor(p runtime.Process) error { 49 m.m.Lock() 50 defer m.m.Unlock() 51 fd := p.ExitFD() 52 event := syscall.EpollEvent{ 53 Fd: int32(fd), 54 Events: syscall.EPOLLHUP, 55 } 56 if err := archutils.EpollCtl(m.epollFd, syscall.EPOLL_CTL_ADD, fd, &event); err != nil { 57 return err 58 } 59 EpollFdCounter.Inc(1) 60 m.receivers[fd] = p 61 return nil 62 } 63 64 // MonitorOOM adds a container to the list of the ones monitored for OOM 65 func (m *Monitor) MonitorOOM(c runtime.Container) error { 66 m.m.Lock() 67 defer m.m.Unlock() 68 o, err := c.OOM() 69 if err != nil { 70 return err 71 } 72 fd := o.FD() 73 event := syscall.EpollEvent{ 74 Fd: int32(fd), 75 Events: syscall.EPOLLHUP | syscall.EPOLLIN, 76 } 77 if err := archutils.EpollCtl(m.epollFd, syscall.EPOLL_CTL_ADD, fd, &event); err != nil { 78 return err 79 } 80 EpollFdCounter.Inc(1) 81 m.receivers[fd] = o 82 return nil 83 } 84 85 // Close cleans up resources allocated by NewMonitor() 86 func (m *Monitor) Close() error { 87 return syscall.Close(m.epollFd) 88 } 89 90 func (m *Monitor) start() { 91 var events [128]syscall.EpollEvent 92 for { 93 n, err := archutils.EpollWait(m.epollFd, events[:], -1) 94 if err != nil { 95 if err == syscall.EINTR { 96 continue 97 } 98 logrus.WithField("error", err).Fatal("containerd: epoll wait") 99 } 100 // process events 101 for i := 0; i < n; i++ { 102 fd := int(events[i].Fd) 103 m.m.Lock() 104 r := m.receivers[fd] 105 switch t := r.(type) { 106 case runtime.Process: 107 if events[i].Events == syscall.EPOLLHUP { 108 delete(m.receivers, fd) 109 if err = syscall.EpollCtl(m.epollFd, syscall.EPOLL_CTL_DEL, fd, &syscall.EpollEvent{ 110 Events: syscall.EPOLLHUP, 111 Fd: int32(fd), 112 }); err != nil { 113 logrus.WithField("error", err).Error("containerd: epoll remove fd") 114 } 115 if err := t.Close(); err != nil { 116 logrus.WithField("error", err).Error("containerd: close process IO") 117 } 118 EpollFdCounter.Dec(1) 119 m.exits <- t 120 } 121 case runtime.OOM: 122 // always flush the event fd 123 t.Flush() 124 if t.Removed() { 125 delete(m.receivers, fd) 126 // epoll will remove the fd from its set after it has been closed 127 t.Close() 128 EpollFdCounter.Dec(1) 129 } else { 130 m.ooms <- t.ContainerID() 131 } 132 } 133 m.m.Unlock() 134 } 135 } 136 }