Beispiel #1
0
/*
 * select/poll wake up when a socket is closed, but epoll just removes
 * the socket from its internal list without notification.
 */
void
mono_thread_pool_remove_socket (int sock)
{
	MonoMList *list;
	MonoSocketAsyncResult *state;
	MonoObject *ares;

	if (socket_io_data.inited == 0)
		return;

	EnterCriticalSection (&socket_io_data.io_lock);
	if (socket_io_data.sock_to_state == NULL) {
		LeaveCriticalSection (&socket_io_data.io_lock);
		return;
	}
	list = mono_g_hash_table_lookup (socket_io_data.sock_to_state, GINT_TO_POINTER (sock));
	if (list)
		mono_g_hash_table_remove (socket_io_data.sock_to_state, GINT_TO_POINTER (sock));
	LeaveCriticalSection (&socket_io_data.io_lock);
	
	while (list) {
		state = (MonoSocketAsyncResult *) mono_mlist_get_data (list);
		if (state->operation == AIO_OP_RECEIVE)
			state->operation = AIO_OP_RECV_JUST_CALLBACK;
		else if (state->operation == AIO_OP_SEND)
			state->operation = AIO_OP_SEND_JUST_CALLBACK;

		ares = get_io_event (&list, MONO_POLLIN);
		threadpool_append_job (&async_io_tp, ares);
		if (list) {
			ares = get_io_event (&list, MONO_POLLOUT);
			threadpool_append_job (&async_io_tp, ares);
		}
	}
}
Beispiel #2
0
static void
wait_callback (gint fd, gint events, gpointer user_data)
{
	if (mono_runtime_is_shutting_down ())
		return;

	if (fd == threadpool_io->wakeup_pipes [0]) {
		mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_THREADPOOL, "io threadpool: wke");
		selector_thread_wakeup_drain_pipes ();
	} else {
		MonoGHashTable *states;
		MonoMList *list = NULL;
		gpointer k;
		gboolean remove_fd = FALSE;
		gint operations;

		g_assert (user_data);
		states = user_data;

		mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_THREADPOOL, "io threadpool: cal fd %3d, events = %2s | %2s | %3s",
			fd, (events & EVENT_IN) ? "RD" : "..", (events & EVENT_OUT) ? "WR" : "..", (events & EVENT_ERR) ? "ERR" : "...");

		if (!mono_g_hash_table_lookup_extended (states, GINT_TO_POINTER (fd), &k, (gpointer*) &list))
			g_error ("wait_callback: fd %d not found in states table", fd);

		if (list && (events & EVENT_IN) != 0) {
			MonoIOSelectorJob *job = get_job_for_event (&list, EVENT_IN);
			if (job)
				mono_threadpool_ms_enqueue_work_item (((MonoObject*) job)->vtable->domain, (MonoObject*) job);
		}
		if (list && (events & EVENT_OUT) != 0) {
			MonoIOSelectorJob *job = get_job_for_event (&list, EVENT_OUT);
			if (job)
				mono_threadpool_ms_enqueue_work_item (((MonoObject*) job)->vtable->domain, (MonoObject*) job);
		}

		remove_fd = (events & EVENT_ERR) == EVENT_ERR;
		if (!remove_fd) {
			mono_g_hash_table_replace (states, GINT_TO_POINTER (fd), list);

			operations = get_operations_for_jobs (list);

			mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_THREADPOOL, "io threadpool: res fd %3d, events = %2s | %2s | %2s",
				fd, (operations & EVENT_IN) ? "RD" : "..", (operations & EVENT_OUT) ? "WR" : "..");

			threadpool_io->backend.register_fd (fd, operations, FALSE);
		} else {
			mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_THREADPOOL, "io threadpool: err fd %d", fd);

			mono_g_hash_table_remove (states, GINT_TO_POINTER (fd));

			threadpool_io->backend.remove_fd (fd);
		}
	}
}
Beispiel #3
0
static void
continuation_free (MonoContinuation *cont)
{
	if (cont->saved_stack) {
		tasklets_lock ();
		mono_g_hash_table_remove (keepalive_stacks, cont->saved_stack);
		tasklets_unlock ();
		mono_gc_free_fixed (cont->saved_stack);
	}
	g_free (cont);
}
Beispiel #4
0
MonoBoolean 
ves_icall_System_Threading_StInternalMethods_RemoveHandle_internal (gpointer handle) 
{
	gboolean removed;
	
	g_assert (handles != NULL);

	st_lock_enter (&lock);
	removed = mono_g_hash_table_remove (handles, handle);
	st_lock_exit (&lock);
	
	return removed;
}
Beispiel #5
0
static int
continuation_store (MonoContinuation *cont, int state, MonoException **e)
{
	MonoLMF *lmf = mono_get_lmf ();
	gsize num_bytes;

	if (!cont->domain) {
		*e =  mono_get_exception_argument ("cont", "Continuation not initialized");
		return 0;
	}
	if (cont->domain != mono_domain_get () || cont->thread_id != GetCurrentThreadId ()) {
		*e = mono_get_exception_argument ("cont", "Continuation from another thread or domain");
		return 0;
	}

	cont->lmf = lmf;
	cont->return_ip = __builtin_return_address (0);
	cont->return_sp = __builtin_frame_address (0);

	num_bytes = (char*)cont->top_sp - (char*)cont->return_sp;

	/*g_print ("store: %d bytes, sp: %p, ip: %p, lmf: %p\n", num_bytes, cont->return_sp, cont->return_ip, lmf);*/

	if (cont->saved_stack && num_bytes <= cont->stack_alloc_size) {
		/* clear to avoid GC retention */
		if (num_bytes < cont->stack_used_size) {
			memset ((char*)cont->saved_stack + num_bytes, 0, cont->stack_used_size - num_bytes);
		}
		cont->stack_used_size = num_bytes;
	} else {
		tasklets_lock ();
		internal_init ();
		if (cont->saved_stack) {
			mono_g_hash_table_remove (keepalive_stacks, cont->saved_stack);
			mono_gc_free_fixed (cont->saved_stack);
		}
		cont->stack_used_size = num_bytes;
		cont->stack_alloc_size = num_bytes * 1.1;
		cont->saved_stack = mono_gc_alloc_fixed (cont->stack_alloc_size, NULL);
		mono_g_hash_table_insert (keepalive_stacks, cont->saved_stack, cont->saved_stack);
		tasklets_unlock ();
	}
	memcpy (cont->saved_stack, cont->return_sp, num_bytes);

	return state;
}
Beispiel #6
0
/**
 * mono_g_hash_table_foreach_remove:
 */
