From: Ludovic Henry Date: Wed, 19 Jul 2017 21:49:20 +0000 (-0400) Subject: [threads] Make mono_thread_detach_internal static (#5241) X-Git-Url: http://wien.tomnetworks.com/gitweb/?p=mono.git;a=commitdiff_plain;h=78bcf6aa14f65dd196c2256e2ce248f81fe95864 [threads] Make mono_thread_detach_internal static (#5241) --- diff --git a/mono/metadata/threads-types.h b/mono/metadata/threads-types.h index 0a1b6b7d116..cf40b5a09d1 100644 --- a/mono/metadata/threads-types.h +++ b/mono/metadata/threads-types.h @@ -245,8 +245,6 @@ void mono_threads_add_joinable_thread (gpointer tid); void mono_threads_join_threads (void); void mono_thread_join (gpointer tid); -void mono_thread_detach_internal (MonoInternalThread *thread); - void ves_icall_System_Threading_Thread_GetStackTraces (MonoArray **out_threads, MonoArray **out_stack_traces); MONO_API gpointer diff --git a/mono/metadata/threads.c b/mono/metadata/threads.c index e0a7aee8edc..21c6e53c317 100644 --- a/mono/metadata/threads.c +++ b/mono/metadata/threads.c @@ -737,6 +737,149 @@ mono_thread_attach_internal (MonoThread *thread, gboolean force_attach, gboolean return TRUE; } +static void +mono_thread_detach_internal (MonoInternalThread *thread) +{ + gboolean removed; + + g_assert (thread != NULL); + SET_CURRENT_OBJECT (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 + + if (thread->abort_state_handle) { + mono_gchandle_free (thread->abort_state_handle); + thread->abort_state_handle = 0; + } + + thread->abort_exc = NULL; + thread->current_appcontext = NULL; + + /* + * thread->synch_cs can be NULL if this was called after + * ves_icall_System_Threading_InternalThread_Thread_free_internal. + * This can happen only during shutdown. + * The shutting_down flag is not always set, so we can't assert on it. + */ + if (thread->synch_cs) + LOCK_THREAD (thread); + + thread->state |= ThreadState_Stopped; + thread->state &= ~ThreadState_Background; + + if (thread->synch_cs) + UNLOCK_THREAD (thread); + + /* + An interruption request has leaked to cleanup. Adjust the global counter. + + This can happen is the abort source thread finds the abortee (this) thread + in unmanaged code. If this thread never trips back to managed code or check + the local flag it will be left set and positively unbalance the global counter. + + Leaving the counter unbalanced will cause a performance degradation since all threads + will now keep checking their local flags all the time. + */ + mono_thread_clear_interruption_requested (thread); + + mono_threads_lock (); + + if (!threads) { + removed = FALSE; + } else if (mono_g_hash_table_lookup (threads, (gpointer)thread->tid) != thread) { + /* We have to check whether the thread object for the + * tid is still the same in the table because the + * thread might have been destroyed and the tid reused + * in the meantime, in which case the tid would be in + * the table, but with another thread object. + */ + removed = FALSE; + } else { + mono_g_hash_table_remove (threads, (gpointer)thread->tid); + removed = TRUE; + } + + mono_threads_unlock (); + + /* Don't close the handle here, wait for the object finalizer + * to do it. Otherwise, the following race condition applies: + * + * 1) Thread exits (and mono_thread_detach_internal() closes the handle) + * + * 2) Some other handle is reassigned the same slot + * + * 3) Another thread tries to join the first thread, and + * blocks waiting for the reassigned handle to be signalled + * (which might never happen). This is possible, because the + * thread calling Join() still has a reference to the first + * thread's object. + */ + + /* if the thread is not in the hash it has been removed already */ + if (!removed) { + mono_domain_unset (); + mono_memory_barrier (); + + if (mono_thread_cleanup_fn) + mono_thread_cleanup_fn (thread_get_tid (thread)); + + goto done; + } + + mono_release_type_locks (thread); + + /* Can happen when we attach the profiler helper thread in order to heapshot. */ + if (!mono_thread_info_lookup (MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid))->tools_thread) + MONO_PROFILER_RAISE (thread_stopped, (thread->tid)); + + mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1); + + /* + * This will signal async signal handlers that the thread has exited. + * The profiler callback needs this to be set, so it cannot be done earlier. + */ + mono_domain_unset (); + mono_memory_barrier (); + + if (thread == mono_thread_internal_current ()) + mono_thread_pop_appdomain_ref (); + + mono_free_static_data (thread->static_data); + thread->static_data = NULL; + ref_stack_destroy (thread->appdomain_refs); + thread->appdomain_refs = NULL; + + g_assert (thread->suspended); + mono_os_event_destroy (thread->suspended); + g_free (thread->suspended); + thread->suspended = NULL; + + if (mono_thread_cleanup_fn) + mono_thread_cleanup_fn (thread_get_tid (thread)); + + mono_memory_barrier (); + + if (mono_gc_is_moving ()) { + MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref); + thread->thread_pinning_ref = NULL; + } + +done: + SET_CURRENT_OBJECT (NULL); + mono_domain_unset (); + + mono_thread_info_unset_internal_thread_gchandle ((MonoThreadInfo*) thread->thread_info); + + /* Don't need to close the handle to this thread, even though we took a + * reference in mono_thread_attach (), because the GC will do it + * when the Thread object is finalised. + */ +} + typedef struct { gint32 ref; MonoThread *thread; @@ -1138,149 +1281,6 @@ mono_thread_attach (MonoDomain *domain) return mono_thread_attach_full (domain, FALSE); } -void -mono_thread_detach_internal (MonoInternalThread *thread) -{ - gboolean removed; - - g_assert (thread != NULL); - SET_CURRENT_OBJECT (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 - - if (thread->abort_state_handle) { - mono_gchandle_free (thread->abort_state_handle); - thread->abort_state_handle = 0; - } - - thread->abort_exc = NULL; - thread->current_appcontext = NULL; - - /* - * thread->synch_cs can be NULL if this was called after - * ves_icall_System_Threading_InternalThread_Thread_free_internal. - * This can happen only during shutdown. - * The shutting_down flag is not always set, so we can't assert on it. - */ - if (thread->synch_cs) - LOCK_THREAD (thread); - - thread->state |= ThreadState_Stopped; - thread->state &= ~ThreadState_Background; - - if (thread->synch_cs) - UNLOCK_THREAD (thread); - - /* - An interruption request has leaked to cleanup. Adjust the global counter. - - This can happen is the abort source thread finds the abortee (this) thread - in unmanaged code. If this thread never trips back to managed code or check - the local flag it will be left set and positively unbalance the global counter. - - Leaving the counter unbalanced will cause a performance degradation since all threads - will now keep checking their local flags all the time. - */ - mono_thread_clear_interruption_requested (thread); - - mono_threads_lock (); - - if (!threads) { - removed = FALSE; - } else if (mono_g_hash_table_lookup (threads, (gpointer)thread->tid) != thread) { - /* We have to check whether the thread object for the - * tid is still the same in the table because the - * thread might have been destroyed and the tid reused - * in the meantime, in which case the tid would be in - * the table, but with another thread object. - */ - removed = FALSE; - } else { - mono_g_hash_table_remove (threads, (gpointer)thread->tid); - removed = TRUE; - } - - mono_threads_unlock (); - - /* Don't close the handle here, wait for the object finalizer - * to do it. Otherwise, the following race condition applies: - * - * 1) Thread exits (and mono_thread_detach_internal() closes the handle) - * - * 2) Some other handle is reassigned the same slot - * - * 3) Another thread tries to join the first thread, and - * blocks waiting for the reassigned handle to be signalled - * (which might never happen). This is possible, because the - * thread calling Join() still has a reference to the first - * thread's object. - */ - - /* if the thread is not in the hash it has been removed already */ - if (!removed) { - mono_domain_unset (); - mono_memory_barrier (); - - if (mono_thread_cleanup_fn) - mono_thread_cleanup_fn (thread_get_tid (thread)); - - goto done; - } - - mono_release_type_locks (thread); - - /* Can happen when we attach the profiler helper thread in order to heapshot. */ - if (!mono_thread_info_lookup (MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid))->tools_thread) - MONO_PROFILER_RAISE (thread_stopped, (thread->tid)); - - mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1); - - /* - * This will signal async signal handlers that the thread has exited. - * The profiler callback needs this to be set, so it cannot be done earlier. - */ - mono_domain_unset (); - mono_memory_barrier (); - - if (thread == mono_thread_internal_current ()) - mono_thread_pop_appdomain_ref (); - - mono_free_static_data (thread->static_data); - thread->static_data = NULL; - ref_stack_destroy (thread->appdomain_refs); - thread->appdomain_refs = NULL; - - g_assert (thread->suspended); - mono_os_event_destroy (thread->suspended); - g_free (thread->suspended); - thread->suspended = NULL; - - if (mono_thread_cleanup_fn) - mono_thread_cleanup_fn (thread_get_tid (thread)); - - mono_memory_barrier (); - - if (mono_gc_is_moving ()) { - MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref); - thread->thread_pinning_ref = NULL; - } - -done: - SET_CURRENT_OBJECT (NULL); - mono_domain_unset (); - - mono_thread_info_unset_internal_thread_gchandle ((MonoThreadInfo*) thread->thread_info); - - /* Don't need to close the handle to this thread, even though we took a - * reference in mono_thread_attach (), because the GC will do it - * when the Thread object is finalised. - */ -} - /** * mono_thread_detach: */