Esempio n. 1
0
void*
mono_threads_try_prepare_blocking (void* stackdata)
{
	MonoThreadInfo *info;

	if (!mono_threads_is_coop_enabled ())
		return NULL;

	++coop_try_blocking_count;

	info = mono_thread_info_current_unchecked ();
	/* If the thread is not attached, it doesn't make sense prepare for suspend. */
	if (!info || !mono_thread_info_is_live (info) || mono_thread_info_current_state (info) == STATE_BLOCKING) {
		THREADS_SUSPEND_DEBUG ("PREPARE-TRY-BLOCKING failed %p\n", mono_thread_info_get_tid (info));
		return NULL;
	}

	copy_stack_data (info, stackdata);

retry:
	++coop_save_count;
	mono_threads_get_runtime_callbacks ()->thread_state_init (&info->thread_saved_state [SELF_SUSPEND_STATE_INDEX]);

	switch (mono_threads_transition_do_blocking (info)) {
	case DoBlockingContinue:
		break;
	case DoBlockingPollAndRetry:
		mono_threads_state_poll ();
		goto retry;
	}

	return info;
}
Esempio n. 2
0
void*
mono_threads_reset_blocking_start (void* stackdata)
{
	MonoThreadInfo *info;

	if (!mono_threads_is_coop_enabled ())
		return NULL;

	++coop_reset_blocking_count;

	info = mono_thread_info_current_unchecked ();
	/* If the thread is not attached, it doesn't make sense prepare for suspend. */
	if (!info || !mono_thread_info_is_live (info))
		return NULL;

	copy_stack_data (info, stackdata);

	switch (mono_threads_transition_abort_blocking (info)) {
	case AbortBlockingIgnore:
		info->thread_saved_state [SELF_SUSPEND_STATE_INDEX].valid = FALSE;
		return NULL;
	case AbortBlockingIgnoreAndPoll:
		mono_threads_state_poll ();
		return NULL;
	case AbortBlockingOk:
		info->thread_saved_state [SELF_SUSPEND_STATE_INDEX].valid = FALSE;
		return info;
	case AbortBlockingOkAndPool:
		mono_threads_state_poll ();
		return info;
	default:
		g_error ("Unknown thread state");
	}
}
Esempio n. 3
0
static gpointer
mono_threads_enter_gc_safe_region_unbalanced_with_info (MonoThreadInfo *info, gpointer *stackdata)
{
	if (!mono_threads_is_coop_enabled ())
		return NULL;

	++coop_do_blocking_count;

	check_info (info, "enter", "safe");

	copy_stack_data (info, stackdata);

retry:
	++coop_save_count;
	mono_threads_get_runtime_callbacks ()->thread_state_init (&info->thread_saved_state [SELF_SUSPEND_STATE_INDEX]);

	switch (mono_threads_transition_do_blocking (info)) {
	case DoBlockingContinue:
		break;
	case DoBlockingPollAndRetry:
		mono_threads_state_poll_with_info (info);
		goto retry;
	}

	return info;
}
Esempio n. 4
0
gpointer
mono_threads_enter_gc_unsafe_region_unbalanced_with_info (MonoThreadInfo *info, gpointer *stackdata)
{
	if (!mono_threads_is_coop_enabled ())
		return NULL;

	++coop_reset_blocking_count;

	check_info (info, "enter", "unsafe");

	copy_stack_data (info, stackdata);

	switch (mono_threads_transition_abort_blocking (info)) {
	case AbortBlockingIgnore:
		info->thread_saved_state [SELF_SUSPEND_STATE_INDEX].valid = FALSE;
		return NULL;
	case AbortBlockingIgnoreAndPoll:
		mono_threads_state_poll_with_info (info);
		return NULL;
	case AbortBlockingOk:
		info->thread_saved_state [SELF_SUSPEND_STATE_INDEX].valid = FALSE;
		break;
	case AbortBlockingWait:
		mono_thread_info_wait_for_resume (info);
		break;
	default:
		g_error ("Unknown thread state");
	}

	return info;
}
Esempio n. 5
0
static void
rehash (MonoGHashTable *hash)
{
	MONO_REQ_GC_UNSAFE_MODE; //we must run in unsafe mode to make rehash safe

	int diff = ABS (hash->last_rehash - hash->in_use);
	RehashData data;
	void *old_table G_GNUC_UNUSED; /* unused on Boehm */

	/* These are the factors to play with to change the rehashing strategy */
	/* I played with them with a large range, and could not really get */
	/* something that was too good, maybe the tests are not that great */
	if (!(diff * 0.75 > hash->table_size * 2))
		return;

	data.hash = hash;
	data.new_size = g_spaced_primes_closest (hash->in_use);
	data.table = mg_new0 (Slot *, data.new_size);

	if (!mono_threads_is_coop_enabled ()) {
		old_table = mono_gc_invoke_with_gc_lock (do_rehash, &data);
	} else {
		/* We cannot be preempted */
		old_table = do_rehash (&data);
	}

	mg_free (old_table);
}
Esempio n. 6
0
void
mono_threads_finish_blocking (void *cookie, void* stackdata)
{
	static gboolean warned_about_bad_transition;
	MonoThreadInfo *info;

	if (!mono_threads_is_coop_enabled ())
		return;

	info = cookie;
	if (!info)
		return;

	g_assert (info == mono_thread_info_current_unchecked ());

	switch (mono_threads_transition_done_blocking (info)) {
	case DoneBlockingAborted:
		if (!warned_about_bad_transition) {
			warned_about_bad_transition = TRUE;
			g_warning ("[%p] Blocking call ended in running state for, this might lead to unbound GC pauses.", mono_thread_info_get_tid (info));
		}
		mono_threads_state_poll ();
		break;
	case DoneBlockingOk:
		info->thread_saved_state [SELF_SUSPEND_STATE_INDEX].valid = FALSE;
		break;
	case DoneBlockingWait:
		THREADS_SUSPEND_DEBUG ("state polling done, notifying of resume\n");
		mono_thread_info_wait_for_resume (info);
		break;
	default:
		g_error ("Unknown thread state");
	}
}
Esempio n. 7
0
void
mono_threads_state_poll (void)
{
	MonoThreadInfo *info;

	g_assert (mono_threads_is_coop_enabled ());

	++coop_do_polling_count;

	info = mono_thread_info_current_unchecked ();
	if (!info)
		return;
	THREADS_SUSPEND_DEBUG ("FINISH SELF SUSPEND OF %p\n", mono_thread_info_get_tid (info));

	/* Fast check for pending suspend requests */
	if (!(info->thread_state & (STATE_ASYNC_SUSPEND_REQUESTED | STATE_SELF_SUSPEND_REQUESTED)))
		return;

	++coop_save_count;
	mono_threads_get_runtime_callbacks ()->thread_state_init (&info->thread_saved_state [SELF_SUSPEND_STATE_INDEX]);

	/* commit the saved state and notify others if needed */
	switch (mono_threads_transition_state_poll (info)) {
	case SelfSuspendResumed:
		return;
	case SelfSuspendWait:
		mono_thread_info_wait_for_resume (info);
		break;
	case SelfSuspendNotifyAndWait:
		mono_threads_notify_initiator_of_suspend (info);
		mono_thread_info_wait_for_resume (info);
		break;
	}
}
Esempio n. 8
0
void
mono_threads_finish_try_blocking (void* cookie, void* stackdata)
{
	if (!mono_threads_is_coop_enabled ())
		return;

	mono_threads_finish_blocking (cookie, stackdata);
}
Esempio n. 9
0
void*
mono_threads_enter_gc_unsafe_region (void* stackdata)
{
	if (!mono_threads_is_coop_enabled ())
		return NULL;

	return mono_threads_reset_blocking_start (stackdata);
}
Esempio n. 10
0
void
mono_threads_exit_gc_unsafe_region (void *regions_cookie, void* stackdata)
{
	if (!mono_threads_is_coop_enabled ())
		return;

	mono_threads_reset_blocking_end (regions_cookie, stackdata);
}
Esempio n. 11
0
static void
resume_async_suspended (MonoThreadInfo *info)
{
	if (mono_threads_is_coop_enabled ())
		g_assert_not_reached ();

	g_assert (mono_threads_core_begin_async_resume (info));
}
Esempio n. 12
0
static gboolean
check_async_suspend (MonoThreadInfo *info)
{
	if (mono_threads_is_coop_enabled ()) {
		/* Async suspend can't async fail on coop */
		return TRUE;
	}

	return mono_threads_core_check_suspend_result (info);
}
Esempio n. 13
0
void
mono_threads_exit_gc_unsafe_region_unbalanced (gpointer cookie, gpointer *stackdata)
{
	if (!mono_threads_is_coop_enabled ())
		return;

	if (!cookie)
		return;

	mono_threads_enter_gc_safe_region_unbalanced (stackdata);
}
Esempio n. 14
0
static gboolean
begin_async_suspend (MonoThreadInfo *info, gboolean interrupt_kernel)
{
	if (mono_threads_is_coop_enabled ()) {
		/* There's nothing else to do after we async request the thread to suspend */
		mono_threads_add_to_pending_operation_set (info);
		return TRUE;
	}

	return mono_threads_core_begin_async_suspend (info, interrupt_kernel);
}
Esempio n. 15
0
void
mono_threads_init (MonoThreadInfoCallbacks *callbacks, size_t info_size)
{
	gboolean res;
	threads_callbacks = *callbacks;
	thread_info_size = info_size;
	const char *sleepLimit;
#ifdef HOST_WIN32
	res = mono_native_tls_alloc (&thread_info_key, NULL);
	res = mono_native_tls_alloc (&thread_exited_key, NULL);
#else
	res = mono_native_tls_alloc (&thread_info_key, (void *) thread_info_key_dtor);
	res = mono_native_tls_alloc (&thread_exited_key, (void *) thread_exited_dtor);
#endif

	g_assert (res);

#ifndef HAVE_KW_THREAD
	res = mono_native_tls_alloc (&small_id_key, NULL);
#endif
	g_assert (res);

	unified_suspend_enabled = g_getenv ("MONO_ENABLE_UNIFIED_SUSPEND") != NULL || mono_threads_is_coop_enabled ();
	
	if ((sleepLimit = g_getenv ("MONO_SLEEP_ABORT_LIMIT")) != NULL) {
		errno = 0;
		long threshold = strtol(sleepLimit, NULL, 10);
		if ((errno == 0) && (threshold >= 40))  {
			sleepAbortDuration = threshold;
			sleepWarnDuration = threshold / 20;
		} else
			g_warning("MONO_SLEEP_ABORT_LIMIT must be a number >= 40");
	}

	mono_os_sem_init (&global_suspend_semaphore, 1);
	mono_os_sem_init (&suspend_semaphore, 0);

	mono_lls_init (&thread_list, NULL, HAZARD_FREE_NO_LOCK);
	mono_thread_smr_init ();
	mono_threads_platform_init ();
	mono_threads_suspend_init ();
	mono_threads_coop_init ();
	mono_threads_abort_syscall_init ();

#if defined(__MACH__)
	mono_mach_init (thread_info_key);
#endif

	mono_threads_inited = TRUE;

	g_assert (sizeof (MonoNativeThreadId) <= sizeof (uintptr_t));
}
Esempio n. 16
0
void
mono_threads_exit_gc_unsafe_region (gpointer cookie, gpointer *stackdata)
{
	if (!mono_threads_is_coop_enabled ())
		return;

#ifdef ENABLE_CHECKED_BUILD_GC
	if (mono_check_mode_enabled (MONO_CHECK_MODE_GC))
		coop_tls_pop (cookie);
#endif

	mono_threads_exit_gc_unsafe_region_unbalanced (cookie, stackdata);
}
Esempio n. 17
0
void
mono_threads_init_coop (void)
{
	if (!mono_threads_is_coop_enabled ())
		return;

	mono_counters_register ("Coop Reset Blocking", MONO_COUNTER_GC | MONO_COUNTER_INT, &coop_reset_blocking_count);
	mono_counters_register ("Coop Try Blocking", MONO_COUNTER_GC | MONO_COUNTER_INT, &coop_try_blocking_count);
	mono_counters_register ("Coop Do Blocking", MONO_COUNTER_GC | MONO_COUNTER_INT, &coop_do_blocking_count);
	mono_counters_register ("Coop Do Polling", MONO_COUNTER_GC | MONO_COUNTER_INT, &coop_do_polling_count);
	mono_counters_register ("Coop Save Count", MONO_COUNTER_GC | MONO_COUNTER_INT, &coop_save_count);
	//See the above for what's wrong here.
}
Esempio n. 18
0
void
mono_threads_reset_blocking_end (void *cookie, void* stackdata)
{
	MonoThreadInfo *info;

	if (!mono_threads_is_coop_enabled ())
		return;

	info = cookie;
	if (!info)
		return;

	g_assert (info == mono_thread_info_current_unchecked ());
	mono_threads_prepare_blocking (stackdata);
}
Esempio n. 19
0
gpointer
mono_threads_enter_gc_unsafe_region_with_info (THREAD_INFO_TYPE *info, gpointer *stackdata)
{
	gpointer cookie;

	if (!mono_threads_is_coop_enabled ())
		return NULL;

	cookie = mono_threads_enter_gc_unsafe_region_unbalanced_with_info (info, stackdata);

#ifdef ENABLE_CHECKED_BUILD_GC
	if (mono_check_mode_enabled (MONO_CHECK_MODE_GC))
		coop_tls_push (cookie);
#endif

	return cookie;
}
Esempio n. 20
0
void
mono_threads_coop_init (void)
{
	if (!mono_threads_is_coop_enabled ())
		return;

	mono_counters_register ("Coop Reset Blocking", MONO_COUNTER_GC | MONO_COUNTER_INT, &coop_reset_blocking_count);
	mono_counters_register ("Coop Try Blocking", MONO_COUNTER_GC | MONO_COUNTER_INT, &coop_try_blocking_count);
	mono_counters_register ("Coop Do Blocking", MONO_COUNTER_GC | MONO_COUNTER_INT, &coop_do_blocking_count);
	mono_counters_register ("Coop Do Polling", MONO_COUNTER_GC | MONO_COUNTER_INT, &coop_do_polling_count);
	mono_counters_register ("Coop Save Count", MONO_COUNTER_GC | MONO_COUNTER_INT, &coop_save_count);
	//See the above for what's wrong here.

#ifdef ENABLE_CHECKED_BUILD_GC
	mono_native_tls_alloc (&coop_reset_count_stack_key, NULL);
#endif
}
Esempio n. 21
0
gpointer
mono_threads_enter_gc_unsafe_region_cookie (void)
{
	MonoThreadInfo *info;

	g_assert (mono_threads_is_coop_enabled ());

	info = mono_thread_info_current_unchecked ();

	check_info (info, "enter (cookie)", "unsafe");

#ifdef ENABLE_CHECKED_BUILD_GC
	if (mono_check_mode_enabled (MONO_CHECK_MODE_GC))
		coop_tls_push (info);
#endif

	return info;
}
Esempio n. 22
0
void
mono_threads_init (MonoThreadInfoCallbacks *callbacks, size_t info_size)
{
	gboolean res;
	threads_callbacks = *callbacks;
	thread_info_size = info_size;
#ifdef HOST_WIN32
	res = mono_native_tls_alloc (&thread_info_key, NULL);
	res = mono_native_tls_alloc (&thread_exited_key, NULL);
#else
	res = mono_native_tls_alloc (&thread_info_key, (void *) unregister_thread);
	res = mono_native_tls_alloc (&thread_exited_key, (void *) thread_exited_dtor);
#endif

	g_assert (res);

#ifndef HAVE_KW_THREAD
	res = mono_native_tls_alloc (&small_id_key, NULL);
#endif
	g_assert (res);

	unified_suspend_enabled = g_getenv ("MONO_ENABLE_UNIFIED_SUSPEND") != NULL || mono_threads_is_coop_enabled ();

	mono_coop_sem_init (&global_suspend_semaphore, 1);
	mono_os_sem_init (&suspend_semaphore, 0);

	mono_lls_init (&thread_list, NULL);
	mono_thread_smr_init ();
	mono_threads_init_platform ();
	mono_threads_init_coop ();
	mono_threads_init_abort_syscall ();

#if defined(__MACH__)
	mono_mach_init (thread_info_key);
#endif

	mono_threads_inited = TRUE;

	g_assert (sizeof (MonoNativeThreadId) <= sizeof (uintptr_t));
}
Esempio n. 23
0
void
mono_thread_info_safe_suspend_and_run (MonoNativeThreadId id, gboolean interrupt_kernel, MonoSuspendThreadCallback callback, gpointer user_data)
{
	int result;
	MonoThreadInfo *info = NULL;
	MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();

	THREADS_SUSPEND_DEBUG ("SUSPENDING tid %p\n", (void*)id);
	/*FIXME: unify this with self-suspend*/
	g_assert (id != mono_native_thread_id_get ());

	/* This can block during stw */
	mono_thread_info_suspend_lock ();
	mono_threads_begin_global_suspend ();

	info = suspend_sync_nolock (id, interrupt_kernel);
	if (!info)
		goto done;

	switch (result = callback (info, user_data)) {
	case MonoResumeThread:
		mono_hazard_pointer_set (hp, 1, info);
		mono_thread_info_core_resume (info);
		mono_threads_wait_pending_operations ();
		break;
	case KeepSuspended:
		g_assert (!mono_threads_is_coop_enabled ());
		break;
	default:
		g_error ("Invalid suspend_and_run callback return value %d", result);
	}

done:
	mono_hazard_pointer_clear (hp, 1);
	mono_threads_end_global_suspend ();
	mono_thread_info_suspend_unlock ();
}
Esempio n. 24
0
void
mono_threads_exit_gc_safe_region_unbalanced (gpointer cookie, gpointer *stackdata)
{
	MonoThreadInfo *info;

	if (!mono_threads_is_coop_enabled ())
		return;

	info = (MonoThreadInfo *)cookie;

	check_info (info, "exit", "safe");

	switch (mono_threads_transition_done_blocking (info)) {
	case DoneBlockingOk:
		info->thread_saved_state [SELF_SUSPEND_STATE_INDEX].valid = FALSE;
		break;
	case DoneBlockingWait:
		THREADS_SUSPEND_DEBUG ("state polling done, notifying of resume\n");
		mono_thread_info_wait_for_resume (info);
		break;
	default:
		g_error ("Unknown thread state");
	}
}
Esempio n. 25
0
void
mono_threads_coop_end_global_suspend (void)
{
	if (mono_threads_is_coop_enabled ())
		mono_polling_required = 0;
}