[threads] Inline thread_cleanup into mono_thread_detach_internal (#4119)
[mono.git] / mono / metadata / threadpool-ms-io-epoll.c
index eb18b3e98e6ae590da09a16686dde0928516a624..2bc99e105b9cca5e57845d28d8ff21e3a68a305d 100644 (file)
@@ -27,9 +27,9 @@ epoll_init (gint wakeup_pipe_fd)
 
        if (epoll_fd == -1) {
 #ifdef EPOOL_CLOEXEC
-               g_warning ("epoll_init: epoll (EPOLL_CLOEXEC) failed, error (%d) %s\n", errno, g_strerror (errno));
+               g_error ("epoll_init: epoll (EPOLL_CLOEXEC) failed, error (%d) %s\n", errno, g_strerror (errno));
 #else
-               g_warning ("epoll_init: epoll (256) failed, error (%d) %s\n", errno, g_strerror (errno));
+               g_error ("epoll_init: epoll (256) failed, error (%d) %s\n", errno, g_strerror (errno));
 #endif
                return FALSE;
        }
@@ -37,7 +37,7 @@ epoll_init (gint wakeup_pipe_fd)
        event.events = EPOLLIN;
        event.data.fd = wakeup_pipe_fd;
        if (epoll_ctl (epoll_fd, EPOLL_CTL_ADD, event.data.fd, &event) == -1) {
-               g_warning ("epoll_init: epoll_ctl () failed, error (%d) %s", errno, g_strerror (errno));
+               g_error ("epoll_init: epoll_ctl () failed, error (%d) %s", errno, g_strerror (errno));
                close (epoll_fd);
                return FALSE;
        }
@@ -48,33 +48,48 @@ epoll_init (gint wakeup_pipe_fd)
 }
 
 static void
-epoll_cleanup (void)
-{
-       g_free (epoll_events);
-       close (epoll_fd);
-}
-
-static void
-epoll_update_add (gint fd, gint events, gboolean is_new)
+epoll_register_fd (gint fd, gint events, gboolean is_new)
 {
        struct epoll_event event;
 
+#ifndef EPOLLONESHOT
+/* it was only defined on android in May 2013 */
+#define EPOLLONESHOT 0x40000000
+#endif
+
        event.data.fd = fd;
-       if ((events & MONO_POLLIN) != 0)
+       event.events = EPOLLONESHOT;
+       if ((events & EVENT_IN) != 0)
                event.events |= EPOLLIN;
-       if ((events & MONO_POLLOUT) != 0)
+       if ((events & EVENT_OUT) != 0)
                event.events |= EPOLLOUT;
 
        if (epoll_ctl (epoll_fd, is_new ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, event.data.fd, &event) == -1)
-               g_warning ("epoll_update_add: epoll_ctl(%s) failed, error (%d) %s", is_new ? "EPOLL_CTL_ADD" : "EPOLL_CTL_MOD", errno, g_strerror (errno));
+               g_error ("epoll_register_fd: epoll_ctl(%s) failed, error (%d) %s", is_new ? "EPOLL_CTL_ADD" : "EPOLL_CTL_MOD", errno, g_strerror (errno));
+}
+
+static void
+epoll_remove_fd (gint fd)
+{
+       if (epoll_ctl (epoll_fd, EPOLL_CTL_DEL, fd, NULL) == -1)
+                       g_error ("epoll_remove_fd: epoll_ctl (EPOLL_CTL_DEL) failed, error (%d) %s", errno, g_strerror (errno));
 }
 
 static gint
-epoll_event_wait (void)
+epoll_event_wait (void (*callback) (gint fd, gint events, gpointer user_data), gpointer user_data)
 {
-       gint ready;
+       gint i, ready;
 
+       memset (epoll_events, 0, sizeof (struct epoll_event) * EPOLL_NEVENTS);
+
+       mono_gc_set_skip_thread (TRUE);
+
+       MONO_ENTER_GC_SAFE;
        ready = epoll_wait (epoll_fd, epoll_events, EPOLL_NEVENTS, -1);
+       MONO_EXIT_GC_SAFE;
+
+       mono_gc_set_skip_thread (FALSE);
+
        if (ready == -1) {
                switch (errno) {
                case EINTR:
@@ -82,54 +97,34 @@ epoll_event_wait (void)
                        ready = 0;
                        break;
                default:
-                       g_warning ("epoll_event_wait: epoll_wait () failed, error (%d) %s", errno, g_strerror (errno));
+                       g_error ("epoll_event_wait: epoll_wait () failed, error (%d) %s", errno, g_strerror (errno));
                        break;
                }
        }
 
-       return ready;
-}
+       if (ready == -1)
+               return -1;
 
-static gint
-epoll_event_get_fd_max (void)
-{
-       return EPOLL_NEVENTS;
-}
+       for (i = 0; i < ready; ++i) {
+               gint fd, events = 0;
 
-static gint
-epoll_event_get_fd_at (gint i, gint *events)
-{
-       g_assert (events);
+               fd = epoll_events [i].data.fd;
+               if (epoll_events [i].events & (EPOLLIN | EPOLLERR | EPOLLHUP))
+                       events |= EVENT_IN;
+               if (epoll_events [i].events & (EPOLLOUT | EPOLLERR | EPOLLHUP))
+                       events |= EVENT_OUT;
 
-       *events = ((epoll_events [i].events & (EPOLLIN | EPOLLERR | EPOLLHUP)) ? MONO_POLLIN : 0)
-                   | ((epoll_events [i].events & (EPOLLOUT | EPOLLERR | EPOLLHUP)) ? MONO_POLLOUT : 0);
-
-       return epoll_events [i].data.fd;
-}
-
-static void
-epoll_event_reset_fd_at (gint i, gint events)
-{
-       if (events == 0) {
-               if (epoll_ctl (epoll_fd, EPOLL_CTL_DEL, epoll_events [i].data.fd, &epoll_events [i]) == -1)
-                       g_warning ("epoll_event_reset_fd_at: epoll_ctl (EPOLL_CTL_DEL) failed, error (%d) %s", errno, g_strerror (errno));
-       } else {
-               epoll_events [i].events = ((events & MONO_POLLOUT) ? EPOLLOUT : 0)
-                                           | ((events & MONO_POLLIN) ? EPOLLIN : 0);
-
-               if (epoll_ctl (epoll_fd, EPOLL_CTL_MOD, epoll_events [i].data.fd, &epoll_events [i]) == -1)
-                       g_warning ("epoll_event_get_ioares_at: epoll_ctl (EPOLL_CTL_MOD) failed, error (%d) %s", errno, g_strerror (errno));
+               callback (fd, events, user_data);
        }
+
+       return 0;
 }
 
 static ThreadPoolIOBackend backend_epoll = {
        .init = epoll_init,
-       .cleanup = epoll_cleanup,
-       .update_add = epoll_update_add,
+       .register_fd = epoll_register_fd,
+       .remove_fd = epoll_remove_fd,
        .event_wait = epoll_event_wait,
-       .event_get_fd_max = epoll_event_get_fd_max,
-       .event_get_fd_at = epoll_event_get_fd_at,
-       .event_reset_fd_at = epoll_event_reset_fd_at,
 };
 
 #endif