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; 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 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; switch (mono_poll (&poll_fds [i], 1, 0)) { case 1: ready++; break; case -1: #if !defined(HOST_WIN32) if (errno == EBADF) #else if (WSAGetLastError () == WSAEBADF) #endif { poll_fds [i].revents |= MONO_POLLNVAL; ready++; } break; } } return ready; }
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 gint poll_event_wait (void (*callback) (gint fd, gint events, gpointer user_data), gpointer user_data) { gint i, ready; for (i = 0; i < poll_fds_size; ++i) poll_fds [i].revents = 0; mono_gc_set_skip_thread (TRUE); MONO_ENTER_GC_SAFE; ready = mono_poll (poll_fds, poll_fds_size, -1); MONO_EXIT_GC_SAFE; mono_gc_set_skip_thread (FALSE); 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 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 !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; } #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_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; if (poll_fds [i].fd == -1) continue; if (poll_fds [i].revents == 0) continue; 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; callback (fd, events, user_data); if (--ready == 0) break; } return 0; }
static void tp_poll_wait (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) mono_pollfd *pfds; gint maxfd = 1; gint allocated; gint i; MonoInternalThread *thread; tp_poll_data *data; SocketIOData *socket_io_data = p; gpointer *async_results; gint nresults; thread = mono_thread_internal_current (); data = socket_io_data->event_data; allocated = INITIAL_POLLFD_SIZE; pfds = g_new0 (mono_pollfd, allocated); async_results = g_new0 (gpointer, allocated * 2); 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; MonoObject *ares; 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); g_free (async_results); socket_io_cleanup (socket_io_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); async_results = g_renew (gpointer, async_results, allocated * 2); } #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); g_free (async_results); return; /* we're closed */ } INIT_POLLFD (&pfds [i], data->newpfd.fd, data->newpfd.events); memset (&data->newpfd, 0, sizeof (mono_pollfd)); MONO_SEM_POST (&data->new_sem); if (i >= maxfd) maxfd = i + 1; nsock--; } if (nsock == 0) continue; EnterCriticalSection (&socket_io_data->io_lock); if (socket_io_data->inited == 3) { g_free (pfds); g_free (async_results); LeaveCriticalSection (&socket_io_data->io_lock); return; /* cleanup called */ } nresults = 0; 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 (socket_io_data->sock_to_state, GINT_TO_POINTER (pfd->fd)); if (list != NULL && (pfd->revents & (MONO_POLLIN | POLL_ERRORS)) != 0) { ares = get_io_event (&list, MONO_POLLIN); if (ares != NULL) async_results [nresults++] = ares; } if (list != NULL && (pfd->revents & (MONO_POLLOUT | POLL_ERRORS)) != 0) { ares = get_io_event (&list, MONO_POLLOUT); if (ares != NULL) async_results [nresults++] = ares; } if (list != NULL) { mono_g_hash_table_replace (socket_io_data->sock_to_state, GINT_TO_POINTER (pfd->fd), list); pfd->events = get_events_from_list (list); } else { mono_g_hash_table_remove (socket_io_data->sock_to_state, GINT_TO_POINTER (pfd->fd)); pfd->fd = -1; if (i == maxfd - 1) maxfd--; } } LeaveCriticalSection (&socket_io_data->io_lock); threadpool_append_jobs (&async_io_tp, (MonoObject **) async_results, nresults); memset (async_results, 0, sizeof (gpointer) * nresults); } }
static gint poll_event_wait (void (*callback) (gint fd, gint events, gpointer user_data), gpointer user_data) { gint i, ready; for (i = 0; i < poll_fds_size; ++i) poll_fds [i].revents = 0; mono_thread_info_set_flags (MONO_THREAD_INFO_FLAGS_NO_GC); MONO_ENTER_GC_SAFE; ready = mono_poll (poll_fds, poll_fds_size, -1); MONO_EXIT_GC_SAFE; mono_thread_info_set_flags (MONO_THREAD_INFO_FLAGS_NONE); 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 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 * */ switch (errno) { case EINTR: { ready = 0; break; } case EBADF: { ready = poll_mark_bad_fds (poll_fds, poll_fds_size); break; } default: g_error ("poll_event_wait: mono_poll () failed, error (%d) %s", errno, g_strerror (errno)); 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; if (poll_fds [i].fd == -1) continue; if (poll_fds [i].revents == 0) continue; 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; callback (fd, events, user_data); if (--ready == 0) break; } return 0; }
int mono_w32socket_connect (SOCKET sock, const struct sockaddr *addr, int addrlen, gboolean blocking) { gpointer handle; MonoW32HandleSocket *socket_handle; handle = GUINT_TO_POINTER (sock); if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET, (gpointer *)&socket_handle)) { mono_w32socket_set_last_error (WSAENOTSOCK); return SOCKET_ERROR; } if (connect (sock, addr, addrlen) == -1) { MonoThreadInfo *info; mono_pollfd fds; gint errnum, so_error; socklen_t len; errnum = errno; if (errno != EINTR) { mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect error: %s", __func__, g_strerror (errnum)); errnum = mono_w32socket_convert_error (errnum); if (errnum == WSAEINPROGRESS) errnum = WSAEWOULDBLOCK; /* see bug #73053 */ mono_w32socket_set_last_error (errnum); /* * On solaris x86 getsockopt (SO_ERROR) is not set after * connect () fails so we need to save this error. * * But don't do this for EWOULDBLOCK (bug 317315) */ if (errnum != WSAEWOULDBLOCK) { /* ECONNRESET means the socket was closed by another thread */ /* Async close on mac raises ECONNABORTED. */ socket_handle->saved_error = errnum; } return SOCKET_ERROR; } info = mono_thread_info_current (); fds.fd = sock; fds.events = MONO_POLLOUT; while (mono_poll (&fds, 1, -1) == -1 && !mono_thread_info_is_interrupt_state (info)) { if (errno != EINTR) { gint errnum = errno; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect poll error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); return SOCKET_ERROR; } } len = sizeof(so_error); if (getsockopt (sock, SOL_SOCKET, SO_ERROR, &so_error, &len) == -1) { gint errnum = errno; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect getsockopt error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); return SOCKET_ERROR; } if (so_error != 0) { gint errnum = mono_w32socket_convert_error (so_error); /* Need to save this socket error */ socket_handle->saved_error = errnum; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect getsockopt returned error: %s", __func__, g_strerror (so_error)); mono_w32socket_set_last_error (errnum); return SOCKET_ERROR; } } return 0; }
int _wapi_connect(guint32 fd, const struct sockaddr *serv_addr, socklen_t addrlen) { gpointer handle = GUINT_TO_POINTER (fd); struct _WapiHandle_socket *socket_handle; gboolean ok; gint errnum; if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { WSASetLastError (WSAENOTSOCK); return(SOCKET_ERROR); } if (connect (fd, serv_addr, addrlen) == -1) { mono_pollfd fds; int so_error; socklen_t len; errnum = errno; if (errno != EINTR) { DEBUG ("%s: connect error: %s", __func__, strerror (errnum)); errnum = errno_to_WSA (errnum, __func__); if (errnum == WSAEINPROGRESS) errnum = WSAEWOULDBLOCK; /* see bug #73053 */ WSASetLastError (errnum); /* * On solaris x86 getsockopt (SO_ERROR) is not set after * connect () fails so we need to save this error. * * But don't do this for EWOULDBLOCK (bug 317315) */ if (errnum != WSAEWOULDBLOCK) { ok = _wapi_lookup_handle (handle, WAPI_HANDLE_SOCKET, (gpointer *)&socket_handle); if (ok == FALSE) { /* ECONNRESET means the socket was closed by another thread */ /* Async close on mac raises ECONNABORTED. */ if (errnum != WSAECONNRESET && errnum != WSAENETDOWN) g_warning ("%s: error looking up socket handle %p (error %d)", __func__, handle, errnum); } else { socket_handle->saved_error = errnum; } } return(SOCKET_ERROR); } fds.fd = fd; fds.events = MONO_POLLOUT; while (mono_poll (&fds, 1, -1) == -1 && !_wapi_thread_cur_apc_pending ()) { if (errno != EINTR) { errnum = errno_to_WSA (errno, __func__); DEBUG ("%s: connect poll error: %s", __func__, strerror (errno)); WSASetLastError (errnum); return(SOCKET_ERROR); } } len = sizeof(so_error); if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &so_error, &len) == -1) { errnum = errno_to_WSA (errno, __func__); DEBUG ("%s: connect getsockopt error: %s", __func__, strerror (errno)); WSASetLastError (errnum); return(SOCKET_ERROR); } if (so_error != 0) { errnum = errno_to_WSA (so_error, __func__); /* Need to save this socket error */ ok = _wapi_lookup_handle (handle, WAPI_HANDLE_SOCKET, (gpointer *)&socket_handle); if (ok == FALSE) { g_warning ("%s: error looking up socket handle %p", __func__, handle); } else { socket_handle->saved_error = errnum; } DEBUG ("%s: connect getsockopt returned error: %s", __func__, strerror (so_error)); WSASetLastError (errnum); return(SOCKET_ERROR); } } return(0); }