This prevents possible STW deadlocks.
/* pointer to a previously allocated heap */
/* object. */
+// Keep somewhat in sync with mono/metadata/profiler.h:enum MonoGCEvent
typedef enum {
GC_EVENT_START,
GC_EVENT_MARK_START,
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:
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_profiler_gc_event (e, 0);
+
+ switch (e) {
+ case MONO_GC_EVENT_PRE_STOP_WORLD:
+ mono_thread_info_suspend_lock ();
+ mono_profiler_gc_event (MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED, 0);
+ break;
+ case MONO_GC_EVENT_POST_START_WORLD:
+ mono_thread_info_suspend_unlock ();
+ mono_profiler_gc_event (MONO_GC_EVENT_POST_START_WORLD_UNLOCKED, 0);
+ break;
+ default:
+ break;
+ }
}
+
static void
on_gc_heap_resize (size_t new_size)
MONO_PROFILE_FAILED
} MonoProfileResult;
+// Keep somewhat in sync with libgc/include/gc.h:enum GC_EventType
typedef enum {
MONO_GC_EVENT_START,
MONO_GC_EVENT_MARK_START,
MONO_GC_EVENT_RECLAIM_START,
MONO_GC_EVENT_RECLAIM_END,
MONO_GC_EVENT_END,
+ /*
+ * This is the actual arrival order of the following events:
+ *
+ * MONO_GC_EVENT_PRE_STOP_WORLD
+ * MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED
+ * MONO_GC_EVENT_POST_STOP_WORLD
+ * MONO_GC_EVENT_PRE_START_WORLD
+ * MONO_GC_EVENT_POST_START_WORLD_UNLOCKED
+ * MONO_GC_EVENT_POST_START_WORLD
+ *
+ * The LOCKED and UNLOCKED events guarantee that, by the time they arrive,
+ * the GC and suspend locks will both have been acquired and released,
+ * respectively.
+ */
MONO_GC_EVENT_PRE_STOP_WORLD,
MONO_GC_EVENT_POST_STOP_WORLD,
MONO_GC_EVENT_PRE_START_WORLD,
- MONO_GC_EVENT_POST_START_WORLD
+ MONO_GC_EVENT_POST_START_WORLD,
+ MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED,
+ MONO_GC_EVENT_POST_START_WORLD_UNLOCKED
} MonoGCEvent;
/* coverage info */
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 ();
*/
release_gc_locks ();
+ mono_profiler_gc_event (MONO_GC_EVENT_POST_START_WORLD_UNLOCKED, generation);
+
*stw_time = usec;
}
case MONO_GC_EVENT_RECLAIM_END: return "reclaim end";
case MONO_GC_EVENT_END: return "end";
case MONO_GC_EVENT_PRE_STOP_WORLD: return "pre stop";
+ case MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED: return "pre stop lock";
case MONO_GC_EVENT_POST_STOP_WORLD: return "post stop";
case MONO_GC_EVENT_PRE_START_WORLD: return "pre start";
case MONO_GC_EVENT_POST_START_WORLD: return "post start";
+ case MONO_GC_EVENT_POST_START_WORLD_UNLOCKED: return "post start unlock";
default:
return "unknown";
}
if (generation == mono_gc_max_generation ())
gc_count++;
break;
- case MONO_GC_EVENT_PRE_STOP_WORLD:
+ case MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED:
/*
* Ensure that no thread can be in the middle of writing to
* a buffer when the world stops...
case MONO_GC_EVENT_PRE_START_WORLD:
heap_walk (profiler);
break;
- case MONO_GC_EVENT_POST_START_WORLD:
+ case MONO_GC_EVENT_POST_START_WORLD_UNLOCKED:
/*
* Similarly, we must now make sure that any object moves
* written to the GC thread's buffer are flushed. Otherwise,
#define LOG_HEADER_ID 0x4D505A01
#define LOG_VERSION_MAJOR 0
#define LOG_VERSION_MINOR 4
-#define LOG_DATA_VERSION 12
+#define LOG_DATA_VERSION 13
/*
* Changes in data versions:
* version 2: added offsets in heap walk
added TYPE_GC_HANDLE_{CREATED,DESTROYED}_BT
TYPE_JIT events are no longer guaranteed to have code start/size info (can be zero)
* version 12: added MONO_COUNTER_PROFILER
+ * version 13: added MONO_GC_EVENT_{PRE_STOP_WORLD_LOCKED,POST_START_WORLD_UNLOCKED}
*/
enum {