Merge pull request #3663 from lateralusX/jlorenss/win-api-family-support-libgcmonosgen
[mono.git] / mono / metadata / threads.c
index c80cb5344ef20869ed500055f722684fc82a36e2..3921c7e352205fb6d5e6ec98707f916181118e57 100644 (file)
@@ -46,6 +46,7 @@
 #include <mono/utils/mono-error-internals.h>
 #include <mono/utils/w32handle.h>
 #include <mono/metadata/w32event.h>
+#include <mono/metadata/w32mutex.h>
 
 #include <mono/metadata/gc-internals.h>
 #include <mono/metadata/reflection-internals.h>
 #include <signal.h>
 #endif
 
+#if defined(HOST_WIN32)
+#include <objbase.h>
+#endif
+
 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
 #define USE_TKILL_ON_ANDROID 1
 #endif
@@ -874,20 +879,10 @@ static guint32 WINAPI start_wrapper_internal(StartInfo *start_info, gsize *stack
         * for the current thead */
        mono_thread_cleanup_apartment_state ();
 
-       thread_cleanup (internal);
+       mono_thread_detach_internal (internal);
 
        internal->tid = 0;
 
-       /* Remove the reference to the thread object in the TLS data,
-        * so the thread object can be finalized.  This won't be
-        * reached if the thread threw an uncaught exception, so those
-        * thread handles will stay referenced :-( (This is due to
-        * missing support for scanning thread-specific data in the
-        * Boehm GC - the io-layer keeps a GC-visible hash of pointers
-        * to TLS data.)
-        */
-       SET_CURRENT_OBJECT (NULL);
-
        return(0);
 }
 
@@ -1075,7 +1070,7 @@ mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
        MonoNativeThreadId tid;
        gsize stack_ptr;
 
-       if ((internal = mono_thread_internal_current ())) {
+       if (mono_thread_internal_current_is_attached ()) {
                if (domain != mono_domain_get ())
                        mono_domain_set (domain, TRUE);
                /* Already attached */
@@ -1127,6 +1122,10 @@ mono_thread_detach_internal (MonoInternalThread *thread)
 
        THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
 
+#ifndef HOST_WIN32
+       mono_w32mutex_abandon ();
+#endif
+
        thread_cleanup (thread);
 
        SET_CURRENT_OBJECT (NULL);
@@ -1168,6 +1167,18 @@ mono_thread_detach_if_exiting (void)
        return FALSE;
 }
 
+gboolean
+mono_thread_internal_current_is_attached (void)
+{
+       MonoInternalThread *internal;
+
+       internal = GET_CURRENT_OBJECT ();
+       if (!internal)
+               return FALSE;
+
+       return TRUE;
+}
+
 void
 mono_thread_exit (void)
 {
@@ -1175,13 +1186,12 @@ mono_thread_exit (void)
 
        THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
 
-       thread_cleanup (thread);
-       SET_CURRENT_OBJECT (NULL);
-       mono_domain_unset ();
+       mono_thread_detach_internal (thread);
 
        /* we could add a callback here for embedders to use. */
        if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
                exit (mono_environment_exitcode_get ());
+
        mono_thread_info_exit ();
 }
 
@@ -2839,9 +2849,6 @@ void mono_thread_init (MonoThreadStartCB start_cb,
         * anything up.
         */
        GetCurrentProcess ();
-
-       /* Check that the managed and unmanaged layout of MonoInternalThread matches */
-       g_assert (MONO_STRUCT_OFFSET (MonoInternalThread, last) == mono_field_get_offset (mono_class_get_field_from_name (mono_defaults.internal_thread_class, "last")));
 }
 
 void mono_thread_cleanup (void)
@@ -2926,34 +2933,14 @@ wait_for_tids (struct wait_data *wait, guint32 timeout)
                return;
 
        for(i=0; i<wait->num; i++) {
-               gsize tid = wait->threads[i]->tid;
+               MonoInternalThread *internal;
 
-               /*
-                * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
-                * it can still run io-layer etc. code. So wait for it to really exit.
-                * FIXME: This won't join threads which are not in the joinable_hash yet.
-                */
-               mono_thread_join ((gpointer)tid);
+               internal = wait->threads [i];
 
                mono_threads_lock ();
-               if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
-                       /* This thread must have been killed, because
-                        * it hasn't cleaned itself up. (It's just
-                        * possible that the thread exited before the
-                        * parent thread had a chance to store the
-                        * handle, and now there is another pointer to
-                        * the already-exited thread stored.  In this
-                        * case, we'll just get two
-                        * mono_profiler_thread_end() calls for the
-                        * same thread.)
-                        */
-       
-                       mono_threads_unlock ();
-                       THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
-                       thread_cleanup (wait->threads[i]);
-               } else {
-                       mono_threads_unlock ();
-               }
+               if (mono_g_hash_table_lookup (threads, (gpointer) internal->tid) == internal)
+                       g_error ("%s: failed to call mono_thread_detach_internal on thread %p, InternalThread: %p", __func__, internal->tid, internal);
+               mono_threads_unlock ();
        }
 }
 
