-#define POLL_NEVENTS 1024
+#include "utils/mono-poll.h"
static mono_pollfd *poll_fds;
static guint poll_fds_capacity;
static gboolean
poll_init (gint wakeup_pipe_fd)
{
- guint i;
+ g_assert (wakeup_pipe_fd >= 0);
poll_fds_size = 1;
- poll_fds_capacity = POLL_NEVENTS;
+ poll_fds_capacity = 64;
+
poll_fds = g_new0 (mono_pollfd, poll_fds_capacity);
- POLL_INIT_FD (poll_fds, wakeup_pipe_fd, MONO_POLLIN);
- for (i = 1; i < poll_fds_capacity; ++i)
- POLL_INIT_FD (poll_fds + i, -1, 0);
+ POLL_INIT_FD (&poll_fds [0], wakeup_pipe_fd, MONO_POLLIN);
return TRUE;
}
static void
-poll_cleanup (void)
+poll_register_fd (gint fd, gint events, gboolean is_new)
{
- g_free (poll_fds);
+ gint i;
+ gint poll_event;
+
+ g_assert (fd >= 0);
+ g_assert (poll_fds_size <= 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;
+
+ 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;
+ }
+ }
+
+ g_assert (is_new);
+
+ 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_fds_size += 1;
+
+ if (poll_fds_size > poll_fds_capacity) {
+ poll_fds_capacity *= 2;
+ g_assert (poll_fds_size <= poll_fds_capacity);
+
+ poll_fds = (mono_pollfd *)g_renew (mono_pollfd, poll_fds, poll_fds_capacity);
+ }
+
+ POLL_INIT_FD (&poll_fds [poll_fds_size - 1], fd, poll_event);
+}
+
+static void
+poll_remove_fd (gint fd)
+{
+ gint i;
+
+ g_assert (fd >= 0);
+
+ 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;
- gint ret;
- gint ready = 0;
- mono_pollfd *poll_fd;
+ gint i, ready = 0;
for (i = 0; i < poll_fds_size; i++) {
- poll_fd = poll_fds + i;
- if (poll_fd->fd == -1)
+ if (poll_fds [i].fd == -1)
continue;
- ret = mono_poll (poll_fd, 1, 0);
- if (ret == 1)
+ switch (mono_poll (&poll_fds [i], 1, 0)) {
+ case 1:
ready++;
- if (ret == -1) {
-#if !defined(HOST_WIN32)
+ break;
+ case -1:
if (errno == EBADF)
-#else
- if (WSAGetLastError () == WSAEBADF)
-#endif
{
- poll_fd->revents |= MONO_POLLNVAL;
+ poll_fds [i].revents |= MONO_POLLNVAL;
ready++;
}
+ break;
}
}
return ready;
}
-static void
-poll_update_add (ThreadPoolIOUpdate *update)
+static gint
+poll_event_wait (void (*callback) (gint fd, gint events, gpointer user_data), gpointer user_data)
{
- gboolean found = FALSE;
- gint j, k;
+ gint i, ready;
- for (j = 1; j < poll_fds_size; ++j) {
- mono_pollfd *poll_fd = poll_fds + j;
- if (poll_fd->fd == update->fd) {
- found = TRUE;
- break;
- }
- }
+ for (i = 0; i < poll_fds_size; ++i)
+ poll_fds [i].revents = 0;
- if (!found) {
- for (j = 1; j < poll_fds_capacity; ++j) {
- mono_pollfd *poll_fd = poll_fds + j;
- if (poll_fd->fd == -1)
- break;
- }
- }
+ mono_gc_set_skip_thread (TRUE);
- if (j == poll_fds_capacity) {
- poll_fds_capacity += POLL_NEVENTS;
- poll_fds = g_renew (mono_pollfd, poll_fds, poll_fds_capacity);
- for (k = j; k < poll_fds_capacity; ++k)
- POLL_INIT_FD (poll_fds + k, -1, 0);
- }
-
- POLL_INIT_FD (poll_fds + j, update->fd, update->events);
-
- if (j >= poll_fds_size)
- poll_fds_size = j + 1;
-}
+ MONO_ENTER_GC_SAFE;
+ ready = mono_poll (poll_fds, poll_fds_size, -1);
+ MONO_EXIT_GC_SAFE;
-static gint
-poll_event_wait (void)
-{
- gint ready;
+ mono_gc_set_skip_thread (FALSE);
- ready = mono_poll (poll_fds, poll_fds_size, -1);
if (ready == -1) {
/*
* Apart from EINTR, we only check EBADF, for the rest:
* EINVAL: mono_poll() 'protects' us from descriptor
* numbers above the limit if using select() by marking
- * then as MONO_POLLERR. If a system poll() is being
+ * then as POLLERR. If a system poll() is being
* used, the number of descriptor we're passing will not
* be over sysconf(_SC_OPEN_MAX), as the error would have
* happened when opening.
* 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
- check_for_interruption_critical ();
+ {
+ mono_thread_internal_check_for_interruption_critical (mono_thread_internal_current ());
ready = 0;
break;
-#if !defined(HOST_WIN32)
+ }
case EBADF:
-#else
- case WSAEBADF:
-#endif
+ {
ready = poll_mark_bad_fds (poll_fds, poll_fds_size);
break;
+ }
default:
-#if !defined(HOST_WIN32)
- g_warning ("poll_event_wait: mono_poll () failed, error (%d) %s", errno, g_strerror (errno));
-#else
- g_warning ("poll_event_wait: mono_poll () failed, error (%d)\n", WSAGetLastError ());
-#endif
+ g_error ("poll_event_wait: mono_poll () failed, error (%d) %s", errno, g_strerror (errno));
break;
}
}
- return ready;
-}
+ if (ready == -1)
+ return -1;
+ if (ready == 0)
+ return 0;
-static inline gint
-poll_event_fd_at (guint i)
-{
- return poll_fds [i].fd;
-}
+ g_assert (ready > 0);
-static gint
-poll_event_max (void)
-{
- return poll_fds_size;
-}
+ for (i = 0; i < poll_fds_size; ++i) {
+ gint fd, events = 0;
-static gboolean
-poll_event_create_sockares_at (guint i, gint fd, MonoMList **list)
-{
- mono_pollfd *poll_fd;
-
- g_assert (list);
-
- poll_fd = &poll_fds [i];
- g_assert (poll_fd);
+ if (poll_fds [i].fd == -1)
+ continue;
+ if (poll_fds [i].revents == 0)
+ continue;
- g_assert (fd == poll_fd->fd);
+ fd = poll_fds [i].fd;
+ if (poll_fds [i].revents & (MONO_POLLIN | MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL))
+ events |= EVENT_IN;
+ 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;
- if (fd == -1 || poll_fd->revents == 0)
- return FALSE;
+ callback (fd, events, user_data);
- if (*list && (poll_fd->revents & (MONO_POLLIN | MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL)) != 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 && (poll_fd->revents & (MONO_POLLOUT | MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL)) != 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 (--ready == 0)
+ break;
}
- if (*list)
- poll_fd->events = get_events (*list);
- else
- POLL_INIT_FD (poll_fd, -1, 0);
-
- return TRUE;
+ return 0;
}
static ThreadPoolIOBackend backend_poll = {
.init = poll_init,
- .cleanup = poll_cleanup,
- .update_add = poll_update_add,
+ .register_fd = poll_register_fd,
+ .remove_fd = poll_remove_fd,
.event_wait = poll_event_wait,
- .event_max = poll_event_max,
- .event_fd_at = poll_event_fd_at,
- .event_create_sockares_at = poll_event_create_sockares_at,
};