/** * Removes the current thread from the thread list. * This must be called from the thread unregister callback and nowhere else. * The current thread must be passed as TLS might have already been cleaned up. */ static void mono_threads_unregister_current_thread (MonoThreadInfo *info) { gboolean result; g_assert (mono_thread_info_get_tid (info) == mono_native_thread_id_get ()); result = mono_thread_info_remove (info); g_assert (result); }
static void unregister_thread (void *arg) { gpointer gc_unsafe_stackdata; MonoThreadInfo *info; int small_id; gboolean result; gpointer handle; info = (MonoThreadInfo *) arg; g_assert (info); g_assert (mono_thread_info_is_current (info)); g_assert (mono_thread_info_is_live (info)); small_id = info->small_id; /* We only enter the GC unsafe region, as when exiting this function, the thread * will be detached, and the current MonoThreadInfo* will be destroyed. */ mono_threads_enter_gc_unsafe_region_unbalanced_with_info (info, &gc_unsafe_stackdata); THREADS_DEBUG ("unregistering info %p\n", info); mono_native_tls_set_value (thread_exited_key, GUINT_TO_POINTER (1)); /* * TLS destruction order is not reliable so small_id might be cleaned up * before us. */ #ifndef HAVE_KW_THREAD mono_native_tls_set_value (small_id_key, GUINT_TO_POINTER (info->small_id + 1)); #endif /* we need to duplicate it, as the info->handle is going * to be closed when unregistering from the platform */ handle = mono_threads_platform_duplicate_handle (info); /* First perform the callback that requires no locks. This callback has the potential of taking other locks, so we do it before. After it completes, the thread remains functional. */ if (threads_callbacks.thread_detach) threads_callbacks.thread_detach (info); mono_thread_info_suspend_lock_with_info (info); /* Now perform the callback that must be done under locks. This will render the thread useless and non-suspendable, so it must be done while holding the suspend lock to give no other thread chance to suspend it. */ if (threads_callbacks.thread_unregister) threads_callbacks.thread_unregister (info); mono_threads_platform_unregister (info); result = mono_thread_info_remove (info); g_assert (result); mono_threads_transition_detach (info); mono_thread_info_suspend_unlock (); g_byte_array_free (info->stackdata, /*free_segment=*/TRUE); /*now it's safe to free the thread info.*/ mono_thread_hazardous_try_free (info, free_thread_info); /* Pump the HP queue */ mono_thread_hazardous_try_free_some (); mono_thread_small_id_free (small_id); /* Signal the w32handle. It can be done as late as here * because w32handle does not access the current MonoThreadInfo, * neither does it switch state to BLOCKING. */ mono_threads_platform_set_exited (handle); mono_threads_platform_close_thread_handle (handle); }