Exemplo n.º 1
0
static void*
register_thread (MonoThreadInfo *info, gpointer baseptr)
{
	size_t stsize = 0;
	guint8 *staddr = NULL;
	int small_id = mono_thread_info_register_small_id ();
	gboolean result;
	mono_thread_info_set_tid (info, mono_native_thread_id_get ());
	info->small_id = small_id;

	info->handle = g_new0 (MonoThreadHandle, 1);
	mono_refcount_init (info->handle, thread_handle_destroy);
	mono_os_event_init (&info->handle->event, FALSE);

	mono_os_sem_init (&info->resume_semaphore, 0);

	/*set TLS early so SMR works */
	mono_native_tls_set_value (thread_info_key, info);

	THREADS_DEBUG ("registering info %p tid %p small id %x\n", info, mono_thread_info_get_tid (info), info->small_id);

	if (threads_callbacks.thread_register) {
		if (threads_callbacks.thread_register (info, baseptr) == NULL) {
			// g_warning ("thread registation failed\n");
			mono_native_tls_set_value (thread_info_key, NULL);
			g_free (info);
			return NULL;
		}
	}

	mono_thread_info_get_stack_bounds (&staddr, &stsize);
	g_assert (staddr);
	g_assert (stsize);
	info->stack_start_limit = staddr;
	info->stack_end = staddr + stsize;

	info->stackdata = g_byte_array_new ();

	mono_threads_suspend_register (info);

	/*
	Transition it before taking any locks or publishing itself to reduce the chance
	of others witnessing a detached thread.
	We can reasonably expect that until this thread gets published, no other thread will
	try to manipulate it.
	*/
	mono_threads_transition_attach (info);
	mono_thread_info_suspend_lock ();
	/*If this fail it means a given thread has been registered twice, which doesn't make sense. */
	result = mono_thread_info_insert (info);
	g_assert (result);
	mono_thread_info_suspend_unlock ();
	return info;
}
Exemplo n.º 2
0
void
mono_runtime_setup_stat_profiler (void)
{
	/*
	 * Use a real-time signal when possible. This gives us roughly a 99% signal
	 * delivery rate in all cases. On the other hand, using a regular signal
	 * tends to result in awful delivery rates when the application is heavily
	 * loaded.
	 *
	 * We avoid real-time signals on Android as they're super broken in certain
	 * API levels (too small sigset_t, nonsensical SIGRTMIN/SIGRTMAX values,
	 * etc).
	 *
	 * TODO: On Mac, we should explore using the Mach thread suspend/resume
	 * functions and doing the stack walk from the sampling thread. This would
	 * get us a 100% sampling rate. However, this may interfere with the GC's
	 * STW logic. Could perhaps be solved by taking the suspend lock.
	 */
#if defined (USE_POSIX_BACKEND) && defined (SIGRTMIN) && !defined (HOST_ANDROID)
	/* Just take the first real-time signal we can get. */
	profiler_signal = mono_threads_suspend_search_alternative_signal ();
#else
	profiler_signal = SIGPROF;
#endif

	add_signal_handler (profiler_signal, profiler_signal_handler, SA_RESTART);

	mono_counters_register ("Sampling signals sent", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &profiler_signals_sent);
	mono_counters_register ("Sampling signals received", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &profiler_signals_received);
	mono_counters_register ("Sampling signals accepted", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &profiler_signals_accepted);
	mono_counters_register ("Shutdown signals received", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &profiler_interrupt_signals_received);

	mono_os_event_init (&sampling_thread_exited, FALSE);

	mono_atomic_store_i32 (&sampling_thread_running, 1);

	MonoError error;
	MonoInternalThread *thread = mono_thread_create_internal (mono_get_root_domain (), sampling_thread_func, NULL, MONO_THREAD_CREATE_FLAGS_NONE, &error);
	mono_error_assert_ok (&error);

	sampling_thread = MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
}
Exemplo n.º 3
0
MonoOSEventWaitRet
mono_os_event_wait_multiple (MonoOSEvent **events, gsize nevents, gboolean waitall, guint32 timeout, gboolean alertable)
{
	MonoOSEventWaitRet ret;
	mono_cond_t signal_cond;
	OSEventWaitData *data;
	gboolean alerted;
	gint64 start;
	gint i;

	g_assert (mono_lazy_is_initialized (&status));

	g_assert (events);
	g_assert (nevents > 0);
	g_assert (nevents <= MONO_OS_EVENT_WAIT_MAXIMUM_OBJECTS);

	for (i = 0; i < nevents; ++i)
		g_assert (events [i]);

	if (alertable) {
		data = g_new0 (OSEventWaitData, 1);
		data->ref = 2;
		mono_os_event_init (&data->event, FALSE);

		alerted = FALSE;
		mono_thread_info_install_interrupt (signal_and_unref, data, &alerted);
		if (alerted) {
			mono_os_event_destroy (&data->event);
			g_free (data);
			return MONO_OS_EVENT_WAIT_RET_ALERTED;
		}
	}

	if (timeout != MONO_INFINITE_WAIT)
		start = mono_msec_ticks ();

	mono_os_cond_init (&signal_cond);

	mono_os_mutex_lock (&signal_mutex);

	for (i = 0; i < nevents; ++i)
		g_ptr_array_add (events [i]->conds, &signal_cond);

	if (alertable)
		g_ptr_array_add (data->event.conds, &signal_cond);

	for (;;) {
		gint count, lowest;
		gboolean signalled;

		count = 0;
		lowest = -1;

		for (i = 0; i < nevents; ++i) {
			if (mono_os_event_is_signalled (events [i])) {
				count += 1;
				if (lowest == -1)
					lowest = i;
			}
		}

		if (alertable && mono_os_event_is_signalled (&data->event))
			signalled = TRUE;
		else if (waitall)
			signalled = (count == nevents);
		else /* waitany */
			signalled = (count > 0);

		if (signalled) {
			ret = MONO_OS_EVENT_WAIT_RET_SUCCESS_0 + lowest;
			goto done;
		}

		if (timeout == MONO_INFINITE_WAIT) {
			mono_os_cond_wait (&signal_cond, &signal_mutex);
		} else {
			gint64 elapsed;
			gint res;

			elapsed = mono_msec_ticks () - start;
			if (elapsed >= timeout) {
				ret = MONO_OS_EVENT_WAIT_RET_TIMEOUT;
				goto done;
			}

			res = mono_os_cond_timedwait (&signal_cond, &signal_mutex, timeout - elapsed);
			if (res != 0) {
				ret = MONO_OS_EVENT_WAIT_RET_TIMEOUT;
				goto done;
			}
		}
	}

done:
	for (i = 0; i < nevents; ++i)
		g_ptr_array_remove (events [i]->conds, &signal_cond);

	if (alertable)
		g_ptr_array_remove (data->event.conds, &signal_cond);

	mono_os_mutex_unlock (&signal_mutex);

	mono_os_cond_destroy (&signal_cond);

	if (alertable) {
		mono_thread_info_uninstall_interrupt (&alerted);
		if (alerted) {
			if (InterlockedDecrement ((gint32*) &data->ref) == 0) {
				mono_os_event_destroy (&data->event);
				g_free (data);
			}
			return MONO_OS_EVENT_WAIT_RET_ALERTED;
		}

		mono_os_event_destroy (&data->event);
		g_free (data);
	}

	return ret;
}