static void mono_thread_info_suspend_lock_with_info (MonoThreadInfo *info) { g_assert (info); g_assert (mono_thread_info_is_current (info)); g_assert (mono_thread_info_is_live (info)); MONO_ENTER_GC_SAFE_WITH_INFO(info); int res = mono_os_sem_wait (&global_suspend_semaphore, MONO_SEM_FLAGS_NONE); g_assert (res != -1); MONO_EXIT_GC_SAFE_WITH_INFO; }
/* Check the current state of the thread and try to init a self suspend. This must be called with self state saved. Returns one of the following values: - Resumed: Async resume happened and current thread should keep running - Suspend: Caller should wait for a resume signal - SelfSuspendNotifyAndWait: Notify the suspend initiator and wait for a resume signals suspend should start. */ MonoSelfSupendResult mono_threads_transition_state_poll (MonoThreadInfo *info) { int raw_state, cur_state, suspend_count; g_assert (mono_thread_info_is_current (info)); retry_state_change: UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info); switch (cur_state) { case STATE_RUNNING: if (!(suspend_count == 0)) mono_fatal_with_history ("suspend_count = %d, but should be == 0", suspend_count); trace_state_change ("STATE_POLL", info, raw_state, cur_state, 0); return SelfSuspendResumed; //We're fine, don't suspend case STATE_ASYNC_SUSPEND_REQUESTED: //Async suspend requested, service it with a self suspend if (!(suspend_count > 0)) mono_fatal_with_history ("suspend_count = %d, but should be > 0", suspend_count); if (mono_atomic_cas_i32 (&info->thread_state, build_thread_state (STATE_SELF_SUSPENDED, suspend_count), raw_state) != raw_state) goto retry_state_change; trace_state_change ("STATE_POLL", info, raw_state, STATE_SELF_SUSPENDED, 0); return SelfSuspendNotifyAndWait; //Caller should notify suspend initiator and wait for resume /* STATE_ASYNC_SUSPENDED: Code should not be running while suspended. STATE_SELF_SUSPENDED: Code should not be running while suspended. STATE_BLOCKING: STATE_BLOCKING_SUSPEND_REQUESTED: STATE_BLOCKING_ASYNC_SUSPENDED: STATE_BLOCKING_SELF_SUSPENDED: Poll is a local state transition. No VM activities are allowed while in blocking mode. (In all the blocking states - the local thread has no checkpoints, hence no polling, it can only do abort blocking or done blocking on itself). */ default: mono_fatal_with_history ("Cannot transition thread %p from %s with STATE_POLL", mono_thread_info_get_tid (info), state_name (cur_state)); } }
static void unregister_thread (void *arg) { gpointer gc_unsafe_stackdata; MonoThreadInfo *info; int small_id; 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)); mono_threads_platform_unregister (info); /* * 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 /* 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_unregister_current_thread (info); 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); }
void mono_thread_info_set_exited (THREAD_INFO_TYPE *info) { g_assert (mono_thread_info_is_current (info)); mono_threads_platform_set_exited (info); }
gpointer mono_thread_info_duplicate_handle (MonoThreadInfo *info) { g_assert (mono_thread_info_is_current (info)); return mono_threads_platform_duplicate_handle (info); }