示例#1
0
void*
mono_threads_reset_blocking_start (void)
{
	MonoThreadInfo *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;

	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");
	}
}
示例#2
0
void
mono_threads_finish_blocking (void *cookie)
{
	static gboolean warned_about_bad_transition;
	MonoThreadInfo *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");
	}
}
示例#3
0
void*
mono_threads_try_prepare_blocking (void)
{
	MonoThreadInfo *info;

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

retry:
	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;
}
示例#4
0
void
mono_threads_state_poll (void)
{
	MonoThreadInfo *info;
	++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;
	}
}
示例#5
0
/*
Signal that the current thread wants to be suspended.
This function can be called without holding the suspend lock held.
To finish suspending, call mono_suspend_check.
*/
void
mono_thread_info_begin_self_suspend (void)
{
	MonoThreadInfo *info = mono_thread_info_current_unchecked ();
	if (!info)
		return;

	THREADS_SUSPEND_DEBUG ("BEGIN SELF SUSPEND OF %p\n", info);
	mono_threads_transition_request_self_suspension (info);
}
示例#6
0
void
mono_threads_reset_blocking_end (void *cookie)
{
	MonoThreadInfo *info = cookie;

	if (!info)
		return;

	g_assert (info == mono_thread_info_current_unchecked ());
	mono_threads_prepare_blocking ();
}
示例#7
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);
}
示例#8
0
DWORD
mono_win32_wsa_wait_for_multiple_events (DWORD count, const WSAEVENT FAR *handles, BOOL waitAll, DWORD timeout, BOOL alertable)
{
	DWORD result = WAIT_FAILED;
	MonoThreadInfo * const info = alertable ? mono_thread_info_current_unchecked () : NULL;

	if (info)
		enter_alertable_wait (info);

	result = WSAWaitForMultipleEvents (count, handles, waitAll, timeout, alertable);

	// NOTE, leave_alertable_wait should not affect GetLastError but
	// if changed, GetLastError needs to be preserved and reset before returning.
	if (info)
		leave_alertable_wait (info);

	return result;
}
示例#9
0
DWORD
mono_win32_sleep_ex (DWORD timeout, BOOL alertable)
{
	DWORD result = WAIT_FAILED;
	MonoThreadInfo * const info = alertable ? mono_thread_info_current_unchecked () : NULL;

	if (info)
		enter_alertable_wait (info);

	result = SleepEx (timeout, alertable);

	// NOTE, leave_alertable_wait should not affect GetLastError but
	// if changed, GetLastError needs to be preserved and reset before returning.
	if (info)
		leave_alertable_wait (info);

	return result;
}
示例#10
0
DWORD
mono_win32_signal_object_and_wait (HANDLE toSignal, HANDLE toWait, DWORD timeout, BOOL alertable)
{
	DWORD result = WAIT_FAILED;
	MonoThreadInfo * const info = alertable ? mono_thread_info_current_unchecked () : NULL;

	if (info)
		enter_alertable_wait (info);

	result = SignalObjectAndWait (toSignal, toWait, timeout, alertable);

	// NOTE, leave_alertable_wait should not affect GetLastError but
	// if changed, GetLastError needs to be preserved and reset before returning.
	if (info)
		leave_alertable_wait (info);

	return result;
}
示例#11
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;
}
示例#12
0
DWORD
mono_win32_msg_wait_for_multiple_objects_ex (DWORD count, CONST HANDLE *handles, DWORD timeout, DWORD wakeMask, DWORD flags)
{
	DWORD result = WAIT_FAILED;
	BOOL alertable = flags & MWMO_ALERTABLE;
	MonoThreadInfo * const info = alertable ? mono_thread_info_current_unchecked () : NULL;

	if (info)
		enter_alertable_wait (info);

	result = MsgWaitForMultipleObjectsEx (count, handles, timeout, wakeMask, flags);

	// NOTE, leave_alertable_wait should not affect GetLastError but
	// if changed, GetLastError needs to be preserved and reset before returning.
	if (info)
		leave_alertable_wait (info);

	return result;
}
示例#13
0
DWORD
mono_win32_wait_for_single_object_ex (HANDLE handle, DWORD timeout, BOOL alertable)
{
	DWORD result = WAIT_FAILED;
	MonoThreadInfo * const info = alertable ? mono_thread_info_current_unchecked () : NULL;

	if (info)
		enter_alertable_wait (info);

	result = WaitForSingleObjectEx (handle, timeout, alertable);

	// NOTE, leave_alertable_wait should not affect GetLastError but
	// if changed, GetLastError needs to be preserved and reset before returning.
	if (alertable && info) {
		leave_alertable_wait (info);
	}

	return result;
}
示例#14
0
void
checked_build_thread_transition (const char *transition, void *info, int from_state, int suspend_count, int next_state, int suspend_count_delta)
{
	MonoThreadInfo *cur = mono_thread_info_current_unchecked ();
	CheckState *state = get_state ();
	/* We currently don't record external changes as those are hard to reason about. */
	if (cur != info)
		return;

	if (state->transitions->len >= MAX_TRANSITIONS)
		free_transition (g_ptr_array_remove_index (state->transitions, 0));

	ThreadTransition *t = g_new0 (ThreadTransition, 1);
	t->name = transition;
	t->from_state = from_state;
	t->next_state = next_state;
	t->suspend_count = suspend_count;
	t->suspend_count_delta = suspend_count_delta;
	t->size = collect_backtrace (t->backtrace);
	g_ptr_array_add (state->transitions, t);
}
示例#15
0
DWORD
mono_win32_wait_for_multiple_objects_ex (DWORD count, CONST HANDLE *handles, BOOL waitAll, DWORD timeout, BOOL alertable, MonoError *error)
{
	MonoThreadInfo * const info = alertable ? mono_thread_info_current_unchecked () : NULL;

	if (info)
		enter_alertable_wait (info);

	DWORD const result = WaitForMultipleObjectsEx (count, handles, waitAll, timeout, alertable);

	// NOTE, leave_alertable_wait should not affect GetLastError but
	// if changed, GetLastError needs to be preserved and reset before returning.
	if (info)
		leave_alertable_wait (info);

	// This is not perfect, but it is the best you can do in usermode and matches CoreCLR.
	// i.e. handle-based instead of object-based.

	if (result == WAIT_FAILED && waitAll && error &&
			count > 1 && count <= MAXIMUM_WAIT_OBJECTS
			&& GetLastError () == ERROR_INVALID_PARAMETER) {
		gpointer handles_sorted [MAXIMUM_WAIT_OBJECTS]; // 64
		memcpy (handles_sorted, handles, count * sizeof (handles [0]));
		qsort (handles_sorted, count, sizeof (handles_sorted [0]), g_direct_equal);
		for (DWORD i = 1; i < count; ++i) {
			if (handles_sorted [i - 1] == handles_sorted [i]) {
				mono_error_set_duplicate_wait_object (error);
				mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_HANDLE, "%s: handle %p is duplicated", __func__, handles_sorted [i]);
				// Preserve LastError, but reduce triggering write breakpoints.
				if (GetLastError () != ERROR_INVALID_PARAMETER)
					SetLastError (ERROR_INVALID_PARAMETER);
				break;
			}
		}
	}

	return result;
}
示例#16
0
gpointer
mono_threads_enter_gc_unsafe_region_unbalanced (gpointer *stackdata)
{
	return mono_threads_enter_gc_unsafe_region_unbalanced_with_info (mono_thread_info_current_unchecked (), stackdata);
}
示例#17
0
void
mono_thread_info_suspend_lock (void)
{
	mono_thread_info_suspend_lock_with_info (mono_thread_info_current_unchecked ());
}
示例#18
0
void
mono_threads_state_poll (void)
{
	mono_threads_state_poll_with_info (mono_thread_info_current_unchecked ());
}