Exemplo n.º 1
0
void
ves_icall_System_IOSelector_Add (gpointer handle, MonoIOSelectorJob *job)
{
	ThreadPoolIOUpdate *update;

	g_assert (handle >= 0);

	g_assert (job->operation == EVENT_IN ^ job->operation == EVENT_OUT);
	g_assert (job->callback);

	if (mono_runtime_is_shutting_down ())
		return;
	if (mono_domain_is_unloading (mono_object_domain (job)))
		return;

	mono_lazy_initialize (&io_status, initialize);

	mono_mutex_lock (&threadpool_io->updates_lock);

	update = update_get_new ();
	update->type = UPDATE_ADD;
	update->data.add.fd = GPOINTER_TO_INT (handle);
	update->data.add.job = job;
	mono_memory_barrier (); /* Ensure this is safely published before we wake up the selector */

	selector_thread_wakeup ();

	mono_mutex_unlock (&threadpool_io->updates_lock);
}
Exemplo n.º 2
0
/*
 * Some of our objects may point to a different address than the address returned by GC_malloc()
 * (because of the GetHashCode hack), but we need to pass the real address to register_finalizer.
 * This also means that in the callback we need to adjust the pointer to get back the real
 * MonoObject*.
 * We also need to be consistent in the use of the GC_debug* variants of malloc and register_finalizer, 
 * since that, too, can cause the underlying pointer to be offset.
 */
static void
object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*))
{
#if HAVE_BOEHM_GC
	guint offset = 0;
	MonoDomain *domain;

	if (obj == NULL)
		mono_raise_exception (mono_get_exception_argument_null ("obj"));
	
	domain = obj->vtable->domain;

#ifndef GC_DEBUG
	/* This assertion is not valid when GC_DEBUG is defined */
	g_assert (GC_base (obj) == (char*)obj - offset);
#endif

	if (mono_domain_is_unloading (domain) && (callback != NULL))
		/*
		 * Can't register finalizers in a dying appdomain, since they
		 * could be invoked after the appdomain has been unloaded.
		 */
		return;

	mono_domain_finalizers_lock (domain);

	if (callback)
		g_hash_table_insert (domain->finalizable_objects_hash, obj, obj);
	else
		g_hash_table_remove (domain->finalizable_objects_hash, obj);

	mono_domain_finalizers_unlock (domain);

	GC_REGISTER_FINALIZER_NO_ORDER ((char*)obj - offset, callback, GUINT_TO_POINTER (offset), NULL, NULL);
#elif defined(HAVE_SGEN_GC)
	if (obj == NULL)
		mono_raise_exception (mono_get_exception_argument_null ("obj"));

	/*
	 * If we register finalizers for domains that are unloading we might
	 * end up running them while or after the domain is being cleared, so
	 * the objects will not be valid anymore.
	 */
	if (!mono_domain_is_unloading (obj->vtable->domain))
		mono_gc_register_for_finalization (obj, callback);
#endif
}
Exemplo n.º 3
0
Arquivo: gc.c Projeto: rodrmoya/mono
/*
 * Some of our objects may point to a different address than the address returned by GC_malloc()
 * (because of the GetHashCode hack), but we need to pass the real address to register_finalizer.
 * This also means that in the callback we need to adjust the pointer to get back the real
 * MonoObject*.
 * We also need to be consistent in the use of the GC_debug* variants of malloc and register_finalizer, 
 * since that, too, can cause the underlying pointer to be offset.
 */
static void
object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*))
{
	MonoDomain *domain;

	if (obj == NULL)
		mono_raise_exception (mono_get_exception_argument_null ("obj"));

	domain = obj->vtable->domain;

#if HAVE_BOEHM_GC
	if (mono_domain_is_unloading (domain) && (callback != NULL))
		/*
		 * Can't register finalizers in a dying appdomain, since they
		 * could be invoked after the appdomain has been unloaded.
		 */
		return;

	mono_domain_finalizers_lock (domain);

	if (callback)
		g_hash_table_insert (domain->finalizable_objects_hash, obj, obj);
	else
		g_hash_table_remove (domain->finalizable_objects_hash, obj);

	mono_domain_finalizers_unlock (domain);

