-static MonoMList *
-process_io_event (MonoMList *list, int event)
-{
- MonoSocketAsyncResult *state;
- MonoMList *oldlist;
-
- oldlist = list;
- state = NULL;
- while (list) {
- state = (MonoSocketAsyncResult *) mono_mlist_get_data (list);
- if (get_event_from_state (state) == event)
- break;
-
- list = mono_mlist_next (list);
- }
-
- if (list != NULL) {
- oldlist = mono_mlist_remove_item (oldlist, list);
- EPOLL_DEBUG ("Dispatching event %d on socket %p", event, state->handle);
- threadpool_append_job (&async_io_tp, (MonoObject *) state);
- }
-
- return oldlist;
-}
-
-static int
-mark_bad_fds (mono_pollfd *pfds, int nfds)
-{
- int i, ret;
- mono_pollfd *pfd;
- int count = 0;
-
- for (i = 0; i < nfds; i++) {
- pfd = &pfds [i];
- if (pfd->fd == -1)
- continue;
-
- ret = mono_poll (pfd, 1, 0);
- if (ret == -1 && errno == EBADF) {
- pfd->revents |= MONO_POLLNVAL;
- count++;
- } else if (ret == 1) {
- count++;
- }
- }
-
- return count;
-}
-
-static void
-socket_io_poll_main (gpointer p)
-{
-#if MONO_SMALL_CONFIG
-#define INITIAL_POLLFD_SIZE 128
-#else
-#define INITIAL_POLLFD_SIZE 1024
-#endif
-#define POLL_ERRORS (MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL)
- SocketIOData *data = p;
- mono_pollfd *pfds;
- gint maxfd = 1;
- gint allocated;
- gint i;
- MonoInternalThread *thread;
-
- thread = mono_thread_internal_current ();
-
- allocated = INITIAL_POLLFD_SIZE;
- pfds = g_new0 (mono_pollfd, allocated);
- INIT_POLLFD (pfds, data->pipe [0], MONO_POLLIN);
- for (i = 1; i < allocated; i++)
- INIT_POLLFD (&pfds [i], -1, 0);
-
- while (1) {
- int nsock = 0;
- mono_pollfd *pfd;
- char one [1];
- MonoMList *list;
-
- do {
- if (nsock == -1) {
- if (THREAD_WANTS_A_BREAK (thread))
- mono_thread_interruption_checkpoint ();
- }
-
- nsock = mono_poll (pfds, maxfd, -1);
- } while (nsock == -1 && errno == EINTR);
-
- /*
- * 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
- * used, the number of descriptor we're passing will not
- * be over sysconf(_SC_OPEN_MAX), as the error would have
- * happened when opening.
- *
- * EFAULT: we own the memory pointed by pfds.
- * ENOMEM: we're doomed anyway
- *
- */
-
- if (nsock == -1 && errno == EBADF) {
- pfds->revents = 0; /* Just in case... */
- nsock = mark_bad_fds (pfds, maxfd);
- }
-
- if ((pfds->revents & POLL_ERRORS) != 0) {
- /* We're supposed to die now, as the pipe has been closed */
- g_free (pfds);
- socket_io_cleanup (data);
- return;
- }
-
- /* Got a new socket */
- if ((pfds->revents & MONO_POLLIN) != 0) {
- int nread;
-
- for (i = 1; i < allocated; i++) {
- pfd = &pfds [i];
- if (pfd->fd == -1 || pfd->fd == data->newpfd->fd)
- break;
- }
-
- if (i == allocated) {
- mono_pollfd *oldfd;
-
- oldfd = pfds;
- i = allocated;
- allocated = allocated * 2;
- pfds = g_renew (mono_pollfd, oldfd, allocated);
- g_free (oldfd);
- for (; i < allocated; i++)
- INIT_POLLFD (&pfds [i], -1, 0);
- }
-#ifndef HOST_WIN32
- nread = read (data->pipe [0], one, 1);
-#else
- nread = recv ((SOCKET) data->pipe [0], one, 1, 0);
-#endif
- if (nread <= 0) {
- g_free (pfds);
- return; /* we're closed */
- }
-
- INIT_POLLFD (&pfds [i], data->newpfd->fd, data->newpfd->events);
- ReleaseSemaphore (data->new_sem, 1, NULL);
- if (i >= maxfd)
- maxfd = i + 1;
- nsock--;
- }
-
- if (nsock == 0)
- continue;
-
- EnterCriticalSection (&data->io_lock);
- if (data->inited == 0) {
- g_free (pfds);
- LeaveCriticalSection (&data->io_lock);
- return; /* cleanup called */
- }
-
- for (i = 1; i < maxfd && nsock > 0; i++) {
- pfd = &pfds [i];
- if (pfd->fd == -1 || pfd->revents == 0)
- continue;
-
- nsock--;
- list = mono_g_hash_table_lookup (data->sock_to_state, GINT_TO_POINTER (pfd->fd));
- if (list != NULL && (pfd->revents & (MONO_POLLIN | POLL_ERRORS)) != 0) {
- list = process_io_event (list, MONO_POLLIN);
- }
-
- if (list != NULL && (pfd->revents & (MONO_POLLOUT | POLL_ERRORS)) != 0) {
- list = process_io_event (list, MONO_POLLOUT);
- }
-
- if (list != NULL) {
- mono_g_hash_table_replace (data->sock_to_state, GINT_TO_POINTER (pfd->fd), list);
- pfd->events = get_events_from_list (list);
- } else {
- mono_g_hash_table_remove (data->sock_to_state, GINT_TO_POINTER (pfd->fd));
- pfd->fd = -1;
- if (i == maxfd - 1)
- maxfd--;
- }
- }
- LeaveCriticalSection (&data->io_lock);
- }
-}
-
-#ifdef HAVE_EPOLL
-#define EPOLL_ERRORS (EPOLLERR | EPOLLHUP)
-#define EPOLL_NEVENTS 128
-static void
-socket_io_epoll_main (gpointer p)
-{
- SocketIOData *data;
- int epollfd;
- MonoInternalThread *thread;
- struct epoll_event *events, *evt;
- int ready = 0, i;
- gpointer async_results [EPOLL_NEVENTS * 2]; // * 2 because each loop can add up to 2 results here
- gint nresults;
-
- data = p;
- epollfd = data->epollfd;
- thread = mono_thread_internal_current ();
- events = g_new0 (struct epoll_event, EPOLL_NEVENTS);
-
- while (1) {
- do {
- if (ready == -1) {
- if (THREAD_WANTS_A_BREAK (thread))
- mono_thread_interruption_checkpoint ();
- }
- EPOLL_DEBUG ("epoll_wait init");
- ready = epoll_wait (epollfd, events, EPOLL_NEVENTS, -1);
- EPOLL_DEBUG_STMT(
- int err = errno;
- EPOLL_DEBUG ("epoll_wait end with %d ready sockets (%d %s).", ready, err, (err) ? g_strerror (err) : "");
- errno = err;
- );
- } while (ready == -1 && errno == EINTR);
-
- if (ready == -1) {
- int err = errno;
- g_free (events);
- if (err != EBADF)
- g_warning ("epoll_wait: %d %s", err, g_strerror (err));
-
- close (epollfd);
- return;
- }
-
- EnterCriticalSection (&data->io_lock);
- if (data->inited == 0) {
- EPOLL_DEBUG ("data->inited == 0");
- g_free (events);
- close (epollfd);
- return; /* cleanup called */
- }
-
- nresults = 0;
- for (i = 0; i < ready; i++) {
- int fd;
- MonoMList *list;
- MonoObject *ares;
-
- evt = &events [i];
- fd = evt->data.fd;
- list = mono_g_hash_table_lookup (data->sock_to_state, GINT_TO_POINTER (fd));
- EPOLL_DEBUG ("Event %d on %d list length: %d", evt->events, fd, mono_mlist_length (list));
- if (list != NULL && (evt->events & (EPOLLIN | EPOLL_ERRORS)) != 0) {
- ares = get_io_event (&list, MONO_POLLIN);
- if (ares != NULL)
- async_results [nresults++] = ares;
- }
-
- if (list != NULL && (evt->events & (EPOLLOUT | EPOLL_ERRORS)) != 0) {
- ares = get_io_event (&list, MONO_POLLOUT);
- if (ares != NULL)
- async_results [nresults++] = ares;
- }
-
- if (list != NULL) {
- mono_g_hash_table_replace (data->sock_to_state, GINT_TO_POINTER (fd), list);
- evt->events = get_events_from_list (list);
- EPOLL_DEBUG ("MOD %d to %d", fd, evt->events);
- if (epoll_ctl (epollfd, EPOLL_CTL_MOD, fd, evt)) {
- if (epoll_ctl (epollfd, EPOLL_CTL_ADD, fd, evt) == -1) {
- EPOLL_DEBUG_STMT (
- int err = errno;
- EPOLL_DEBUG ("epoll_ctl(MOD): %d %s fd: %d events: %d", err, g_strerror (err), fd, evt->events);
- errno = err;
- );
- }
- }
- } else {
- mono_g_hash_table_remove (data->sock_to_state, GINT_TO_POINTER (fd));
- EPOLL_DEBUG ("DEL %d", fd);
- epoll_ctl (epollfd, EPOLL_CTL_DEL, fd, evt);
- }
- }
- LeaveCriticalSection (&data->io_lock);
- threadpool_append_jobs (&async_io_tp, (MonoObject **) async_results, nresults);
- memset (async_results, 0, sizeof (gpointer) * nresults);
- }
-}
-#undef EPOLL_NEVENTS
-#endif
-