コード例 #1
0
static void
async_invoke_thread (gpointer data)
{
	MonoDomain *domain;
	MonoWSQ *wsq;
	ThreadPool *tp;
	gboolean must_die;
  
	tp = data;
	wsq = NULL;
	if (!tp->is_io)
		wsq = add_wsq ();

	set_tp_thread_info (tp);

	if (tp_start_func)
		tp_start_func (tp_hooks_user_data);

	data = NULL;
	for (;;) {
		MonoAsyncResult *ar;
		MonoClass *klass;
		gboolean is_io_task;
		gboolean is_socket;
		int n_naps = 0;

		is_io_task = FALSE;
		ar = (MonoAsyncResult *) data;
		if (ar) {
			InterlockedIncrement (&tp->busy_threads);
			domain = ((MonoObject *)ar)->vtable->domain;
#ifndef DISABLE_SOCKETS
			klass = ((MonoObject *) data)->vtable->klass;
			is_io_task = !is_corlib_asyncresult (domain, klass);
			is_socket = FALSE;
			if (is_io_task) {
				MonoSocketAsyncResult *state = (MonoSocketAsyncResult *) data;
				is_socket = is_socketasyncresult (domain, klass);
				ar = state->ares;
				switch (state->operation) {
				case AIO_OP_RECEIVE:
					state->total = ICALL_RECV (state);
					break;
				case AIO_OP_SEND:
					state->total = ICALL_SEND (state);
					break;
				}
			}
#endif
			/* worker threads invokes methods in different domains,
			 * so we need to set the right domain here */
			g_assert (domain);

			if (mono_domain_is_unloading (domain) || mono_runtime_is_shutting_down ()) {
				threadpool_jobs_dec ((MonoObject *)ar);
				data = NULL;
				ar = NULL;
				InterlockedDecrement (&tp->busy_threads);
			} else {
				mono_thread_push_appdomain_ref (domain);
				if (threadpool_jobs_dec ((MonoObject *)ar)) {
					data = NULL;
					ar = NULL;
					mono_thread_pop_appdomain_ref ();
					InterlockedDecrement (&tp->busy_threads);
					continue;
				}

				if (mono_domain_set (domain, FALSE)) {
					MonoObject *exc;

					if (tp_item_begin_func)
						tp_item_begin_func (tp_item_user_data);

					exc = mono_async_invoke (tp, ar);
					if (tp_item_end_func)
						tp_item_end_func (tp_item_user_data);
					if (exc)
						mono_internal_thread_unhandled_exception (exc);
					if (is_socket && tp->is_io) {
						MonoSocketAsyncResult *state = (MonoSocketAsyncResult *) data;

						if (state->completed && state->callback) {
							MonoAsyncResult *cb_ares;
							cb_ares = create_simple_asyncresult ((MonoObject *) state->callback,
												(MonoObject *) state);
							icall_append_job ((MonoObject *) cb_ares);
						}
					}
					mono_domain_set (mono_get_root_domain (), TRUE);
				}
				mono_thread_pop_appdomain_ref ();
				InterlockedDecrement (&tp->busy_threads);
				clear_thread_state ();
			}
		}

		ar = NULL;
		data = NULL;
		must_die = should_i_die (tp);
		if (must_die) {
			mono_wsq_suspend (wsq);
		} else {
			if (tp->is_io || !mono_wsq_local_pop (&data))
				dequeue_or_steal (tp, &data, wsq);
		}

		n_naps = 0;
		while (!must_die && !data && n_naps < 4) {
			gboolean res;

			InterlockedIncrement (&tp->waiting);

			// Another thread may have added a job into its wsq since the last call to dequeue_or_steal
			// Check all the queues again before entering the wait loop
			dequeue_or_steal (tp, &data, wsq);
			if (data) {
				InterlockedDecrement (&tp->waiting);
				break;
			}

			mono_gc_set_skip_thread (TRUE);

#if defined(__OpenBSD__)
			while (mono_cq_count (tp->queue) == 0 && (res = mono_sem_wait (&tp->new_job, TRUE)) == -1) {// && errno == EINTR) {
#else
			while (mono_cq_count (tp->queue) == 0 && (res = mono_sem_timedwait (&tp->new_job, 2000, TRUE)) == -1) {// && errno == EINTR) {
#endif
				if (mono_runtime_is_shutting_down ())
					break;
				check_for_interruption_critical ();
			}
			InterlockedDecrement (&tp->waiting);

			mono_gc_set_skip_thread (FALSE);

			if (mono_runtime_is_shutting_down ())
				break;
			must_die = should_i_die (tp);
			dequeue_or_steal (tp, &data, wsq);
			n_naps++;
		}

		if (!data && !tp->is_io && !mono_runtime_is_shutting_down ()) {
			mono_wsq_local_pop (&data);
			if (data && must_die) {
				InterlockedCompareExchange (&tp->destroy_thread, 1, 0);
				pulse_on_new_job (tp);
			}
		}

		if (!data) {
			gint nt;
			gboolean down;
			while (1) {
				nt = tp->nthreads;
				down = mono_runtime_is_shutting_down ();
				if (!down && nt <= tp->min_threads)
					break;
				if (down || InterlockedCompareExchange (&tp->nthreads, nt - 1, nt) == nt) {
#ifndef DISABLE_PERFCOUNTERS
					mono_perfcounter_update_value (tp->pc_nthreads, TRUE, -1);
#endif
					if (!tp->is_io) {
						remove_wsq (wsq);
					}

					fire_profiler_thread_end ();

					if (tp_finish_func)
						tp_finish_func (tp_hooks_user_data);

					if (!tp->is_io) {
						if (threads) {
							mono_mutex_lock (&threads_lock);
							if (threads)
								g_ptr_array_remove_fast (threads, mono_thread_current ()->internal_thread);
							mono_mutex_unlock (&threads_lock);
						}
					}

					return;
				}
			}
		}
	}

	g_assert_not_reached ();
}

void
ves_icall_System_Threading_ThreadPool_GetAvailableThreads (gint *workerThreads, gint *completionPortThreads)
{
	*workerThreads = async_tp.max_threads - async_tp.busy_threads;
	*completionPortThreads = async_io_tp.max_threads - async_io_tp.busy_threads;
}
コード例 #2
0
ファイル: tpool-epoll.c プロジェクト: aakashapoorv/mono
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);
	}
}
コード例 #3
0
ファイル: tpool-kqueue.c プロジェクト: Adamcbrz/mono
static void
tp_kqueue_wait (gpointer p)
{
	SocketIOData *socket_io_data;
	int kfd;
	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;
	events = g_new0 (struct kevent, KQUEUE_NEVENTS);

	while (1) {
	
		mono_gc_set_skip_thread (TRUE);

		do {
			if (ready == -1) {
				check_for_interruption_critical ();
			}
			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;
		}

		mono_mutex_lock (&socket_io_data->io_lock);
		if (socket_io_data->inited == 3) {
			g_free (events);
			mono_mutex_unlock (&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));
			}
		}
		mono_mutex_unlock (&socket_io_data->io_lock);
		threadpool_append_jobs (&async_io_tp, (MonoObject **) async_results, nresults);
		mono_gc_bzero_aligned (async_results, sizeof (gpointer) * nresults);
	}
}