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