89 lines
		
	
	
		
			1.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			89 lines
		
	
	
		
			1.9 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
 | 
						|
	}
 | 
						|
	EpollFdCounter.Inc(1)
 | 
						|
	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")
 | 
						|
				}
 | 
						|
				EpollFdCounter.Dec(1)
 | 
						|
				if err := proc.Close(); err != nil {
 | 
						|
					logrus.WithField("error", err).Error("containerd: close process IO")
 | 
						|
				}
 | 
						|
				m.m.Unlock()
 | 
						|
				m.exits <- proc
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 |