[threads] Inline thread_cleanup into mono_thread_detach_internal (#4119)
[mono.git] / mono / metadata / threadpool-ms-io-poll.c
index a02ceea4c50411148fc47ec79dd5d38b7a449c9c..3d32130d3b530cc14ad38ce04cffaf5258ac28cf 100644 (file)
@@ -1,24 +1,5 @@
 
-#if defined(HAVE_POLL)
-
-#if defined(HAVE_POLL_H)
-#include <poll.h>
-#elif defined(HAVE_SYS_POLL_H)
-#include <sys/poll.h>
-#endif
-
-typedef struct pollfd mono_pollfd;
-
-#elif defined(HOST_WIN32)
-
-#include "mswsock.h"
-
-typedef WSAPOLLFD mono_pollfd;
-
-#else
-/* poll is not defined */
-#error
-#endif
+#include "utils/mono-poll.h"
 
 static mono_pollfd *poll_fds;
 static guint poll_fds_capacity;
@@ -35,76 +16,117 @@ POLL_INIT_FD (mono_pollfd *poll_fd, gint fd, gint events)
 static gboolean
 poll_init (gint wakeup_pipe_fd)
 {
-       gint i;
+       g_assert (wakeup_pipe_fd >= 0);
 
-       poll_fds_size = wakeup_pipe_fd + 1;
+       poll_fds_size = 1;
        poll_fds_capacity = 64;
 
-       while (wakeup_pipe_fd >= poll_fds_capacity)
-               poll_fds_capacity *= 4;
-
        poll_fds = g_new0 (mono_pollfd, poll_fds_capacity);
 
-       for (i = 0; i < wakeup_pipe_fd; ++i)
-               POLL_INIT_FD (&poll_fds [i], -1, 0);
-
-       POLL_INIT_FD (&poll_fds [wakeup_pipe_fd], wakeup_pipe_fd, POLLIN);
+       POLL_INIT_FD (&poll_fds [0], wakeup_pipe_fd, MONO_POLLIN);
 
        return TRUE;
 }
 
-static void
-poll_cleanup (void)
-{
-       g_free (poll_fds);
-}
-
 static void
 poll_register_fd (gint fd, gint events, gboolean is_new)
 {
        gint i;
-       mono_pollfd *poll_fd;
+       gint poll_event;
 
        g_assert (fd >= 0);
        g_assert (poll_fds_size <= poll_fds_capacity);
 
-       if (fd >= poll_fds_capacity) {
-               do {
-                       poll_fds_capacity *= 4;
-               } while (fd >= poll_fds_capacity);
+       g_assert ((events & ~(EVENT_IN | EVENT_OUT)) == 0);
+
+       poll_event = 0;
+       if (events & EVENT_IN)
+               poll_event |= MONO_POLLIN;
+       if (events & EVENT_OUT)
+               poll_event |= MONO_POLLOUT;
 
-               poll_fds = g_renew (mono_pollfd, poll_fds, poll_fds_capacity);
+       for (i = 0; i < poll_fds_size; ++i) {
+               if (poll_fds [i].fd == fd) {
+                       g_assert (!is_new);
+                       POLL_INIT_FD (&poll_fds [i], fd, poll_event);
+                       return;
+               }
        }
 
-       if (fd >= poll_fds_size) {
-               for (i = poll_fds_size; i <= fd; ++i)
-                       POLL_INIT_FD (&poll_fds [i], -1, 0);
+       g_assert (is_new);
 
-               poll_fds_size = fd + 1;
+       for (i = 0; i < poll_fds_size; ++i) {
+               if (poll_fds [i].fd == -1) {
+                       POLL_INIT_FD (&poll_fds [i], fd, poll_event);
+                       return;
+               }
        }
 
-       poll_fd = &poll_fds [fd];
+       poll_fds_size += 1;
+
+       if (poll_fds_size > poll_fds_capacity) {
+               poll_fds_capacity *= 2;
+               g_assert (poll_fds_size <= poll_fds_capacity);
 
-       if (poll_fd->fd != -1) {
-               g_assert (poll_fd->fd == fd);
-               g_assert (!is_new);
+               poll_fds = (mono_pollfd *)g_renew (mono_pollfd, poll_fds, poll_fds_capacity);
        }
 
-       POLL_INIT_FD (poll_fd, fd, ((events & EVENT_IN) ? POLLIN : 0) | ((events & EVENT_OUT) ? POLLOUT : 0));
+       POLL_INIT_FD (&poll_fds [poll_fds_size - 1], fd, poll_event);
 }
 
 static void
 poll_remove_fd (gint fd)
 {
-       mono_pollfd *poll_fd;
+       gint i;
 
        g_assert (fd >= 0);
 
-       g_assert (fd < poll_fds_size);
-       poll_fd = &poll_fds [fd];
+       for (i = 0; i < poll_fds_size; ++i) {
+               if (poll_fds [i].fd == fd) {
+                       POLL_INIT_FD (&poll_fds [i], -1, 0);
+                       break;
+               }
+       }
+
+       /* if we don't find the fd in poll_fds,
+        * it means we try to delete it twice */
+       g_assert (i < poll_fds_size);
+
+       /* if we find it again, it means we added
+        * it twice */
+       for (; i < poll_fds_size; ++i)
+               g_assert (poll_fds [i].fd != fd);
+
+       /* reduce the value of poll_fds_size so we
+        * do not keep it too big */
+       while (poll_fds_size > 1 && poll_fds [poll_fds_size - 1].fd == -1)
+               poll_fds_size -= 1;
+}
+
+static inline gint
+poll_mark_bad_fds (mono_pollfd *poll_fds, gint poll_fds_size)
+{
+       gint i, ready = 0;
+
+       for (i = 0; i < poll_fds_size; i++) {
+               if (poll_fds [i].fd == -1)
+                       continue;
 
-       g_assert (poll_fd->fd == fd);
-       POLL_INIT_FD (poll_fd, -1, 0);
+               switch (mono_poll (&poll_fds [i], 1, 0)) {
+               case 1:
+                       ready++;
+                       break;
+               case -1:
+                       if (errno == EBADF)
+                       {
+                               poll_fds [i].revents |= MONO_POLLNVAL;
+                               ready++;
+                       }
+                       break;
+               }
+       }
+
+       return ready;
 }
 
 static gint
@@ -117,13 +139,9 @@ poll_event_wait (void (*callback) (gint fd, gint events, gpointer user_data), gp
 
        mono_gc_set_skip_thread (TRUE);
 
-#if !defined(HOST_WIN32)
-       ready = poll (poll_fds, poll_fds_size, -1);
-#else
-       ready = WSAPoll(poll_fds, poll_fds_size, -1);
-       if (ready == SOCKET_ERROR)
-               ready = -1;
-#endif
+       MONO_ENTER_GC_SAFE;
+       ready = mono_poll (poll_fds, poll_fds_size, -1);
+       MONO_EXIT_GC_SAFE;
 
        mono_gc_set_skip_thread (FALSE);
 
@@ -141,34 +159,31 @@ poll_event_wait (void (*callback) (gint fd, gint events, gpointer user_data), gp
                 *  ENOMEM: we're doomed anyway
                 *
                 */
-#if !defined(HOST_WIN32)
                switch (errno)
-#else
-               switch (WSAGetLastError ())
-#endif
                {
-#if !defined(HOST_WIN32)
                case EINTR:
-#else
-               case WSAEINTR:
-#endif
                {
                        mono_thread_internal_check_for_interruption_critical (mono_thread_internal_current ());
                        ready = 0;
                        break;
                }
+               case EBADF:
+               {
+                       ready = poll_mark_bad_fds (poll_fds, poll_fds_size);
+                       break;
+               }
                default:
-#if !defined(HOST_WIN32)
                        g_error ("poll_event_wait: mono_poll () failed, error (%d) %s", errno, g_strerror (errno));
-#else
-                       g_error ("poll_event_wait: mono_poll () failed, error (%d)\n", WSAGetLastError ());
-#endif
                        break;
                }
        }
 
        if (ready == -1)
                return -1;
+       if (ready == 0)
+               return 0;
+
+       g_assert (ready > 0);
 
        for (i = 0; i < poll_fds_size; ++i) {
                gint fd, events = 0;
@@ -179,10 +194,12 @@ poll_event_wait (void (*callback) (gint fd, gint events, gpointer user_data), gp
                        continue;
 
                fd = poll_fds [i].fd;
-               if (poll_fds [i].revents & (POLLIN | POLLERR | POLLHUP | POLLNVAL))
+               if (poll_fds [i].revents & (MONO_POLLIN | MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL))
                        events |= EVENT_IN;
-               if (poll_fds [i].revents & (POLLOUT | POLLERR | POLLHUP | POLLNVAL))
+               if (poll_fds [i].revents & (MONO_POLLOUT | MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL))
                        events |= EVENT_OUT;
+               if (poll_fds [i].revents & (MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL))
+                       events |= EVENT_ERR;
 
                callback (fd, events, user_data);
 
@@ -195,7 +212,6 @@ poll_event_wait (void (*callback) (gint fd, gint events, gpointer user_data), gp
 
 static ThreadPoolIOBackend backend_poll = {
        .init = poll_init,
-       .cleanup = poll_cleanup,
        .register_fd = poll_register_fd,
        .remove_fd = poll_remove_fd,
        .event_wait = poll_event_wait,