[threads] Assert that every thread is detached when exiting (#3620)
authorLudovic Henry <ludovic@xamarin.com>
Thu, 29 Sep 2016 06:49:35 +0000 (08:49 +0200)
committerGitHub <noreply@github.com>
Thu, 29 Sep 2016 06:49:35 +0000 (08:49 +0200)
mono/metadata/threads.c
mono/tests/Makefile.am
mono/tests/thread-native-exit.cs [new file with mode: 0644]

index 7a2379628800309be9e35819f64e5e1fedf07a40..61c69e0ba92819f02eb87b6e18e6021cecbc63fd 100644 (file)
@@ -2929,34 +2929,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 ();
        }
 }
 
@@ -2992,15 +2972,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 ();
        }
 }
 
index 36e5c9a5ef011089ec301d63461b37cf7fa6b52a..de70fe0b446e5c46d283e401eb4d1f264fd844bf 100644 (file)
@@ -468,7 +468,8 @@ BASE_TEST_CS_SRC_UNIVERSAL=         \
        bug-29585.cs    \
        priority.cs     \
        abort-cctor.cs  \
-       namedmutex-destroy-race.cs
+       namedmutex-destroy-race.cs      \
+       thread-native-exit.cs
 
 if INSTALL_MOBILE_STATIC
 BASE_TEST_CS_SRC= \
diff --git a/mono/tests/thread-native-exit.cs b/mono/tests/thread-native-exit.cs
new file mode 100644 (file)
index 0000000..16af9f6
--- /dev/null
@@ -0,0 +1,76 @@
+
+using System;
+using System.Runtime.InteropServices;
+using System.Threading;
+
+class Driver
+{
+       [DllImport ("libc")]
+       extern static void pthread_exit (IntPtr value);
+
+       [DllImport ("kernel32")]
+       extern static void ExitThread (IntPtr value);
+
+       static Thread GetThread1 ()
+       {
+               return new Thread (() => {
+                       /* Exit bypassing completely the runtime */
+                       try {
+                               pthread_exit (IntPtr.Zero);
+                       } catch (EntryPointNotFoundException) {
+                       }
+
+                       try {
+                               ExitThread (IntPtr.Zero);
+                       } catch (EntryPointNotFoundException) {
+                       }
+               });
+       }
+
+       static Thread GetThread2 ()
+       {
+               return new Thread (() => {
+                       /* Exit without returning from the ThreadStart delegate */
+                       Thread.CurrentThread.Abort ();
+               });
+       }
+
+       static Thread GetThread3 ()
+       {
+               return new Thread (() => {
+                       /* Exit by returning from the ThreadStart delegate */
+                       return;
+               });
+       }
+
+       static Thread[] CreateThreads ()
+       {
+               return new Thread [] {
+                       GetThread1 (),
+                       GetThread2 (),
+                       GetThread3 (),
+               };
+       }
+
+       public static void Main ()
+       {
+               Thread[] threads;
+
+               {
+                       threads = CreateThreads ();
+
+                       for (int i = 0; i < threads.Length; ++i)
+                               threads [i].Start ();
+
+                       for (int i = 0; i < threads.Length; ++i)
+                               threads [i].Join ();
+               }
+
+               {
+                       threads = CreateThreads ();
+
+                       for (int i = 0; i < threads.Length; ++i)
+                               threads [i].Start ();
+               }
+       }
+}
\ No newline at end of file