guint
mono_g_hash_table_foreach_remove (MonoGHashTable *hash, GHRFunc func, gpointer user_data)
{
	int i;
	int count = 0;

	g_return_val_if_fail (hash != NULL, 0);
	g_return_val_if_fail (func != NULL, 0);

	for (i = 0; i < hash->table_size; i++) {
		if (hash->keys [i] && (*func)(hash->keys [i], hash->values [i], user_data)) {
			mono_g_hash_table_remove (hash, hash->keys [i]);
			count++;
			/* Retry current slot in case the removal shifted elements */
			i--;
		}
	}
	if (hash->in_use < hash->table_size * HASH_TABLE_MIN_LOAD_FACTOR)
		rehash (hash);
	return count;
}
Beispiel #7
0
static void
selector_thread (gpointer data)
{
	MonoGHashTable *states;

	io_selector_running = TRUE;

	if (mono_runtime_is_shutting_down ()) {
		io_selector_running = FALSE;
		return;
	}

	states = mono_g_hash_table_new_type (g_direct_hash, g_direct_equal, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_THREAD_POOL, "i/o thread pool states table");

	for (;;) {
		gint i, j;
		gint res;

		mono_mutex_lock (&threadpool_io->updates_lock);

		for (i = 0; i < threadpool_io->updates_size; ++i) {
			ThreadPoolIOUpdate *update = &threadpool_io->updates [i];

			switch (update->type) {
			case UPDATE_EMPTY:
				break;
			case UPDATE_ADD: {
				gint fd;
				gint operations;
				gpointer k;
				gboolean exists;
				MonoMList *list = NULL;
				MonoIOSelectorJob *job;

				fd = update->data.add.fd;
				g_assert (fd >= 0);

				job = update->data.add.job;
				g_assert (job);

				exists = mono_g_hash_table_lookup_extended (states, GINT_TO_POINTER (fd), &k, (gpointer*) &list);
				list = mono_mlist_append (list, (MonoObject*) job);
				mono_g_hash_table_replace (states, GINT_TO_POINTER (fd), list);

				operations = get_operations_for_jobs (list);

				mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_THREADPOOL, "io threadpool: %3s fd %3d, operations = %2s | %2s | %2s",
					exists ? "mod" : "add", fd, (operations & EVENT_IN) ? "RD" : "..", (operations & EVENT_OUT) ? "WR" : "..");

				threadpool_io->backend.register_fd (fd, operations, !exists);

				break;
			}
			case UPDATE_REMOVE_SOCKET: {
				gint fd;
				gpointer k;
				MonoMList *list = NULL;

				fd = update->data.remove_socket.fd;
				g_assert (fd >= 0);

				if (mono_g_hash_table_lookup_extended (states, GINT_TO_POINTER (fd), &k, (gpointer*) &list)) {
					mono_g_hash_table_remove (states, GINT_TO_POINTER (fd));

					for (j = i + 1; j < threadpool_io->updates_size; ++j) {
						ThreadPoolIOUpdate *update = &threadpool_io->updates [j];
						if (update->type == UPDATE_ADD && update->data.add.fd == fd)
							memset (update, 0, sizeof (ThreadPoolIOUpdate));
					}

					for (; list; list = mono_mlist_remove_item (list, list))
						mono_threadpool_ms_enqueue_work_item (mono_object_domain (mono_mlist_get_data (list)), mono_mlist_get_data (list));

					mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_THREADPOOL, "io threadpool: del fd %3d", fd);
					threadpool_io->backend.remove_fd (fd);
				}

				break;
			}
			case UPDATE_REMOVE_DOMAIN: {
				MonoDomain *domain;

				domain = update->data.remove_domain.domain;
				g_assert (domain);

				FilterSockaresForDomainData user_data = { .domain = domain, .states = states };
				mono_g_hash_table_foreach (states, filter_jobs_for_domain, &user_data);

				for (j = i + 1; j < threadpool_io->updates_size; ++j) {
					ThreadPoolIOUpdate *update = &threadpool_io->updates [j];
					if (update->type == UPDATE_ADD && mono_object_domain (update->data.add.job) == domain)
						memset (update, 0, sizeof (ThreadPoolIOUpdate));
				}

				break;
			}
			default:
				g_assert_not_reached ();
			}
		}

		mono_cond_broadcast (&threadpool_io->updates_cond);

		if (threadpool_io->updates_size > 0) {
			threadpool_io->updates_size = 0;
			memset (&threadpool_io->updates, 0, UPDATES_CAPACITY * sizeof (ThreadPoolIOUpdate));
		}

		mono_mutex_unlock (&threadpool_io->updates_lock);

		mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_THREADPOOL, "io threadpool: wai");

		res = threadpool_io->backend.event_wait (wait_callback, states);

		if (res == -1 || mono_runtime_is_shutting_down ())
			break;
	}

	mono_g_hash_table_destroy (states);

	io_selector_running = FALSE;
}
Beispiel #8
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);
	}
}
Beispiel #9
0
static void
tp_kqueue_wait (gpointer p)
{
    SocketIOData *socket_io_data;
    int kfd;
    MonoInternalThread *thread;
    struct kevent *events, *evt;
    int ready = 0, i;
    gpointer async_results [KQUEUE_NEVENTS * 2]; // * 2 because each loop can add up to 2 results here
    gint nresults;
    tp_kqueue_data *data;

    socket_io_data = p;
    data = socket_io_data->event_data;
    kfd = data->fd;
    thread = mono_thread_internal_current ();
    events = g_new0 (struct kevent, KQUEUE_NEVENTS);

    while (1) {

        mono_gc_set_skip_thread (TRUE);

        do {
            if (ready == -1) {
                if (THREAD_WANTS_A_BREAK (thread))
                    mono_thread_interruption_checkpoint ();
            }
            ready = kevent (kfd, NULL, 0, events, KQUEUE_NEVENTS, NULL);
        } while (ready == -1 && errno == EINTR);

        mono_gc_set_skip_thread (FALSE);

        if (ready == -1) {
            int err = errno;
            g_free (events);
            if (err != EBADF)
                g_warning ("kevent wait: %d %s", err, g_strerror (err));

            return;
        }

        EnterCriticalSection (&socket_io_data->io_lock);
        if (socket_io_data->inited == 3) {
            g_free (events);
            LeaveCriticalSection (&socket_io_data->io_lock);
            return; /* cleanup called */
        }

        nresults = 0;
        for (i = 0; i < ready; i++) {
            int fd;
            MonoMList *list;
            MonoObject *ares;

            evt = &events [i];
            fd = evt->ident;
            list = mono_g_hash_table_lookup (socket_io_data->sock_to_state, GINT_TO_POINTER (fd));
            if (list != NULL && (evt->filter == EVFILT_READ || (evt->flags & EV_ERROR) != 0)) {
                ares = get_io_event (&list, MONO_POLLIN);
                if (ares != NULL)
                    async_results [nresults++] = ares;
            }
            if (list != NULL && (evt->filter == EVFILT_WRITE || (evt->flags & EV_ERROR) != 0)) {
                ares = get_io_event (&list, MONO_POLLOUT);
                if (ares != NULL)
                    async_results [nresults++] = ares;
            }

            if (list != NULL) {
                int p;

                mono_g_hash_table_replace (socket_io_data->sock_to_state, GINT_TO_POINTER (fd), list);
                p = get_events_from_list (list);
                if (evt->filter == EVFILT_READ && (p & MONO_POLLIN) != 0) {
                    EV_SET (evt, fd, EVFILT_READ, EV_ADD | EV_ENABLE | EV_ONESHOT, 0, 0, 0);
                    kevent_change (kfd, evt, "READD read");
                }

                if (evt->filter == EVFILT_WRITE && (p & MONO_POLLOUT) != 0) {
                    EV_SET (evt, fd, EVFILT_WRITE, EV_ADD | EV_ENABLE | EV_ONESHOT, 0, 0, 0);
                    kevent_change (kfd, evt, "READD write");
                }
            } else {
                mono_g_hash_table_remove (socket_io_data->sock_to_state, GINT_TO_POINTER (fd));
            }
        }
        LeaveCriticalSection (&socket_io_data->io_lock);
        threadpool_append_jobs (&async_io_tp, (MonoObject **) async_results, nresults);
        mono_gc_bzero (async_results, sizeof (gpointer) * nresults);
    }
}
Beispiel #10
0
static void
tp_epoll_wait (gpointer p)
{
	SocketIOData *socket_io_data;
	int epollfd;
	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;
	tp_epoll_data *data;

	socket_io_data = p;
	data = socket_io_data->event_data;
	epollfd = data->epollfd;
	events = g_new0 (struct epoll_event, EPOLL_NEVENTS);

	while (1) {
		mono_gc_set_skip_thread (TRUE);

		do {
			if (ready == -1) {
				check_for_interruption_critical ();
			}
			ready = epoll_wait (epollfd, events, EPOLL_NEVENTS, -1);
		} while (ready == -1 && errno == EINTR);

		mono_gc_set_skip_thread (FALSE);

		if (ready == -1) {
			int err = errno;
			g_free (events);
			if (err != EBADF)
				g_warning ("epoll_wait: %d %s", err, g_strerror (err));

			return;
		}

		EnterCriticalSection (&socket_io_data->io_lock);
		if (socket_io_data->inited == 3) {
			g_free (events);
			LeaveCriticalSection (&socket_io_data->io_lock);
			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 (socket_io_data->sock_to_state, GINT_TO_POINTER (fd));
			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) {
				int p;

				mono_g_hash_table_replace (socket_io_data->sock_to_state, GINT_TO_POINTER (fd), list);
				p = get_events_from_list (list);
				evt->events = (p & MONO_POLLOUT) ? EPOLLOUT : 0;
				evt->events |= (p & MONO_POLLIN) ? EPOLLIN : 0;
				if (epoll_ctl (epollfd, EPOLL_CTL_MOD, fd, evt) == -1) {
					if (epoll_ctl (epollfd, EPOLL_CTL_ADD, fd, evt) == -1) {
						int err = errno;
						g_message ("epoll(ADD): %d %s", err, g_strerror (err));
					}
				}
			} else {
				mono_g_hash_table_remove (socket_io_data->sock_to_state, GINT_TO_POINTER (fd));
				epoll_ctl (epollfd, EPOLL_CTL_DEL, fd, evt);
			}
		}
		LeaveCriticalSection (&socket_io_data->io_lock);
		threadpool_append_jobs (&async_io_tp, (MonoObject **) async_results, nresults);
		mono_gc_bzero (async_results, sizeof (gpointer) * nresults);
	}
}