@@ -2989,15 +2976,14 @@ static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeo
                return;
        
        if (ret < wait->num) {
-               gsize tid = wait->threads[ret]->tid;
+               MonoInternalThread *internal;
+
+               internal = wait->threads [ret];
+
                mono_threads_lock ();
-               if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
-                       /* See comment in wait_for_tids about thread cleanup */
-                       mono_threads_unlock ();
-                       THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
-                       thread_cleanup (wait->threads [ret]);
-               } else
-                       mono_threads_unlock ();
+               if (mono_g_hash_table_lookup (threads, (gpointer) internal->tid) == internal)
+                       g_error ("%s: failed to call mono_thread_detach_internal on thread %p, InternalThread: %p", __func__, internal->tid, internal);
+               mono_threads_unlock ();
        }
 }
 
@@ -3125,8 +3111,8 @@ mono_threads_set_shutting_down (void)
                        UNLOCK_THREAD (current_thread);
                }
 
-               /*since we're killing the thread, unset the current domain.*/
-               mono_domain_unset ();
+               /*since we're killing the thread, detach it.*/
+               mono_thread_detach_internal (current_thread);
 
                /* Wake up other threads potentially waiting for us */
                mono_thread_info_exit ();
@@ -3386,7 +3372,7 @@ get_thread_dump (MonoThreadInfo *info, gpointer ud)
 #if 0
 /* This no longer works with remote unwinding */
        g_string_append_printf (text, " tid=0x%p this=0x%p ", (gpointer)(gsize)thread->tid, thread);
-       mono_thread_info_describe (info, text);
+       mono_thread_internal_describe (thread, text);
        g_string_append (text, "\n");
 #endif
 
@@ -5159,4 +5145,31 @@ mono_threads_is_ready_to_be_interrupted (void)
 
        UNLOCK_THREAD (thread);
        return TRUE;
-}
\ No newline at end of file
+}
+
+void
+mono_thread_internal_describe (MonoInternalThread *internal, GString *text)
+{
+       g_string_append_printf (text, ", thread handle : %p", internal->handle);
+
+       if (internal->thread_info) {
+               g_string_append (text, ", state : ");
+               mono_thread_info_describe_interrupt_token ((MonoThreadInfo*) internal->thread_info, text);
+       }
+
+       if (internal->owned_mutexes) {
+               int i;
+
+               g_string_append (text, ", owns : [");
+               for (i = 0; i < internal->owned_mutexes->len; i++)
+                       g_string_append_printf (text, i == 0 ? "%p" : ", %p", g_ptr_array_index (internal->owned_mutexes, i));
+               g_string_append (text, "]");
+       }
+}
+
+gboolean
+mono_thread_internal_is_current (MonoInternalThread *internal)
+{
+       g_assert (internal);
+       return mono_native_thread_id_equals (mono_native_thread_id_get (), MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid));
+}