[threads] Inline thread_cleanup into mono_thread_detach_internal (#4119)
[mono.git] / mono / metadata / threadpool-ms-io-kqueue.c
index f6afe7f71a8d603f67acb767f870331a4ade7375..4422b668e8f61c7c2d2a630e1b1cb702dfb5fd56 100644 (file)
 static gint kqueue_fd;
 static struct kevent *kqueue_events;
 
-static gboolean
-kqueue_init (gint wakeup_pipe_fd)
+static gint
+KQUEUE_INIT_FD (gint fd, gint events, gint flags)
 {
        struct kevent event;
+       EV_SET (&event, fd, events, flags, 0, 0, 0);
+       return kevent (kqueue_fd, &event, 1, NULL, 0, NULL);
+}
 
+static gboolean
+kqueue_init (gint wakeup_pipe_fd)
+{
        kqueue_fd = kqueue ();
        if (kqueue_fd == -1) {
-               g_warning ("kqueue_init: kqueue () failed, error (%d) %s", errno, g_strerror (errno));
+               g_error ("kqueue_init: kqueue () failed, error (%d) %s", errno, g_strerror (errno));
                return FALSE;
        }
 
-       EV_SET (&event, wakeup_pipe_fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);
-       if (kevent (kqueue_fd, &event, 1, NULL, 0, NULL) == -1) {
-               g_warning ("kqueue_init: kevent () failed, error (%d) %s", errno, g_strerror (errno));
+       if (KQUEUE_INIT_FD (wakeup_pipe_fd, EVFILT_READ, EV_ADD | EV_ENABLE) == -1) {
+               g_error ("kqueue_init: kevent () failed, error (%d) %s", errno, g_strerror (errno));
                close (kqueue_fd);
                return FALSE;
        }
@@ -39,107 +44,84 @@ kqueue_init (gint wakeup_pipe_fd)
 }
 
 static void
-kqueue_cleanup (void)
+kqueue_register_fd (gint fd, gint events, gboolean is_new)
 {
-       g_free (kqueue_events);
-       close (kqueue_fd);
+       if (events & EVENT_IN) {
+               if (KQUEUE_INIT_FD (fd, EVFILT_READ, EV_ADD | EV_ENABLE) == -1)
+                       g_error ("kqueue_register_fd: kevent(read,enable) failed, error (%d) %s", errno, g_strerror (errno));
+       } else {
+               if (KQUEUE_INIT_FD (fd, EVFILT_READ, EV_ADD | EV_DISABLE) == -1)
+                       g_error ("kqueue_register_fd: kevent(read,disable) failed, error (%d) %s", errno, g_strerror (errno));
+       }
+       if (events & EVENT_OUT) {
+               if (KQUEUE_INIT_FD (fd, EVFILT_WRITE, EV_ADD | EV_ENABLE) == -1)
+                       g_error ("kqueue_register_fd: kevent(write,enable) failed, error (%d) %s", errno, g_strerror (errno));
+       } else {
+               if (KQUEUE_INIT_FD (fd, EVFILT_WRITE, EV_ADD | EV_DISABLE) == -1)
+                       g_error ("kqueue_register_fd: kevent(write,disable) failed, error (%d) %s", errno, g_strerror (errno));
+       }
 }
 
 static void
-kqueue_update_add (ThreadPoolIOUpdate *update)
+kqueue_remove_fd (gint fd)
 {
-       struct kevent event;
-
-       if ((update->events & MONO_POLLIN) != 0)
-               EV_SET (&event, update->fd, EVFILT_READ, EV_ADD | EV_ENABLE | EV_ONESHOT, 0, 0, 0);
-       if ((update->events & MONO_POLLOUT) != 0)
-               EV_SET (&event, update->fd, EVFILT_WRITE, EV_ADD | EV_ENABLE | EV_ONESHOT, 0, 0, 0);
-
-       if (kevent (kqueue_fd, &event, 1, NULL, 0, NULL) == -1)
-               g_warning ("kqueue_update_add: kevent(update) failed, error (%d) %s", errno, g_strerror (errno));
+       /* FIXME: a race between closing and adding operation in the Socket managed code trigger a ENOENT error */
+       if (KQUEUE_INIT_FD (fd, EVFILT_READ, EV_DELETE) == -1)
+               g_error ("kqueue_register_fd: kevent(read,delete) failed, error (%d) %s", errno, g_strerror (errno));
+       if (KQUEUE_INIT_FD (fd, EVFILT_WRITE, EV_DELETE) == -1)
+               g_error ("kqueue_register_fd: kevent(write,delete) failed, error (%d) %s", errno, g_strerror (errno));
 }
 
 static gint
-kqueue_event_wait (void)
+kqueue_event_wait (void (*callback) (gint fd, gint events, gpointer user_data), gpointer user_data)
 {
-       gint ready;
+       gint i, ready;
+
+       memset (kqueue_events, 0, sizeof (struct kevent) * KQUEUE_NEVENTS);
 
+       mono_gc_set_skip_thread (TRUE);
+
+       MONO_ENTER_GC_SAFE;
        ready = kevent (kqueue_fd, NULL, 0, kqueue_events, KQUEUE_NEVENTS, NULL);
+       MONO_EXIT_GC_SAFE;
+
+       mono_gc_set_skip_thread (FALSE);
+
        if (ready == -1) {
                switch (errno) {
                case EINTR:
-                       check_for_interruption_critical ();
+                       mono_thread_internal_check_for_interruption_critical (mono_thread_internal_current ());
                        ready = 0;
                        break;
                default:
-                       g_warning ("kqueue_event_wait: kevent () failed, error (%d) %s", errno, g_strerror (errno));
+                       g_error ("kqueue_event_wait: kevent () failed, error (%d) %s", errno, g_strerror (errno));
                        break;
                }
        }
 
-       return ready;
-}
-
-static inline gint
-kqueue_event_fd_at (guint i)
-{
-       return kqueue_events [i].ident;
-}
+       if (ready == -1)
+               return -1;
 
-static gint
-kqueue_event_max (void)
-{
-       return KQUEUE_NEVENTS;
-}
-
-static gboolean
-kqueue_event_create_sockares_at (guint i, gint fd, MonoMList **list)
-{
-       struct kevent *kqueue_event;
+       for (i = 0; i < ready; ++i) {
+               gint fd, events = 0;
 
-       g_assert (list);
+               fd = kqueue_events [i].ident;
+               if (kqueue_events [i].filter == EVFILT_READ || (kqueue_events [i].flags & EV_ERROR) != 0)
+                       events |= EVENT_IN;
+               if (kqueue_events [i].filter == EVFILT_WRITE || (kqueue_events [i].flags & EV_ERROR) != 0)
+                       events |= EVENT_OUT;
 
-       kqueue_event = &kqueue_events [i];
-       g_assert (kqueue_event);
-
-       g_assert (fd == kqueue_event->ident);
-
-       if (*list && (kqueue_event->filter == EVFILT_READ || (kqueue_event->flags & EV_ERROR) != 0)) {
-               MonoSocketAsyncResult *io_event = get_sockares_for_event (list, MONO_POLLIN);
-               if (io_event)
-                       mono_threadpool_ms_enqueue_work_item (((MonoObject*) io_event)->vtable->domain, (MonoObject*) io_event);
-       }
-       if (*list && (kqueue_event->filter == EVFILT_WRITE || (kqueue_event->flags & EV_ERROR) != 0)) {
-               MonoSocketAsyncResult *io_event = get_sockares_for_event (list, MONO_POLLOUT);
-               if (io_event)
-                       mono_threadpool_ms_enqueue_work_item (((MonoObject*) io_event)->vtable->domain, (MonoObject*) io_event);
-       }
-
-       if (*list) {
-               gint events = get_events (*list);
-               if (kqueue_event->filter == EVFILT_READ && (events & MONO_POLLIN) != 0) {
-                       EV_SET (kqueue_event, fd, EVFILT_READ, EV_ADD | EV_ENABLE | EV_ONESHOT, 0, 0, 0);
-                       if (kevent (kqueue_fd, kqueue_event, 1, NULL, 0, NULL) == -1)
-                               g_warning ("kqueue_event_create_sockares_at: kevent (read) failed, error (%d) %s", errno, g_strerror (errno));
-               }
-               if (kqueue_event->filter == EVFILT_WRITE && (events & MONO_POLLOUT) != 0) {
-                       EV_SET (kqueue_event, fd, EVFILT_WRITE, EV_ADD | EV_ENABLE | EV_ONESHOT, 0, 0, 0);
-                       if (kevent (kqueue_fd, kqueue_event, 1, NULL, 0, NULL) == -1)
-                               g_warning ("kqueue_event_create_sockares_at: kevent (write) failed, error (%d) %s", errno, g_strerror (errno));
-               }
+               callback (fd, events, user_data);
        }
 
-       return TRUE;
+       return 0;
 }
 
 static ThreadPoolIOBackend backend_kqueue = {
        .init = kqueue_init,
-       .cleanup = kqueue_cleanup,
-       .update_add = kqueue_update_add,
+       .register_fd = kqueue_register_fd,
+       .remove_fd = kqueue_remove_fd,
        .event_wait = kqueue_event_wait,
-       .event_max = kqueue_event_max,
-       .event_fd_at = kqueue_event_fd_at,
-       .event_create_sockares_at = kqueue_event_create_sockares_at,
 };
 
 #endif