[threads] Make OSEvent alertable to fix bug #51653 (#4347)
[mono.git] / mono / utils / mono-threads.c
index 3ee65dcfa870158754b8464cc98611f0802be98b..b0e98d43f287c05c329affdc0c9e2376e6eedd35 100644 (file)
@@ -31,8 +31,7 @@
 #include <mono/utils/mono-threads-coop.h>
 #include <mono/utils/mono-threads-debug.h>
 #include <mono/utils/os-event.h>
-
-#include <mono/io-layer/io-layer.h>
+#include <mono/utils/w32api.h>
 
 #include <errno.h>
 
@@ -66,7 +65,7 @@ static MonoThreadInfoCallbacks threads_callbacks;
 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
@@ -76,6 +75,8 @@ static gboolean mono_threads_inited = FALSE;
 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*/
@@ -426,6 +427,9 @@ unregister_thread (void *arg)
        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
@@ -481,8 +485,6 @@ unregister_thread (void *arg)
 
        /*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);
 
@@ -706,6 +708,7 @@ mono_threads_init (MonoThreadInfoCallbacks *callbacks, size_t info_size)
 
        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 ();
@@ -1231,6 +1234,7 @@ mono_thread_info_yield (void)
 {
        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;
@@ -1651,7 +1655,7 @@ mono_thread_info_wait_one_handle (MonoThreadHandle *thread_handle, guint32 timeo
 {
        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)
@@ -1679,7 +1683,7 @@ mono_thread_info_wait_multiple_handle (MonoThreadHandle **thread_handles, gsize
        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)
@@ -1689,3 +1693,26 @@ mono_thread_info_wait_multiple_handle (MonoThreadHandle **thread_handles, gsize
        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
+}