Beispiel #1
0
static void
mono_thread_info_suspend_lock_with_info (MonoThreadInfo *info)
{
	g_assert (info);
	g_assert (mono_thread_info_is_current (info));
	g_assert (mono_thread_info_is_live (info));

	MONO_ENTER_GC_SAFE_WITH_INFO(info);

	int res = mono_os_sem_wait (&global_suspend_semaphore, MONO_SEM_FLAGS_NONE);
	g_assert (res != -1);

	MONO_EXIT_GC_SAFE_WITH_INFO;
}
/*
Check the current state of the thread and try to init a self suspend.
This must be called with self state saved.

Returns one of the following values:

- Resumed: Async resume happened and current thread should keep running
- Suspend: Caller should wait for a resume signal
- SelfSuspendNotifyAndWait: Notify the suspend initiator and wait for a resume signals
 suspend should start.

*/
MonoSelfSupendResult
mono_threads_transition_state_poll (MonoThreadInfo *info)
{
	int raw_state, cur_state, suspend_count;
	g_assert (mono_thread_info_is_current (info));

retry_state_change:
	UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
	switch (cur_state) {
	case STATE_RUNNING:
		if (!(suspend_count == 0))
			mono_fatal_with_history ("suspend_count = %d, but should be == 0", suspend_count);
		trace_state_change ("STATE_POLL", info, raw_state, cur_state, 0);
		return SelfSuspendResumed; //We're fine, don't suspend

	case STATE_ASYNC_SUSPEND_REQUESTED: //Async suspend requested, service it with a self suspend
		if (!(suspend_count > 0))
			mono_fatal_with_history ("suspend_count = %d, but should be > 0", suspend_count);
		if (mono_atomic_cas_i32 (&info->thread_state, build_thread_state (STATE_SELF_SUSPENDED, suspend_count), raw_state) != raw_state)
			goto retry_state_change;
		trace_state_change ("STATE_POLL", info, raw_state, STATE_SELF_SUSPENDED, 0);
		return SelfSuspendNotifyAndWait; //Caller should notify suspend initiator and wait for resume

/*
STATE_ASYNC_SUSPENDED: Code should not be running while suspended.
STATE_SELF_SUSPENDED: Code should not be running while suspended.
STATE_BLOCKING:
STATE_BLOCKING_SUSPEND_REQUESTED:
STATE_BLOCKING_ASYNC_SUSPENDED:
STATE_BLOCKING_SELF_SUSPENDED: Poll is a local state transition. No VM activities are allowed while in blocking mode.
      (In all the blocking states - the local thread has no checkpoints, hence
      no polling, it can only do abort blocking or done blocking on itself).
*/
	default:
		mono_fatal_with_history ("Cannot transition thread %p from %s with STATE_POLL", mono_thread_info_get_tid (info), state_name (cur_state));
	}
}
Beispiel #3
0
static void
unregister_thread (void *arg)
{
	gpointer gc_unsafe_stackdata;
	MonoThreadInfo *info;
	int small_id;

	info = (MonoThreadInfo *) arg;
	g_assert (info);
	g_assert (mono_thread_info_is_current (info));
	g_assert (mono_thread_info_is_live (info));

	small_id = info->small_id;

	/* We only enter the GC unsafe region, as when exiting this function, the thread
	 * will be detached, and the current MonoThreadInfo* will be destroyed. */
	mono_threads_enter_gc_unsafe_region_unbalanced_with_info (info, &gc_unsafe_stackdata);

	THREADS_DEBUG ("unregistering info %p\n", info);

	mono_native_tls_set_value (thread_exited_key, GUINT_TO_POINTER (1));

	mono_threads_platform_unregister (info);

	/*
	 * TLS destruction order is not reliable so small_id might be cleaned up
	 * before us.
	 */
#ifndef HAVE_KW_THREAD
	mono_native_tls_set_value (small_id_key, GUINT_TO_POINTER (info->small_id + 1));
#endif

	/*
	First perform the callback that requires no locks.
	This callback has the potential of taking other locks, so we do it before.
	After it completes, the thread remains functional.
	*/
	if (threads_callbacks.thread_detach)
		threads_callbacks.thread_detach (info);

	mono_thread_info_suspend_lock_with_info (info);

	/*
	Now perform the callback that must be done under locks.
	This will render the thread useless and non-suspendable, so it must
	be done while holding the suspend lock to give no other thread chance
	to suspend it.
	*/
	if (threads_callbacks.thread_unregister)
		threads_callbacks.thread_unregister (info);
	mono_threads_unregister_current_thread (info);
	mono_threads_transition_detach (info);

	mono_thread_info_suspend_unlock ();

	g_byte_array_free (info->stackdata, /*free_segment=*/TRUE);

	/*now it's safe to free the thread info.*/
	mono_thread_hazardous_try_free (info, free_thread_info);
	/* Pump the HP queue */
	mono_thread_hazardous_try_free_some ();

	mono_thread_small_id_free (small_id);
}
Beispiel #4
0
void
mono_thread_info_set_exited (THREAD_INFO_TYPE *info)
{
	g_assert (mono_thread_info_is_current (info));
	mono_threads_platform_set_exited (info);
}
Beispiel #5
0
gpointer
mono_thread_info_duplicate_handle (MonoThreadInfo *info)
{
	g_assert (mono_thread_info_is_current (info));
	return mono_threads_platform_duplicate_handle (info);
}