-/*
- * sgen-stw.c: Stop the world functionality
+/**
+ * \file
+ * Stop the world functionality
*
* Author:
* Paolo Molaro (lupus@ximian.com)
#include "sgen/sgen-gc.h"
#include "sgen/sgen-protocol.h"
#include "sgen/sgen-memory-governor.h"
-#include "sgen/sgen-thread-pool.h"
+#include "sgen/sgen-workers.h"
#include "metadata/profiler-private.h"
#include "sgen/sgen-client.h"
#include "metadata/sgen-bridge-internals.h"
info->client_info.stack_start = align_pointer (&stack_guard);
g_assert (info->client_info.stack_start);
- g_assert (info->client_info.stack_start >= info->client_info.stack_start_limit && info->client_info.stack_start < info->client_info.stack_end);
+ g_assert (info->client_info.stack_start >= info->client_info.info.stack_start_limit && info->client_info.stack_start < info->client_info.info.stack_end);
#if !defined(MONO_CROSS_COMPILE) && MONO_ARCH_HAS_MONO_CONTEXT
MONO_CONTEXT_GET_CURRENT (info->client_info.ctx);
{
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 ();
+ mono_profiler_gc_event (MONO_GC_EVENT_PRE_STOP_WORLD, generation);
acquire_gc_locks ();
SGEN_LOG (3, "world stopped");
+ mono_profiler_gc_event (MONO_GC_EVENT_POST_STOP_WORLD, generation);
+
TV_GETTIME (end_handshake);
time_stop_world += TV_ELAPSED (stop_world_time, end_handshake);
if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_GC_MOVES))
mono_sgen_gc_event_moves ();
+ mono_profiler_gc_event (MONO_GC_EVENT_PRE_START_WORLD, generation);
+
FOREACH_THREAD (info) {
info->client_info.stack_start = NULL;
memset (&info->client_info.ctx, 0, sizeof (MonoContext));
SGEN_LOG (2, "restarted (pause time: %d usec, max: %d)", (int)usec, (int)max_pause_usec);
+ mono_profiler_gc_event (MONO_GC_EVENT_POST_START_WORLD, generation);
+
/*
* We must release the thread info suspend lock after doing
* the thread handshake. Otherwise, if the GC stops the world
We can't suspend the workers that will do all the heavy lifting.
FIXME Use some state bit in SgenThreadInfo for this.
*/
- if (sgen_thread_pool_is_thread_pool_thread (mono_thread_info_get_tid (info))) {
+ if (sgen_thread_pool_is_thread_pool_thread (major_collector.get_sweep_pool (), mono_thread_info_get_tid (info)) ||
+ sgen_workers_is_worker_thread (mono_thread_info_get_tid (info))) {
if (reason)
*reason = 4;
return FALSE;
static void
sgen_unified_suspend_stop_world (void)
{
- int restart_counter;
int sleep_duration = -1;
mono_threads_begin_global_suspend ();
THREADS_STW_DEBUG ("[GC-STW-BEGIN][%p] *** BEGIN SUSPEND *** \n", mono_thread_info_get_tid (mono_thread_info_current ()));
FOREACH_THREAD (info) {
- int reason;
info->client_info.skip = FALSE;
info->client_info.suspend_done = FALSE;
- if (sgen_is_thread_in_current_stw (info, &reason)) {
- info->client_info.skip = !mono_thread_info_begin_suspend (info);
- THREADS_STW_DEBUG ("[GC-STW-BEGIN-SUSPEND] SUSPEND thread %p skip %s\n", mono_thread_info_get_tid (info), info->client_info.skip ? "true" : "false");
- } else {
+
+ int reason;
+ if (!sgen_is_thread_in_current_stw (info, &reason)) {
THREADS_STW_DEBUG ("[GC-STW-BEGIN-SUSPEND] IGNORE thread %p skip %s reason %d\n", mono_thread_info_get_tid (info), info->client_info.skip ? "true" : "false", reason);
+ continue;
}
+
+ info->client_info.skip = !mono_thread_info_begin_suspend (info);
+
+ THREADS_STW_DEBUG ("[GC-STW-BEGIN-SUSPEND] SUSPEND thread %p skip %s\n", mono_thread_info_get_tid (info), info->client_info.skip ? "true" : "false");
} FOREACH_THREAD_END
mono_thread_info_current ()->client_info.suspend_done = TRUE;
mono_threads_wait_pending_operations ();
for (;;) {
- restart_counter = 0;
+ gint restart_counter = 0;
+
FOREACH_THREAD (info) {
+ gint suspend_count;
+
int reason = 0;
if (info->client_info.suspend_done || !sgen_is_thread_in_current_stw (info, &reason)) {
THREADS_STW_DEBUG ("[GC-STW-RESTART] IGNORE RESUME thread %p not been processed done %d current %d reason %d\n", mono_thread_info_get_tid (info), info->client_info.suspend_done, !sgen_is_thread_in_current_stw (info, NULL), reason);
- We haven't accepted the previous suspend as good.
- We haven't gave up on it for this STW (it's either bad or asked not to)
*/
- if (mono_thread_info_in_critical_location (info)) {
- gboolean res;
- gint suspend_count = mono_thread_info_suspend_count (info);
- if (!(suspend_count == 1))
- g_error ("[%p] suspend_count = %d, but should be 1", mono_thread_info_get_tid (info), suspend_count);
- res = mono_thread_info_begin_resume (info);
- if (res)
- ++restart_counter;
- else
- info->client_info.skip = TRUE;
- THREADS_STW_DEBUG ("[GC-STW-RESTART] RESTART thread %p skip %s\n", mono_thread_info_get_tid (info), info->client_info.skip ? "true" : "false");
- } else {
- THREADS_STW_DEBUG ("[GC-STW-RESTART] DONE thread %p deemed fully suspended\n", mono_thread_info_get_tid (info));
- g_assert (!info->client_info.in_critical_region);
+ if (!mono_thread_info_in_critical_location (info)) {
info->client_info.suspend_done = TRUE;
+
+ THREADS_STW_DEBUG ("[GC-STW-RESTART] DONE thread %p deemed fully suspended\n", mono_thread_info_get_tid (info));
+ continue;
}
+
+ suspend_count = mono_thread_info_suspend_count (info);
+ if (!(suspend_count == 1))
+ g_error ("[%p] suspend_count = %d, but should be 1", mono_thread_info_get_tid (info), suspend_count);
+
+ info->client_info.skip = !mono_thread_info_begin_resume (info);
+ if (!info->client_info.skip)
+ restart_counter += 1;
+
+ THREADS_STW_DEBUG ("[GC-STW-RESTART] RESTART thread %p skip %s\n", mono_thread_info_get_tid (info), info->client_info.skip ? "true" : "false");
} FOREACH_THREAD_END
+ mono_threads_wait_pending_operations ();
+
if (restart_counter == 0)
break;
- mono_threads_wait_pending_operations ();
if (sleep_duration < 0) {
mono_thread_info_yield ();
continue;
}
- if (mono_thread_info_is_running (info)) {
- gboolean res = mono_thread_info_begin_suspend (info);
- if (!res)
- info->client_info.skip = TRUE;
- THREADS_STW_DEBUG ("[GC-STW-RESTART] SUSPEND thread %p skip %s\n", mono_thread_info_get_tid (info), info->client_info.skip ? "true" : "false");
+ if (!mono_thread_info_is_running (info)) {
+ THREADS_STW_DEBUG ("[GC-STW-RESTART] IGNORE SUSPEND thread %p not running\n", mono_thread_info_get_tid (info));
+ continue;
}
+
+ info->client_info.skip = !mono_thread_info_begin_suspend (info);
+
+ THREADS_STW_DEBUG ("[GC-STW-RESTART] SUSPEND thread %p skip %s\n", mono_thread_info_get_tid (info), info->client_info.skip ? "true" : "false");
} FOREACH_THREAD_END
mono_threads_wait_pending_operations ();
}
FOREACH_THREAD (info) {
+ gpointer stopped_ip;
+
int reason = 0;
- if (sgen_is_thread_in_current_stw (info, &reason)) {
- gpointer stopped_ip;
+ if (!sgen_is_thread_in_current_stw (info, &reason)) {
+ g_assert (!info->client_info.suspend_done || info == mono_thread_info_current ());
- g_assert (info->client_info.suspend_done);
+ THREADS_STW_DEBUG ("[GC-STW-SUSPEND-END] thread %p is NOT suspended, reason %d\n", mono_thread_info_get_tid (info), reason);
+ continue;
+ }
- info->client_info.ctx = mono_thread_info_get_suspend_state (info)->ctx;
+ g_assert (info->client_info.suspend_done);
- /* Once we remove the old suspend code, we should move sgen to directly access the state in MonoThread */
- info->client_info.stack_start = (gpointer) ((char*)MONO_CONTEXT_GET_SP (&info->client_info.ctx) - REDZONE_SIZE);
+ info->client_info.ctx = mono_thread_info_get_suspend_state (info)->ctx;
- /* altstack signal handler, sgen can't handle them, mono-threads should have handled this. */
- if (!info->client_info.stack_start
- || info->client_info.stack_start < info->client_info.stack_start_limit
- || info->client_info.stack_start >= info->client_info.stack_end) {
- g_error ("BAD STACK: stack_start = %p, stack_start_limit = %p, stack_end = %p",
- info->client_info.stack_start, info->client_info.stack_start_limit, info->client_info.stack_end);
- }
+ /* Once we remove the old suspend code, we should move sgen to directly access the state in MonoThread */
+ info->client_info.stack_start = (gpointer) ((char*)MONO_CONTEXT_GET_SP (&info->client_info.ctx) - REDZONE_SIZE);
- stopped_ip = (gpointer) (MONO_CONTEXT_GET_IP (&info->client_info.ctx));
+ if (info->client_info.stack_start < info->client_info.info.stack_start_limit
+ || info->client_info.stack_start >= info->client_info.info.stack_end) {
+ /*
+ * Thread context is in unhandled state, most likely because it is
+ * dying. We don't scan it.
+ * FIXME We should probably rework and check the valid flag instead.
+ */
+ info->client_info.stack_start = NULL;
+ }
- THREADS_STW_DEBUG ("[GC-STW-SUSPEND-END] thread %p is suspended, stopped_ip = %p, stack = %p -> %p\n",
- mono_thread_info_get_tid (info), stopped_ip, info->client_info.stack_start, info->client_info.stack_start ? info->client_info.stack_end : NULL);
+ stopped_ip = (gpointer) (MONO_CONTEXT_GET_IP (&info->client_info.ctx));
- binary_protocol_thread_suspend ((gpointer) mono_thread_info_get_tid (info), stopped_ip);
- } else {
- THREADS_STW_DEBUG ("[GC-STW-SUSPEND-END] thread %p is NOT suspended, reason %d\n", mono_thread_info_get_tid (info), reason);
- g_assert (!info->client_info.suspend_done || info == mono_thread_info_current ());
- }
+ binary_protocol_thread_suspend ((gpointer) mono_thread_info_get_tid (info), stopped_ip);
+
+ THREADS_STW_DEBUG ("[GC-STW-SUSPEND-END] thread %p is suspended, stopped_ip = %p, stack = %p -> %p\n",
+ mono_thread_info_get_tid (info), stopped_ip, info->client_info.stack_start, info->client_info.stack_start ? info->client_info.info.stack_end : NULL);
} FOREACH_THREAD_END
}