Пример #1
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

	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;
}
Пример #2
0
/* LOCKING: assumes the GC lock is held */
int
sgen_stop_world (int generation)
{
	int count, dead;

	mono_profiler_gc_event (MONO_GC_EVENT_PRE_STOP_WORLD, generation);
	MONO_GC_WORLD_STOP_BEGIN ();
	acquire_gc_locks ();

	/* We start to scan after locks are taking, this ensures we won't be interrupted. */
	sgen_process_togglerefs ();

	update_current_thread_stack (&count);

	sgen_global_stop_count++;
	SGEN_LOG (3, "stopping world n %d from %p %p", sgen_global_stop_count, mono_thread_info_current (), (gpointer)mono_native_thread_id_get ());
	TV_GETTIME (stop_world_time);
	count = sgen_thread_handshake (TRUE);
	dead = restart_threads_until_none_in_managed_allocator ();
	if (count < dead)
		g_error ("More threads have died (%d) that been initialy suspended %d", dead, count);
	count -= dead;

	SGEN_LOG (3, "world stopped %d thread(s)", count);
	mono_profiler_gc_event (MONO_GC_EVENT_POST_STOP_WORLD, generation);
	MONO_GC_WORLD_STOP_END ();

	sgen_memgov_collection_start (generation);
	sgen_bridge_reset_data ();

	return count;
}
Пример #3
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;
}
Пример #4
0
static void
on_gc_notification (GCEventType event)
{
	MonoGCEvent e = (MonoGCEvent)event;

	if (e == MONO_GC_EVENT_PRE_STOP_WORLD) 
		mono_thread_info_suspend_lock ();
	else if (e == MONO_GC_EVENT_POST_START_WORLD)
		mono_thread_info_suspend_unlock ();
	
	if (e == MONO_GC_EVENT_START) {
		if (mono_perfcounters)
			mono_perfcounters->gc_collections0++;
		mono_stats.major_gc_count ++;
		gc_start_time = mono_100ns_ticks ();
	} else if (e == MONO_GC_EVENT_END) {
		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;
		}
		mono_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);
	}
	mono_profiler_gc_event (e, 0);
}
Пример #5
0
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);
}
Пример #6
0
/* LOCKING: assumes the GC lock is held */
void
sgen_client_stop_world (int generation)
{
	TV_DECLARE (end_handshake);

	/* 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))
		mono_sgen_gc_event_moves ();

	acquire_gc_locks ();

	mono_profiler_gc_event (MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED, generation);

	/* We start to scan after locks are taking, this ensures we won't be interrupted. */
	sgen_process_togglerefs ();

	update_current_thread_stack (&generation);

	sgen_global_stop_count++;
	SGEN_LOG (3, "stopping world n %d from %p %p", sgen_global_stop_count, mono_thread_info_current (), (gpointer) (gsize) mono_native_thread_id_get ());
	TV_GETTIME (stop_world_time);

	sgen_unified_suspend_stop_world ();

	SGEN_LOG (3, "world stopped");

	TV_GETTIME (end_handshake);
	time_stop_world += TV_ELAPSED (stop_world_time, end_handshake);

	sgen_memgov_collection_start (generation);
	if (sgen_need_bridge_processing ())
		sgen_bridge_reset_data ();
}
Пример #7
0
/* LOCKING: assumes the GC lock is held */
int
sgen_stop_world (int generation)
{
	TV_DECLARE (end_handshake);
	int count, dead;

	mono_profiler_gc_event (MONO_GC_EVENT_PRE_STOP_WORLD, generation);
	MONO_GC_WORLD_STOP_BEGIN ();
	binary_protocol_world_stopping (sgen_timestamp ());
	acquire_gc_locks ();

	/* We start to scan after locks are taking, this ensures we won't be interrupted. */
	sgen_process_togglerefs ();

	update_current_thread_stack (&count);

	sgen_global_stop_count++;
	SGEN_LOG (3, "stopping world n %d from %p %p", sgen_global_stop_count, mono_thread_info_current (), (gpointer)mono_native_thread_id_get ());
	TV_GETTIME (stop_world_time);
	count = sgen_thread_handshake (TRUE);
	dead = restart_threads_until_none_in_managed_allocator ();
	if (count < dead)
		g_error ("More threads have died (%d) that been initialy suspended %d", dead, count);
	count -= dead;

	SGEN_LOG (3, "world stopped %d thread(s)", count);
	mono_profiler_gc_event (MONO_GC_EVENT_POST_STOP_WORLD, generation);
	MONO_GC_WORLD_STOP_END ();
	if (binary_protocol_is_enabled ()) {
		long long major_total, major_marked, los_total, los_marked;
		count_cards (&major_total, &major_marked, &los_total, &los_marked);
		binary_protocol_world_stopped (sgen_timestamp (), major_total, major_marked, los_total, los_marked);
	}

	TV_GETTIME (end_handshake);
	time_stop_world += TV_ELAPSED (stop_world_time, end_handshake);

	sgen_memgov_collection_start (generation);
	if (sgen_need_bridge_processing ())
		sgen_bridge_reset_data ();

	return count;
}
Пример #8
0
/* LOCKING: assumes the GC lock is held */
void
sgen_client_restart_world (int generation, gint64 *stw_time)
{
	TV_DECLARE (end_sw);
	TV_DECLARE (start_handshake);
	unsigned long 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))
		mono_sgen_gc_event_moves ();

	FOREACH_THREAD (info) {
		info->client_info.stack_start = NULL;
		memset (&info->client_info.ctx, 0, sizeof (MonoContext));
	} FOREACH_THREAD_END

	TV_GETTIME (start_handshake);

	if (mono_thread_info_unified_management_enabled ())
		sgen_unified_suspend_restart_world ();
	else
		sgen_thread_handshake (FALSE);

	TV_GETTIME (end_sw);
	time_restart_world += TV_ELAPSED (start_handshake, end_sw);
	usec = TV_ELAPSED (stop_world_time, end_sw);
	max_pause_usec = MAX (usec, max_pause_usec);
	end_of_last_stw = end_sw;

	SGEN_LOG (2, "restarted (pause time: %d usec, max: %d)", (int)usec, (int)max_pause_usec);

	/*
	 * 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 ();

	mono_profiler_gc_event (MONO_GC_EVENT_POST_START_WORLD_UNLOCKED, generation);

	*stw_time = usec;
}
Пример #9
0
static void
on_gc_notification (GCEventType event)
{
	if (event == MONO_GC_EVENT_START) {
		mono_perfcounters->gc_collections0++;
		mono_stats.major_gc_count ++;
		gc_start_time = mono_100ns_ticks ();
	} else if (event == MONO_GC_EVENT_END) {
		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;
		mono_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);
	}
	mono_profiler_gc_event ((MonoGCEvent) event, 0);
}