[threads] Inline thread_cleanup into mono_thread_detach_internal (#4119)
[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_error ("epoll_init: epoll (EPOLL_CLOEXEC) failed, error (%d) %s\n", errno, g_strerror (errno));
31 #else
32                 g_error ("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_error ("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_register_fd (gint fd, gint events, gboolean is_new)
52 {
53         struct epoll_event event;
54
55 #ifndef EPOLLONESHOT
56 /* it was only defined on android in May 2013 */
57 #define EPOLLONESHOT 0x40000000
58 #endif
59
60         event.data.fd = fd;
61         event.events = EPOLLONESHOT;
62         if ((events & EVENT_IN) != 0)
63                 event.events |= EPOLLIN;
64         if ((events & EVENT_OUT) != 0)
65                 event.events |= EPOLLOUT;
66
67         if (epoll_ctl (epoll_fd, is_new ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, event.data.fd, &event) == -1)
68                 g_error ("epoll_register_fd: epoll_ctl(%s) failed, error (%d) %s", is_new ? "EPOLL_CTL_ADD" : "EPOLL_CTL_MOD", errno, g_strerror (errno));
69 }
70
71 static void
72 epoll_remove_fd (gint fd)
73 {
74         if (epoll_ctl (epoll_fd, EPOLL_CTL_DEL, fd, NULL) == -1)
75                         g_error ("epoll_remove_fd: epoll_ctl (EPOLL_CTL_DEL) failed, error (%d) %s", errno, g_strerror (errno));
76 }
77
78 static gint
79 epoll_event_wait (void (*callback) (gint fd, gint events, gpointer user_data), gpointer user_data)
80 {
81         gint i, ready;
82
83         memset (epoll_events, 0, sizeof (struct epoll_event) * EPOLL_NEVENTS);
84
85         mono_gc_set_skip_thread (TRUE);
86
87         MONO_ENTER_GC_SAFE;
88         ready = epoll_wait (epoll_fd, epoll_events, EPOLL_NEVENTS, -1);
89         MONO_EXIT_GC_SAFE;
90
91         mono_gc_set_skip_thread (FALSE);
92
93         if (ready == -1) {
94                 switch (errno) {
95                 case EINTR:
96                         mono_thread_internal_check_for_interruption_critical (mono_thread_internal_current ());
97                         ready = 0;
98                         break;
99                 default:
100                         g_error ("epoll_event_wait: epoll_wait () failed, error (%d) %s", errno, g_strerror (errno));
101                         break;
102                 }
103         }
104
105         if (ready == -1)
106                 return -1;
107
108         for (i = 0; i < ready; ++i) {
109                 gint fd, events = 0;
110
111                 fd = epoll_events [i].data.fd;
112                 if (epoll_events [i].events & (EPOLLIN | EPOLLERR | EPOLLHUP))
113                         events |= EVENT_IN;
114                 if (epoll_events [i].events & (EPOLLOUT | EPOLLERR | EPOLLHUP))
115                         events |= EVENT_OUT;
116
117                 callback (fd, events, user_data);
118         }
119
120         return 0;
121 }
122
123 static ThreadPoolIOBackend backend_epoll = {
124         .init = epoll_init,
125         .register_fd = epoll_register_fd,
126         .remove_fd = epoll_remove_fd,
127         .event_wait = epoll_event_wait,
128 };
129
130 #endif