Merge pull request #1696 from esdrubal/tzrefactor
[mono.git] / mono / metadata / threadpool-ms-io-epoll.c
1
2 #if defined(HAVE_EPOLL)
3
4 #include <sys/epoll.h>
5
6 #if defined(HOST_WIN32)
7 /* We assume that epoll is not available on windows */
8 #error
9 #endif
10
11 #define EPOLL_NEVENTS 128
12
13 static gint epoll_fd;
14 static struct epoll_event *epoll_events;
15
16 static gboolean
17 epoll_init (gint wakeup_pipe_fd)
18 {
19         struct epoll_event event;
20
21 #ifdef EPOOL_CLOEXEC
22         epoll_fd = epoll_create1 (EPOLL_CLOEXEC);
23 #else
24         epoll_fd = epoll_create (256);
25         fcntl (epoll_fd, F_SETFD, FD_CLOEXEC);
26 #endif
27
28         if (epoll_fd == -1) {
29 #ifdef EPOOL_CLOEXEC
30                 g_warning ("epoll_init: epoll (EPOLL_CLOEXEC) failed, error (%d) %s\n", errno, g_strerror (errno));
31 #else
32                 g_warning ("epoll_init: epoll (256) failed, error (%d) %s\n", errno, g_strerror (errno));
33 #endif
34                 return FALSE;
35         }
36
37         event.events = EPOLLIN;
38         event.data.fd = wakeup_pipe_fd;
39         if (epoll_ctl (epoll_fd, EPOLL_CTL_ADD, event.data.fd, &event) == -1) {
40                 g_warning ("epoll_init: epoll_ctl () failed, error (%d) %s", errno, g_strerror (errno));
41                 close (epoll_fd);
42                 return FALSE;
43         }
44
45         epoll_events = g_new0 (struct epoll_event, EPOLL_NEVENTS);
46
47         return TRUE;
48 }
49
50 static void
51 epoll_cleanup (void)
52 {
53         g_free (epoll_events);
54         close (epoll_fd);
55 }
56
57 static void
58 epoll_update_add (ThreadPoolIOUpdate *update)
59 {
60         struct epoll_event event;
61
62         event.data.fd = update->fd;
63         if ((update->events & MONO_POLLIN) != 0)
64                 event.events |= EPOLLIN;
65         if ((update->events & MONO_POLLOUT) != 0)
66                 event.events |= EPOLLOUT;
67
68         if (epoll_ctl (epoll_fd, update->is_new ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, event.data.fd, &event) == -1)
69                 g_warning ("epoll_update_add: epoll_ctl(%s) failed, error (%d) %s", update->is_new ? "EPOLL_CTL_ADD" : "EPOLL_CTL_MOD", errno, g_strerror (errno));
70 }
71
72 static gint
73 epoll_event_wait (void)
74 {
75         gint ready;
76
77         ready = epoll_wait (epoll_fd, epoll_events, EPOLL_NEVENTS, -1);
78         if (ready == -1) {
79                 switch (errno) {
80                 case EINTR:
81                         check_for_interruption_critical ();
82                         ready = 0;
83                         break;
84                 default:
85                         g_warning ("epoll_event_wait: epoll_wait () failed, error (%d) %s", errno, g_strerror (errno));
86                         break;
87                 }
88         }
89
90         return ready;
91 }
92
93 static gint
94 epoll_event_max (void)
95 {
96         return EPOLL_NEVENTS;
97 }
98
99 static gint
100 epoll_event_fd_at (guint i)
101 {
102         return epoll_events [i].data.fd;
103 }
104
105 static gboolean
106 epoll_event_create_sockares_at (guint i, gint fd, MonoMList **list)
107 {
108         struct epoll_event *epoll_event;
109
110         g_assert (list);
111
112         epoll_event = &epoll_events [i];
113         g_assert (epoll_event);
114
115         g_assert (fd == epoll_event->data.fd);
116
117         if (*list && (epoll_event->events & (EPOLLIN | EPOLLERR | EPOLLHUP)) != 0) {
118                 MonoSocketAsyncResult *io_event = get_sockares_for_event (list, MONO_POLLIN);
119                 if (io_event)
120                         mono_threadpool_ms_enqueue_work_item (((MonoObject*) io_event)->vtable->domain, (MonoObject*) io_event);
121         }
122         if (*list && (epoll_event->events & (EPOLLOUT | EPOLLERR | EPOLLHUP)) != 0) {
123                 MonoSocketAsyncResult *io_event = get_sockares_for_event (list, MONO_POLLOUT);
124                 if (io_event)
125                         mono_threadpool_ms_enqueue_work_item (((MonoObject*) io_event)->vtable->domain, (MonoObject*) io_event);
126         }
127
128         if (*list) {
129                 gint events = get_events (*list);
130
131                 epoll_event->events = ((events & MONO_POLLOUT) ? EPOLLOUT : 0) | ((events & MONO_POLLIN) ? EPOLLIN : 0);
132                 if (epoll_ctl (epoll_fd, EPOLL_CTL_MOD, fd, epoll_event) == -1) {
133                         if (epoll_ctl (epoll_fd, EPOLL_CTL_ADD, fd, epoll_event) == -1)
134                                 g_warning ("epoll_event_create_sockares_at: epoll_ctl () failed, error (%d) %s", errno, g_strerror (errno));
135                 }
136         } else {
137                 epoll_ctl (epoll_fd, EPOLL_CTL_DEL, fd, epoll_event);
138         }
139
140         return TRUE;
141 }
142
143 static ThreadPoolIOBackend backend_epoll = {
144         .init = epoll_init,
145         .cleanup = epoll_cleanup,
146         .update_add = epoll_update_add,
147         .event_wait = epoll_event_wait,
148         .event_max = epoll_event_max,
149         .event_fd_at = epoll_event_fd_at,
150         .event_create_sockares_at = epoll_event_create_sockares_at,
151 };
152
153 #endif