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 ();
}
}
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 ();
}
}
--- /dev/null
+
+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