containerd/supervisor/monitor.go

87 lines
1.8 KiB
Go

package supervisor
import (
"sync"
"syscall"
"github.com/Sirupsen/logrus"
"github.com/docker/containerd/runtime"
)
func NewMonitor() (*Monitor, error) {
m := &Monitor{
processes: make(map[int]runtime.Process),
exits: make(chan runtime.Process, 1024),
}
fd, err := syscall.EpollCreate1(0)
if err != nil {
return nil, err
}
m.epollFd = fd
go m.start()
return m, nil
}
type Monitor struct {
m sync.Mutex
processes map[int]runtime.Process
exits chan runtime.Process
epollFd int
}
func (m *Monitor) Exits() chan runtime.Process {
return m.exits
}
func (m *Monitor) Monitor(p runtime.Process) error {
m.m.Lock()
defer m.m.Unlock()
fd := p.ExitFD()
event := syscall.EpollEvent{
Fd: int32(fd),
Events: syscall.EPOLLHUP,
}
if err := syscall.EpollCtl(m.epollFd, syscall.EPOLL_CTL_ADD, fd, &event); err != nil {
return err
}
m.processes[fd] = p
return nil
}
func (m *Monitor) Close() error {
return syscall.Close(m.epollFd)
}
func (m *Monitor) start() {
var events [128]syscall.EpollEvent
for {
n, err := syscall.EpollWait(m.epollFd, events[:], -1)
if err != nil {
if err == syscall.EINTR {
continue
}
logrus.WithField("error", err).Fatal("containerd: epoll wait")
}
// process events
for i := 0; i < n; i++ {
if events[i].Events == syscall.EPOLLHUP {
fd := int(events[i].Fd)
m.m.Lock()
proc := m.processes[fd]
delete(m.processes, fd)
if err = syscall.EpollCtl(m.epollFd, syscall.EPOLL_CTL_DEL, fd, &syscall.EpollEvent{
Events: syscall.EPOLLHUP,
Fd: int32(fd),
}); err != nil {
logrus.WithField("error", err).Fatal("containerd: epoll remove fd")
}
if err := proc.Close(); err != nil {
logrus.WithField("error", err).Error("containerd: close process IO")
}
m.m.Unlock()
m.exits <- proc
}
}
}
}