Merge pull request #3070 from kumpera/runtime-handles
[mono.git] / mono / utils / mono-threads.c
index f38a1afdbdd02ce3a3cc1eb479cec79d2b5a4e03..a92d250b290448698ece831e6809b4c99a8f3cdd 100644 (file)
@@ -28,6 +28,7 @@
 #include <mono/utils/mono-lazy-init.h>
 #include <mono/utils/mono-coop-mutex.h>
 #include <mono/utils/mono-coop-semaphore.h>
+#include <mono/utils/mono-threads-coop.h>
 
 #include <errno.h>
 
@@ -46,8 +47,15 @@ harder for an operation that is hardly performance critical.
 The GC has to acquire this lock before starting a STW to make sure
 a runtime suspend won't make it wronly see a thread in a safepoint
 when it is in fact not.
+
+This has to be a naked locking primitive, and not a coop aware one, as
+it needs to be usable when destroying thread_info_key, the TLS key for
+the current MonoThreadInfo. In this case, mono_thread_info_current_unchecked,
+(which is used inside MONO_ENTER_GC_SAFE), would return NULL, leading
+to an assertion error. We then simply switch state manually in
+mono_thread_info_suspend_lock_with_info.
 */
-static MonoCoopSem global_suspend_semaphore;
+static MonoSemType global_suspend_semaphore;
 
 static size_t thread_info_size;
 static MonoThreadInfoCallbacks threads_callbacks;
@@ -378,13 +386,25 @@ register_thread (MonoThreadInfo *info, gpointer baseptr)
        return info;
 }
 
+static void
+mono_thread_info_suspend_lock_with_info (MonoThreadInfo *info);
+
 static void
 unregister_thread (void *arg)
 {
-       MonoThreadInfo *info = (MonoThreadInfo *) arg;
-       int small_id = info->small_id;
+       gpointer gc_unsafe_stackdata;
+       MonoThreadInfo *info;
+       int small_id;
+
+       info = (MonoThreadInfo *) arg;
        g_assert (info);
 
+       small_id = info->small_id;
+
+       /* We only enter the GC unsafe region, as when exiting this function, the thread
+        * will be detached, and the current MonoThreadInfo* will be destroyed. */
+       mono_threads_enter_gc_unsafe_region_unbalanced_with_info (info, &gc_unsafe_stackdata);
+
        THREADS_DEBUG ("unregistering info %p\n", info);
 
        mono_native_tls_set_value (thread_exited_key, GUINT_TO_POINTER (1));
@@ -407,7 +427,7 @@ unregister_thread (void *arg)
        if (threads_callbacks.thread_detach)
                threads_callbacks.thread_detach (info);
 
-       mono_thread_info_suspend_lock ();
+       mono_thread_info_suspend_lock_with_info (info);
 
        /*
        Now perform the callback that must be done under locks.
@@ -636,7 +656,7 @@ mono_threads_init (MonoThreadInfoCallbacks *callbacks, size_t info_size)
 
        unified_suspend_enabled = g_getenv ("MONO_ENABLE_UNIFIED_SUSPEND") != NULL || mono_threads_is_coop_enabled ();
 
-       mono_coop_sem_init (&global_suspend_semaphore, 1);
+       mono_os_sem_init (&global_suspend_semaphore, 1);
        mono_os_sem_init (&suspend_semaphore, 0);
 
        mono_lls_init (&thread_list, NULL, HAZARD_FREE_NO_LOCK);
@@ -985,17 +1005,30 @@ The suspend lock is held during any suspend in progress.
 A GC that has safepoints must take this lock as part of its
 STW to make sure no unsafe pending suspend is in progress.   
 */
+
+static void
+mono_thread_info_suspend_lock_with_info (MonoThreadInfo *info)
+{
+       g_assert (info);
+
+       MONO_ENTER_GC_SAFE_WITH_INFO(info);
+
+       int res = mono_os_sem_wait (&global_suspend_semaphore, MONO_SEM_FLAGS_NONE);
+       g_assert (res != -1);
+
+       MONO_EXIT_GC_SAFE_WITH_INFO;
+}
+
 void
 mono_thread_info_suspend_lock (void)
 {
-       int res = mono_coop_sem_wait (&global_suspend_semaphore, MONO_SEM_FLAGS_NONE);
-       g_assert (res != -1);
+       mono_thread_info_suspend_lock_with_info (mono_thread_info_current_unchecked ());
 }
 
 void
 mono_thread_info_suspend_unlock (void)
 {
-       mono_coop_sem_post (&global_suspend_semaphore);
+       mono_os_sem_post (&global_suspend_semaphore);
 }
 
 /*
@@ -1193,7 +1226,7 @@ mono_thread_info_sleep (guint32 ms, gboolean *alerted)
        if (alerted)
                return sleep_interruptable (ms, alerted);
 
-       MONO_PREPARE_BLOCKING;
+       MONO_ENTER_GC_SAFE;
 
        if (ms == INFINITE) {
                do {
@@ -1238,7 +1271,7 @@ mono_thread_info_sleep (guint32 ms, gboolean *alerted)
 #endif /* __linux__ */
        }
 
-       MONO_FINISH_BLOCKING;
+       MONO_EXIT_GC_SAFE;
 
        return 0;
 }
@@ -1246,9 +1279,9 @@ mono_thread_info_sleep (guint32 ms, gboolean *alerted)
 gint
 mono_thread_info_usleep (guint64 us)
 {
-       MONO_PREPARE_BLOCKING;
+       MONO_ENTER_GC_SAFE;
        g_usleep (us);
-       MONO_FINISH_BLOCKING;
+       MONO_EXIT_GC_SAFE;
        return 0;
 }
 
@@ -1310,12 +1343,6 @@ mono_threads_open_thread_handle (HANDLE handle, MonoNativeThreadId tid)
        return mono_threads_core_open_thread_handle (handle, tid);
 }
 
-void
-mono_thread_info_set_name (MonoNativeThreadId tid, const char *name)
-{
-       mono_threads_core_set_name (tid, name);
-}
-
 #define INTERRUPT_STATE ((MonoThreadInfoInterruptToken*) (size_t) -1)
 
 struct _MonoThreadInfoInterruptToken {
@@ -1515,3 +1542,9 @@ mono_thread_info_describe_interrupt_token (MonoThreadInfo *info, GString *text)
        else
                g_string_append_printf (text, "waiting");
 }
+
+gboolean
+mono_thread_info_is_current (MonoThreadInfo *info)
+{
+       return mono_thread_info_get_tid (info) == mono_native_thread_id_get ();
+}