#include <mono/utils/mono-threads-coop.h>
#include <mono/utils/mono-threads-debug.h>
#include <mono/utils/os-event.h>
+#include <mono/utils/w32api.h>
#include <errno.h>
static MonoThreadInfoRuntimeCallbacks runtime_callbacks;
static MonoNativeTlsKey thread_info_key, thread_exited_key;
#ifdef HAVE_KW_THREAD
-static __thread guint32 tls_small_id MONO_TLS_FAST;
+static __thread guint32 tls_small_id;
#else
static MonoNativeTlsKey small_id_key;
#endif
static MonoSemType suspend_semaphore;
static size_t pending_suspends;
+static mono_mutex_t join_mutex;
+
#define mono_thread_info_run_state(info) (((MonoThreadInfo*)info)->thread_state & THREAD_STATE_MASK)
/*warn at 50 ms*/
g_assert (mono_thread_info_is_current (info));
g_assert (mono_thread_info_is_live (info));
+ /* Pump the HP queue while the thread is alive.*/
+ mono_thread_hazardous_try_free_some ();
+
small_id = info->small_id;
/* We only enter the GC unsafe region, as when exiting this function, the thread
/*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);
mono_os_sem_init (&global_suspend_semaphore, 1);
mono_os_sem_init (&suspend_semaphore, 0);
+ mono_os_mutex_init (&join_mutex);
mono_lls_init (&thread_list, NULL);
mono_thread_smr_init ();
mono_threads_suspend_init ();
- mono_threads_suspend_init_signals ();
mono_threads_coop_init ();
+ mono_threads_platform_init ();
#if defined(__MACH__)
mono_mach_init (thread_info_key);
g_assert (sizeof (MonoNativeThreadId) <= sizeof (uintptr_t));
}
+void
+mono_threads_signals_init (void)
+{
+ mono_threads_suspend_init_signals ();
+}
+
void
mono_threads_runtime_init (MonoThreadInfoRuntimeCallbacks *callbacks)
{
gpointer stack_start;
MonoThreadUnwindState *state;
+ if (mono_threads_platform_in_critical_region (mono_thread_info_get_tid (info)))
+ return TRUE;
+
/* Are we inside a system critical region? */
if (info->inside_critical_region)
return TRUE;
}
break;
case AsyncSuspendBlocking:
- if (interrupt_kernel && mono_threads_suspend_needs_abort_syscall ())
+ if (interrupt_kernel)
mono_threads_suspend_abort_syscall (info);
break;
void
mono_thread_info_setup_async_call (MonoThreadInfo *info, void (*target_func)(void*), void *user_data)
{
- /* An async call can only be setup on an async suspended thread */
- g_assert (mono_thread_info_run_state (info) == STATE_ASYNC_SUSPENDED);
+ if (!mono_threads_is_coop_enabled ()) {
+ /* In non-coop mode, an async call can only be setup on an async suspended thread, but in coop mode, a thread
+ * may be in blocking state, and will execute the async call when leaving the safepoint, leaving a gc safe
+ * region or entering a gc unsafe region */
+ g_assert (mono_thread_info_run_state (info) == STATE_ASYNC_SUSPENDED);
+ }
/*FIXME this is a bad assert, we probably should do proper locking and fail if one is already set*/
g_assert (!info->async_target);
info->async_target = target_func;
MonoThreadHazardPointers *hp;
MonoThreadInfo *info;
- if (tid == mono_native_thread_id_get () || !mono_threads_suspend_needs_abort_syscall ())
+ if (tid == mono_native_thread_id_get ())
return;
hp = mono_hazard_pointer_get ();
{
return mono_threads_platform_yield ();
}
+
static mono_lazy_init_t sleep_init = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED;
static MonoCoopMutex sleep_mutex;
static MonoCoopCond sleep_cond;
{
MonoOSEventWaitRet res;
- res = mono_os_event_wait_one (&thread_handle->event, timeout);
+ res = mono_os_event_wait_one (&thread_handle->event, timeout, alertable);
if (res == MONO_OS_EVENT_WAIT_RET_SUCCESS_0)
return MONO_THREAD_INFO_WAIT_RET_SUCCESS_0;
else if (res == MONO_OS_EVENT_WAIT_RET_ALERTED)
if (background_change_event)
thread_events [nhandles ++] = background_change_event;
- res = mono_os_event_wait_multiple (thread_events, nhandles, waitall, timeout);
+ res = mono_os_event_wait_multiple (thread_events, nhandles, waitall, timeout, alertable);
if (res >= MONO_OS_EVENT_WAIT_RET_SUCCESS_0 && res <= MONO_OS_EVENT_WAIT_RET_SUCCESS_0 + nhandles - 1)
return MONO_THREAD_INFO_WAIT_RET_SUCCESS_0 + (res - MONO_OS_EVENT_WAIT_RET_SUCCESS_0);
else if (res == MONO_OS_EVENT_WAIT_RET_ALERTED)
else
g_error ("%s: unknown res value %d", __func__, res);
}
+
+/*
+ * mono_threads_join_mutex:
+ *
+ * This mutex is used to avoid races between pthread_create () and pthread_join () on osx, see
+ * https://bugzilla.xamarin.com/show_bug.cgi?id=50529
+ * The code inside the lock should not block.
+ */
+void
+mono_threads_join_lock (void)
+{
+#ifdef TARGET_OSX
+ mono_os_mutex_lock (&join_mutex);
+#endif
+}
+
+void
+mono_threads_join_unlock (void)
+{
+#ifdef TARGET_OSX
+ mono_os_mutex_unlock (&join_mutex);
+#endif
+}