	mono_gc_register_for_finalization (obj, callback);
#elif defined(HAVE_SGEN_GC)
	/*
	 * If we register finalizers for domains that are unloading we might
	 * end up running them while or after the domain is being cleared, so
	 * the objects will not be valid anymore.
	 */
	if (!mono_domain_is_unloading (domain)) {
		MONO_TRY_BLOCKING;
		mono_gc_register_for_finalization (obj, callback);
		MONO_FINISH_TRY_BLOCKING;
	}
#endif
}
Exemplo n.º 4
0
static void
threadpool_append_jobs (ThreadPool *tp, MonoObject **jobs, gint njobs)
{
	MonoObject *ar;
	gint i;

	if (mono_runtime_is_shutting_down ())
		return;

	if (tp->pool_status == 0 && InterlockedCompareExchange (&tp->pool_status, 1, 0) == 0) {
		if (!tp->is_io) {
			monitor_internal_thread = mono_thread_create_internal (mono_get_root_domain (), monitor_thread, NULL, TRUE, SMALL_STACK);
			monitor_internal_thread->flags |= MONO_THREAD_FLAG_DONT_MANAGE;
			threadpool_start_thread (tp);
		}
		/* Create on demand up to min_threads to avoid startup penalty for apps that don't use
		 * the threadpool that much
		 */
		if (mono_config_is_server_mode ()) {
			mono_thread_create_internal (mono_get_root_domain (), threadpool_start_idle_threads, tp, TRUE, SMALL_STACK);
		}
	}

	InterlockedAdd (&monitor_njobs, njobs);

	if (monitor_state == MONITOR_STATE_SLEEPING && InterlockedCompareExchange (&monitor_state, MONITOR_STATE_AWAKE, MONITOR_STATE_SLEEPING) == MONITOR_STATE_SLEEPING)
		MONO_SEM_POST (&monitor_sem);

	if (monitor_state == MONITOR_STATE_FALLING_ASLEEP)
		InterlockedCompareExchange (&monitor_state, MONITOR_STATE_AWAKE, MONITOR_STATE_FALLING_ASLEEP);

	for (i = 0; i < njobs; i++) {
		ar = jobs [i];
		if (ar == NULL || mono_domain_is_unloading (ar->vtable->domain))
			continue; /* Might happen when cleaning domain jobs */
		threadpool_jobs_inc (ar); 
#ifndef DISABLE_PERFCOUNTERS
		mono_perfcounter_update_value (tp->pc_nitems, TRUE, 1);
#endif
		if (!tp->is_io && mono_wsq_local_push (ar))
			continue;

		mono_cq_enqueue (tp->queue, ar);
	}

#if DEBUG
	InterlockedAdd (&tp->njobs, njobs);
#endif

	for (i = 0; tp->waiting > 0 && i < MIN(njobs, tp->max_threads); i++)
		pulse_on_new_job (tp);
}
Exemplo n.º 5
0
static void
worker_thread (gpointer data)
{
	static MonoClass *threadpool_wait_callback_class = NULL;
	static MonoMethod *perform_wait_callback_method = NULL;
	MonoInternalThread *thread;
	ThreadPoolDomain *tpdomain;
	ThreadPoolCounter counter;
	gboolean retire = FALSE;

	g_assert (status >= STATUS_INITIALIZED);

	tpdomain = data;
	g_assert (tpdomain);
	g_assert (tpdomain->domain);

	if (mono_runtime_is_shutting_down () || mono_domain_is_unloading (tpdomain->domain)) {
		COUNTER_ATOMIC (counter, { counter._.active --; });
Exemplo n.º 6
0
static void
threadpool_append_jobs (ThreadPool *tp, MonoObject **jobs, gint njobs)
{
	static int job_counter;
	MonoObject *ar;
	gint i;

	if (mono_runtime_is_shutting_down ())
		return;

	if (tp->pool_status == 0 && InterlockedCompareExchange (&tp->pool_status, 1, 0) == 0) {
		if (!tp->is_io) {
			mono_thread_create_internal (mono_get_root_domain (), monitor_thread, NULL, TRUE, SMALL_STACK);
			threadpool_start_thread (tp);
		}
		/* Create on demand up to min_threads to avoid startup penalty for apps that don't use
		 * the threadpool that much
		 */
		if (mono_config_is_server_mode ()) {
			mono_thread_create_internal (mono_get_root_domain (), threadpool_start_idle_threads, tp, TRUE, SMALL_STACK);
		}
	}

	for (i = 0; i < njobs; i++) {
		ar = jobs [i];
		if (ar == NULL || mono_domain_is_unloading (ar->vtable->domain))
			continue; /* Might happen when cleaning domain jobs */
		if (!tp->is_io && (InterlockedIncrement (&job_counter) % 10) == 0) {
			MonoAsyncResult *o = (MonoAsyncResult *) ar;
			o->add_time = mono_100ns_ticks ();
		}
		threadpool_jobs_inc (ar); 
#ifndef DISABLE_PERFCOUNTERS
		mono_perfcounter_update_value (tp->pc_nitems, TRUE, 1);
#endif
		if (!tp->is_io && mono_wsq_local_push (ar))
			continue;

		mono_cq_enqueue (tp->queue, ar);
	}

	for (i = 0; tp->waiting > 0 && i < MIN(njobs, tp->max_threads); i++)
		pulse_on_new_job (tp);
}
Exemplo n.º 7
0
static void
async_invoke_thread (gpointer data)
{
	MonoDomain *domain;
	MonoInternalThread *thread;
	MonoWSQ *wsq;
	ThreadPool *tp;
	gboolean must_die;
	const gchar *name;
  
	tp = data;
	wsq = NULL;
	if (!tp->is_io)
		wsq = add_wsq ();

	thread = mono_thread_internal_current ();

	mono_profiler_thread_start (thread->tid);
	name = (tp->is_io) ? "IO Threadpool worker" : "Threadpool worker";
	mono_thread_set_name_internal (thread, mono_string_new (mono_domain_get (), name), FALSE);

	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);

					if (!is_io_task && ar->add_time > 0)
						process_idle_times (tp, ar->add_time);
					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);
				/* If the callee changes the background status, set it back to TRUE */
				mono_thread_clr_state (thread , ~ThreadState_Background);
				if (!mono_thread_test_state (thread , ThreadState_Background))
					ves_icall_System_Threading_Thread_SetState (thread, ThreadState_Background);
			}
		}

		ar = NULL;
		data = NULL;
		must_die = should_i_die (tp);
		if (!must_die && (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;
				if (THREAD_WANTS_A_BREAK (thread))
					mono_thread_interruption_checkpoint ();
			}
			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) {
					mono_perfcounter_update_value (tp->pc_nthreads, TRUE, -1);
					if (!tp->is_io) {
						remove_wsq (wsq);
					}

					mono_profiler_thread_end (thread->tid);

					if (tp_finish_func)
						tp_finish_func (tp_hooks_user_data);
					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;
}
Exemplo n.º 8
0
bool _GodotSharp::is_domain_finalizing_for_unload(MonoDomain *p_domain) {

	if (!p_domain)
		return true;
	return mono_domain_is_unloading(p_domain);
}