Tizen_4.0 base
[platform/upstream/docker-engine.git] / vendor / github.com / containerd / containerd / supervisor / monitor_solaris.go
1 // +build solaris,cgo
2
3 package supervisor
4
5 /*
6 #include <port.h>
7 #include <poll.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11
12 int portAssociate(int port, int fd) {
13         if (port_associate(port, PORT_SOURCE_FD, fd, POLLIN | POLLHUP, NULL) < 0) {
14                 return 1;
15         }
16 }
17
18 port_event_t* getEvent(int e_fd) {
19         port_event_t *ev;
20         ev = (port_event_t *)malloc(sizeof(port_event_t));
21         if (port_get(e_fd, ev, NULL) < 0) {
22                 return NULL;
23         }
24         return ev;
25 }
26
27 int getFd(uintptr_t x) {
28         return *(int *)x;
29 }
30
31 void freeEvent( port_event_t *ev){
32         free(ev);
33 }
34 */
35 import "C"
36 import (
37         "sync"
38         "unsafe"
39
40         "github.com/Sirupsen/logrus"
41         "github.com/containerd/containerd/runtime"
42 )
43
44 // NewMonitor starts a new process monitor and returns it
45 func NewMonitor() (*Monitor, error) {
46         m := &Monitor{
47                 receivers: make(map[int]interface{}),
48                 exits:     make(chan runtime.Process, 1024),
49                 ooms:      make(chan string, 1024),
50         }
51         fd, err := C.port_create()
52         if err != nil {
53                 return nil, err
54         }
55
56         m.epollFd = int(fd)
57         go m.start()
58         return m, nil
59 }
60
61 // Monitor represents a runtime.Process monitor
62 type Monitor struct {
63         m         sync.Mutex
64         receivers map[int]interface{}
65         exits     chan runtime.Process
66         ooms      chan string
67         epollFd   int
68 }
69
70 // Exits returns the channel used to notify of a process exit
71 func (m *Monitor) Exits() chan runtime.Process {
72         return m.exits
73 }
74
75 // OOMs returns the channel used to notify of a container exit due to OOM
76 func (m *Monitor) OOMs() chan string {
77         return m.ooms
78 }
79
80 // Monitor adds a process to the list of the one being monitored
81 func (m *Monitor) Monitor(p runtime.Process) error {
82         m.m.Lock()
83         defer m.m.Unlock()
84         fd := p.ExitFD()
85         if _, err := C.port_associate(C.int(m.epollFd), C.PORT_SOURCE_FD, C.uintptr_t(fd), C.POLLIN|C.POLLHUP, unsafe.Pointer(&fd)); err != nil {
86                 return err
87         }
88         EpollFdCounter.Inc(1)
89         m.receivers[fd] = p
90         return nil
91 }
92
93 // MonitorOOM adds a container to the list of the ones monitored for OOM
94 // There is no OOM-Killer on Solaris therefore nothing to setup
95 func (m *Monitor) MonitorOOM(c runtime.Container) error {
96         return nil
97 }
98
99 // Close cleans up resources allocated by NewMonitor()
100 func (m *Monitor) Close() error {
101         _, err := C.close(C.int(m.epollFd))
102         return err
103 }
104
105 func (m *Monitor) start() {
106         for {
107                 ev := C.getEvent(C.int(m.epollFd))
108                 if ev == nil {
109                         continue
110                 }
111                 fd := int(C.getFd(C.uintptr_t(uintptr((ev.portev_user)))))
112
113                 if fd < 0 {
114                         logrus.Warnf("containerd: epoll wait")
115                 }
116
117                 m.m.Lock()
118                 r := m.receivers[fd]
119                 switch t := r.(type) {
120                 case runtime.Process:
121                         if ev.portev_events == C.POLLHUP {
122                                 delete(m.receivers, fd)
123                                 if err := t.Close(); err != nil {
124                                         logrus.Warnf("containerd: close process IO")
125                                 }
126                                 EpollFdCounter.Dec(1)
127                                 m.exits <- t
128                         }
129                 case runtime.OOM:
130                         // always flush the event fd
131                         t.Flush()
132                         if t.Removed() {
133                                 delete(m.receivers, fd)
134                                 // epoll will remove the fd from its set after it has been closed
135                                 t.Close()
136                                 EpollFdCounter.Dec(1)
137                         } else {
138                                 m.ooms <- t.ContainerID()
139                         }
140                 }
141                 m.m.Unlock()
142                 C.freeEvent(ev)
143         }
144 }