7 "github.com/Sirupsen/logrus"
8 "github.com/containerd/containerd/archutils"
9 "github.com/containerd/containerd/runtime"
12 // NewMonitor starts a new process monitor and returns it
13 func NewMonitor() (*Monitor, error) {
15 receivers: make(map[int]interface{}),
16 exits: make(chan runtime.Process, 1024),
17 ooms: make(chan string, 1024),
19 fd, err := archutils.EpollCreate1(syscall.EPOLL_CLOEXEC)
28 // Monitor represents a runtime.Process monitor
31 receivers map[int]interface{}
32 exits chan runtime.Process
37 // Exits returns the channel used to notify of a process exit
38 func (m *Monitor) Exits() chan runtime.Process {
42 // OOMs returns the channel used to notify of a container exit due to OOM
43 func (m *Monitor) OOMs() chan string {
47 // Monitor adds a process to the list of the one being monitored
48 func (m *Monitor) Monitor(p runtime.Process) error {
52 event := syscall.EpollEvent{
54 Events: syscall.EPOLLHUP,
56 if err := archutils.EpollCtl(m.epollFd, syscall.EPOLL_CTL_ADD, fd, &event); err != nil {
64 // MonitorOOM adds a container to the list of the ones monitored for OOM
65 func (m *Monitor) MonitorOOM(c runtime.Container) error {
73 event := syscall.EpollEvent{
75 Events: syscall.EPOLLHUP | syscall.EPOLLIN,
77 if err := archutils.EpollCtl(m.epollFd, syscall.EPOLL_CTL_ADD, fd, &event); err != nil {
85 // Close cleans up resources allocated by NewMonitor()
86 func (m *Monitor) Close() error {
87 return syscall.Close(m.epollFd)
90 func (m *Monitor) processEvent(fd int, event uint32) {
93 switch t := r.(type) {
95 if event == syscall.EPOLLHUP {
96 delete(m.receivers, fd)
97 if err := syscall.EpollCtl(m.epollFd, syscall.EPOLL_CTL_DEL, fd, &syscall.EpollEvent{
98 Events: syscall.EPOLLHUP,
101 logrus.WithField("error", err).Error("containerd: epoll remove fd")
103 if err := t.Close(); err != nil {
104 logrus.WithField("error", err).Error("containerd: close process IO")
106 EpollFdCounter.Dec(1)
107 // defer until lock is released
113 // always flush the event fd
116 delete(m.receivers, fd)
117 // epoll will remove the fd from its set after it has been closed
119 EpollFdCounter.Dec(1)
121 // defer until lock is released
123 m.ooms <- t.ContainerID()
127 // This cannot be a defer to avoid a deadlock in case the channels
132 func (m *Monitor) start() {
133 var events [128]syscall.EpollEvent
135 n, err := archutils.EpollWait(m.epollFd, events[:], -1)
137 if err == syscall.EINTR {
140 logrus.WithField("error", err).Fatal("containerd: epoll wait")
143 for i := 0; i < n; i++ {
144 m.processEvent(int(events[i].Fd), events[i].Events)