/* 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 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); /* * We must release the thread info suspend lock after doing * the thread handshake. Otherwise, if the GC stops the world * and a thread is in the process of starting up, but has not * yet registered (it's not in the thread_list), it is * possible that the thread does register while the world is * stopped. When restarting the GC will then try to restart * said thread, but since it never got the suspend signal, it * cannot answer the restart signal, so a deadlock results. */ release_gc_locks (); sgen_try_free_some_memory = TRUE; 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 on_gc_notification (GCEventType event) { MonoGCEvent e = (MonoGCEvent)event; switch (e) { case MONO_GC_EVENT_PRE_STOP_WORLD: MONO_GC_WORLD_STOP_BEGIN (); mono_thread_info_suspend_lock (); break; case MONO_GC_EVENT_POST_STOP_WORLD: MONO_GC_WORLD_STOP_END (); break; case MONO_GC_EVENT_PRE_START_WORLD: MONO_GC_WORLD_RESTART_BEGIN (1); break; case MONO_GC_EVENT_POST_START_WORLD: MONO_GC_WORLD_RESTART_END (1); mono_thread_info_suspend_unlock (); break; case MONO_GC_EVENT_START: MONO_GC_BEGIN (1); #ifndef DISABLE_PERFCOUNTERS if (mono_perfcounters) mono_perfcounters->gc_collections0++; #endif gc_stats.major_gc_count ++; gc_start_time = mono_100ns_ticks (); break; case MONO_GC_EVENT_END: MONO_GC_END (1); #if defined(ENABLE_DTRACE) && defined(__sun__) /* This works around a dtrace -G problem on Solaris. Limit its actual use to when the probe is enabled. */ if (MONO_GC_END_ENABLED ()) sleep(0); #endif #ifndef DISABLE_PERFCOUNTERS if (mono_perfcounters) { guint64 heap_size = GC_get_heap_size (); guint64 used_size = heap_size - GC_get_free_bytes (); mono_perfcounters->gc_total_bytes = used_size; mono_perfcounters->gc_committed_bytes = heap_size; mono_perfcounters->gc_reserved_bytes = heap_size; mono_perfcounters->gc_gen0size = heap_size; } #endif gc_stats.major_gc_time_usecs += (mono_100ns_ticks () - gc_start_time) / 10; mono_trace_message (MONO_TRACE_GC, "gc took %d usecs", (mono_100ns_ticks () - gc_start_time) / 10); break; } mono_profiler_gc_event (e, 0); }
/* 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; }