Merge pull request #5504 from ntherning/wait-for-native-thread-to-die-in-Thread-Join
[mono.git] / mono / metadata / threads.c
index 364316037ca17b9f85557d670013def2a30ed2dc..3eb6b3b623c8994cf3b2442b79a4270c2eebcc0b 100644 (file)
@@ -45,6 +45,7 @@
 #include <mono/utils/mono-error-internals.h>
 #include <mono/utils/os-event.h>
 #include <mono/utils/mono-threads-debug.h>
+#include <mono/utils/unlocked.h>
 #include <mono/metadata/w32handle.h>
 #include <mono/metadata/w32event.h>
 #include <mono/metadata/w32mutex.h>
@@ -152,7 +153,7 @@ static MonoGHashTable *threads_starting_up = NULL;
 /* Contains tids */
 /* Protected by the threads lock */
 static GHashTable *joinable_threads;
-static int joinable_thread_count;
+static gint32 joinable_thread_count;
 
 #define SET_CURRENT_OBJECT(x) mono_tls_set_thread (x)
 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_tls_get_thread ()
@@ -1840,6 +1841,8 @@ ves_icall_System_Threading_Thread_Join_internal (MonoThread *this_obj, int ms)
        if (ret == MONO_THREAD_INFO_WAIT_RET_SUCCESS_0) {
                THREAD_DEBUG (g_message ("%s: join successful", __func__));
 
+#ifdef HOST_WIN32
+               /* TODO: Do this on Unix platforms as well. See PR #5454 for context.  */
                /* Wait for the thread to really exit */
                MONO_ENTER_GC_SAFE;
                /* This shouldn't block */
@@ -1847,6 +1850,7 @@ ves_icall_System_Threading_Thread_Join_internal (MonoThread *this_obj, int ms)
                mono_native_thread_join (tid);
                mono_threads_join_unlock ();
                MONO_EXIT_GC_SAFE;
+#endif
 
                return TRUE;
        }
@@ -3045,6 +3049,8 @@ mono_thread_callbacks_init (void)
 void
 mono_thread_cleanup (void)
 {
+       mono_threads_join_threads ();
+
 #if !defined(RUN_IN_SUBTHREAD) && !defined(HOST_WIN32)
        /* The main thread must abandon any held mutexes (particularly
         * important for named mutexes as they are shared across
@@ -5009,7 +5015,7 @@ mono_threads_add_joinable_thread (gpointer tid)
        if (!joinable_threads)
                joinable_threads = g_hash_table_new (NULL, NULL);
        g_hash_table_insert (joinable_threads, tid, tid);
-       joinable_thread_count ++;
+       UnlockedIncrement (&joinable_thread_count);
        joinable_threads_unlock ();
 
        mono_gc_finalize_notify ();
@@ -5033,7 +5039,7 @@ mono_threads_join_threads (void)
        gboolean found;
 
        /* Fastpath */
-       if (!joinable_thread_count)
+       if (!UnlockedRead (&joinable_thread_count))
                return;
 
        while (TRUE) {
@@ -5044,7 +5050,7 @@ mono_threads_join_threads (void)
                        g_hash_table_iter_next (&iter, &key, (void**)&tid);
                        thread = (pthread_t)tid;
                        g_hash_table_remove (joinable_threads, key);
-                       joinable_thread_count --;
+                       UnlockedDecrement (&joinable_thread_count);
                        found = TRUE;
                }
                joinable_threads_unlock ();
@@ -5082,7 +5088,7 @@ mono_thread_join (gpointer tid)
                joinable_threads = g_hash_table_new (NULL, NULL);
        if (g_hash_table_lookup (joinable_threads, tid)) {
                g_hash_table_remove (joinable_threads, tid);
-               joinable_thread_count --;
+               UnlockedDecrement (&joinable_thread_count);
                found = TRUE;
        }
        joinable_threads_unlock ();