static void* worker (void *arg) { thread_data_t *thread_data = (thread_data_t *)arg; MonoThreadHazardPointers *hp; int skip = thread_data->skip; int i, j; gboolean result; mono_thread_info_register_small_id (); hp = mono_hazard_pointer_get (); i = 0; for (j = 0; j < NUM_ITERS; ++j) { switch (nodes [i].state) { case STATE_BUSY: mono_thread_hazardous_try_free_some (); break; case STATE_OUT: if (InterlockedCompareExchange (&nodes [i].state, STATE_BUSY, STATE_OUT) == STATE_OUT) { result = mono_lls_find (&lls, hp, i, HAZARD_FREE_SAFE_CTX); assert (!result); mono_hazard_pointer_clear_all (hp, -1); result = mono_lls_insert (&lls, hp, &nodes [i].node, HAZARD_FREE_SAFE_CTX); mono_hazard_pointer_clear_all (hp, -1); assert (nodes [i].state == STATE_BUSY); nodes [i].state = STATE_IN; ++thread_data->num_adds; } break; case STATE_IN: if (InterlockedCompareExchange (&nodes [i].state, STATE_BUSY, STATE_IN) == STATE_IN) { result = mono_lls_find (&lls, hp, i, HAZARD_FREE_SAFE_CTX); assert (result); assert (mono_hazard_pointer_get_val (hp, 1) == &nodes [i].node); mono_hazard_pointer_clear_all (hp, -1); result = mono_lls_remove (&lls, hp, &nodes [i].node, HAZARD_FREE_SAFE_CTX); mono_hazard_pointer_clear_all (hp, -1); ++thread_data->num_removes; } break; default: assert (FALSE); } i += skip; if (i >= N) i -= N; } return NULL; }
/* LOCKING: assumes the GC lock is held */ int sgen_restart_world (int generation, GGTimingInfo *timing) { int count; SgenThreadInfo *info; TV_DECLARE (end_sw); TV_DECLARE (end_bridge); unsigned long usec, bridge_usec; /* notify the profiler of the leftovers */ /* FIXME this is the wrong spot at we can STW for non collection reasons. */ if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_GC_MOVES)) sgen_gc_event_moves (); mono_profiler_gc_event (MONO_GC_EVENT_PRE_START_WORLD, generation); MONO_GC_WORLD_RESTART_BEGIN (generation); FOREACH_THREAD (info) { info->stack_start = NULL; #ifdef USE_MONO_CTX memset (&info->ctx, 0, sizeof (MonoContext)); #else memset (&info->regs, 0, sizeof (info->regs)); #endif } END_FOREACH_THREAD release_gc_locks (); count = sgen_thread_handshake (FALSE); TV_GETTIME (end_sw); usec = TV_ELAPSED (stop_world_time, end_sw); max_pause_usec = MAX (usec, max_pause_usec); SGEN_LOG (2, "restarted %d thread(s) (pause time: %d usec, max: %d)", count, (int)usec, (int)max_pause_usec); mono_profiler_gc_event (MONO_GC_EVENT_POST_START_WORLD, generation); MONO_GC_WORLD_RESTART_END (generation); mono_thread_hazardous_try_free_some (); sgen_bridge_processing_finish (generation); TV_GETTIME (end_bridge); bridge_usec = TV_ELAPSED (end_sw, end_bridge); if (timing) { timing [0].stw_time = usec; timing [0].bridge_time = bridge_usec; } sgen_memgov_collection_end (generation, timing, timing ? 2 : 0); return count; }
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); }