X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fsgen-bridge.c;h=7ec2d4386dfb5f4934169182128e402931b4f397;hb=3fd54893bc792eee42164bfb605b418105a92f92;hp=3b0487c9243afe496a0f5d842a592cdf5e7dd459;hpb=56ad8f4e5dfb8198e4671f631a3103b1e8b83dd3;p=mono.git diff --git a/mono/metadata/sgen-bridge.c b/mono/metadata/sgen-bridge.c index 3b0487c9243..7ec2d4386df 100644 --- a/mono/metadata/sgen-bridge.c +++ b/mono/metadata/sgen-bridge.c @@ -21,12 +21,31 @@ #include "sgen/sgen-qsort.h" #include "utils/mono-logger-internals.h" +typedef enum { + BRIDGE_PROCESSOR_INVALID, + BRIDGE_PROCESSOR_OLD, + BRIDGE_PROCESSOR_NEW, + BRIDGE_PROCESSOR_TARJAN, + BRIDGE_PROCESSOR_DEFAULT = BRIDGE_PROCESSOR_TARJAN +} BridgeProcessorSelection; + +// Bridge processor type pending / in use +static BridgeProcessorSelection bridge_processor_selection = BRIDGE_PROCESSOR_DEFAULT; +// Most recently requested callbacks +static MonoGCBridgeCallbacks pending_bridge_callbacks; +// Configuration to be passed to bridge processor after init +static SgenBridgeProcessorConfig bridge_processor_config; +// Currently-in-use callbacks MonoGCBridgeCallbacks bridge_callbacks; + +// Bridge processor state static SgenBridgeProcessor bridge_processor; +// This is used for a special debug feature static SgenBridgeProcessor compare_to_bridge_processor; volatile gboolean bridge_processing_in_progress = FALSE; +// FIXME: The current usage pattern for this function is unsafe. Bridge processing could start immediately after unlock void mono_gc_wait_for_bridge_processing (void) { @@ -39,42 +58,115 @@ mono_gc_wait_for_bridge_processing (void) sgen_gc_unlock (); } - void mono_gc_register_bridge_callbacks (MonoGCBridgeCallbacks *callbacks) { if (callbacks->bridge_version != SGEN_BRIDGE_VERSION) g_error ("Invalid bridge callback version. Expected %d but got %d\n", SGEN_BRIDGE_VERSION, callbacks->bridge_version); - bridge_callbacks = *callbacks; + // Defer assigning to bridge_callbacks until we have the gc lock. + // Note: This line is unsafe if we are on a separate thread from the one the runtime was initialized on. + pending_bridge_callbacks = *callbacks; - if (!bridge_processor.reset_data) - sgen_new_bridge_init (&bridge_processor); + // If sgen has started, will assign bridge callbacks and init bridge + sgen_init_bridge (); } -static gboolean -init_bridge_processor (SgenBridgeProcessor *processor, const char *name) +static BridgeProcessorSelection +bridge_processor_name (const char *name) { if (!strcmp ("old", name)) { - memset (processor, 0, sizeof (SgenBridgeProcessor)); - sgen_old_bridge_init (processor); + return BRIDGE_PROCESSOR_OLD; } else if (!strcmp ("new", name)) { - memset (processor, 0, sizeof (SgenBridgeProcessor)); - sgen_new_bridge_init (processor); + return BRIDGE_PROCESSOR_NEW; } else if (!strcmp ("tarjan", name)) { - memset (processor, 0, sizeof (SgenBridgeProcessor)); - sgen_tarjan_bridge_init (processor); + return BRIDGE_PROCESSOR_TARJAN; } else { - return FALSE; + return BRIDGE_PROCESSOR_INVALID; + } +} + +static gboolean +bridge_processor_started () +{ + return bridge_processor.reset_data != NULL; +} + +// Initialize a single bridge processor +static void +init_bridge_processor (SgenBridgeProcessor *processor, BridgeProcessorSelection selection) +{ + memset (processor, 0, sizeof (SgenBridgeProcessor)); + + switch (selection) { + case BRIDGE_PROCESSOR_OLD: + sgen_old_bridge_init (processor); + break; + case BRIDGE_PROCESSOR_NEW: + sgen_new_bridge_init (processor); + break; + case BRIDGE_PROCESSOR_TARJAN: + sgen_tarjan_bridge_init (processor); + break; + default: + g_assert_not_reached (); + } +} + +/* + * Initializing the sgen bridge consists of setting the bridge callbacks, + * and initializing the bridge processor. Init should follow these rules: + * + * - Init happens only after sgen is initialized (because we don't + * know which bridge processor to initialize until then, and also + * to allow bridge processor init to interact with sgen if it wants) + * + * - Init happens only after mono_gc_register_bridge_callbacks is called + * + * - Init should not happen concurrently with a GC (because a GC will + * call sgen_need_bridge_processing at various times) + * + * - Initializing the bridge processor should happen only once + * + * We call sgen_init_bridge when the callbacks are set, and also when sgen + * is done initing. Actual initialization then only occurs if it is ready. + */ +void +sgen_init_bridge () +{ + if (sgen_gc_initialized ()) { + // This lock is not initialized until the GC is + sgen_gc_lock (); + + bridge_callbacks = pending_bridge_callbacks; + + // If a bridge was registered but there is no bridge processor yet + if (bridge_callbacks.cross_references && !bridge_processor_started ()) { + init_bridge_processor (&bridge_processor, bridge_processor_selection); + + if (bridge_processor.set_config) + bridge_processor.set_config (&bridge_processor_config); + + // Config is no longer needed so free its memory + free (bridge_processor_config.dump_prefix); + bridge_processor_config.dump_prefix = NULL; + } + + sgen_gc_unlock (); } - return TRUE; } void sgen_set_bridge_implementation (const char *name) { - if (!init_bridge_processor (&bridge_processor, name)) - g_warning ("Invalid value for bridge implementation, valid values are: 'new' and 'old'."); + BridgeProcessorSelection selection = bridge_processor_name (name); + + if (selection == BRIDGE_PROCESSOR_INVALID) + g_warning ("Invalid value for bridge processor implementation, valid values are: 'new', 'old' and 'tarjan'."); + else if (bridge_processor_started ()) + g_warning ("Cannot set bridge processor implementation once bridge has already started"); + else + bridge_processor_selection = selection; } gboolean @@ -375,6 +467,8 @@ sgen_bridge_processing_finish (int generation) if (compare_bridge_processors ()) compare_to_bridge_processor.processing_after_callback (generation); + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_GC, "GC_BRIDGE: Complete, was running for %.2fms", mono_time_since_last_stw () / 10000.0f); + bridge_processing_in_progress = FALSE; } @@ -402,12 +496,9 @@ sgen_bridge_describe_pointer (GCObject *obj) static void set_dump_prefix (const char *prefix) { - if (!bridge_processor.set_dump_prefix) { - fprintf (stderr, "Warning: Bridge implementation does not support dumping - ignoring.\n"); - return; - } - - bridge_processor.set_dump_prefix (prefix); + if (bridge_processor_config.dump_prefix) + free (bridge_processor_config.dump_prefix); + bridge_processor_config.dump_prefix = strdup (prefix); } /* Test support code */ @@ -526,6 +617,30 @@ bridge_test_cross_reference2 (int num_sccs, MonoGCBridgeSCC **sccs, int num_xref sccs [i]->is_alive = TRUE; } +/* This bridge keeps all peers with __test > 0 */ +static void +bridge_test_positive_status (int num_sccs, MonoGCBridgeSCC **sccs, int num_xrefs, MonoGCBridgeXRef *xrefs) +{ + int i; + + if (!mono_bridge_test_field) { + mono_bridge_test_field = mono_class_get_field_from_name (mono_object_get_class (sccs[0]->objs [0]), "__test"); + g_assert (mono_bridge_test_field); + } + + /*We mark all objects in a scc with live objects as reachable by scc*/ + for (i = 0; i < num_sccs; ++i) { + int j; + for (j = 0; j < sccs [i]->num_objs; ++j) { + if (test_scc (sccs [i], j)) { + sccs [i]->is_alive = TRUE; + break; + } + } + } +} + + static void register_test_bridge_callbacks (const char *bridge_class_name) { @@ -533,29 +648,57 @@ register_test_bridge_callbacks (const char *bridge_class_name) callbacks.bridge_version = SGEN_BRIDGE_VERSION; callbacks.bridge_class_kind = bridge_test_bridge_class_kind; callbacks.is_bridge_object = bridge_test_is_bridge_object; - callbacks.cross_references = bridge_class_name[0] == '2' ? bridge_test_cross_reference2 : bridge_test_cross_reference; + + switch (bridge_class_name [0]) { + case '2': + bridge_class = bridge_class_name + 1; + callbacks.cross_references = bridge_test_cross_reference2; + break; + case '3': + bridge_class = bridge_class_name + 1; + callbacks.cross_references = bridge_test_positive_status; + break; + default: + bridge_class = bridge_class_name; + callbacks.cross_references = bridge_test_cross_reference; + } mono_gc_register_bridge_callbacks (&callbacks); - bridge_class = bridge_class_name + (bridge_class_name[0] == '2' ? 1 : 0); +} + +gboolean +sgen_bridge_handle_gc_param (const char *opt) +{ + g_assert (!bridge_processor_started ()); + + if (!strcmp (opt, "bridge-require-precise-merge")) { + bridge_processor_config.scc_precise_merge = TRUE; + } else { + return FALSE; + } + + return TRUE; } gboolean sgen_bridge_handle_gc_debug (const char *opt) { + g_assert (!bridge_processor_started ()); + if (g_str_has_prefix (opt, "bridge=")) { opt = strchr (opt, '=') + 1; register_test_bridge_callbacks (g_strdup (opt)); } else if (!strcmp (opt, "enable-bridge-accounting")) { - bridge_processor.enable_accounting (); + bridge_processor_config.accounting = TRUE; } else if (g_str_has_prefix (opt, "bridge-dump=")) { char *prefix = strchr (opt, '=') + 1; - set_dump_prefix (prefix); + set_dump_prefix(prefix); } else if (g_str_has_prefix (opt, "bridge-compare-to=")) { const char *name = strchr (opt, '=') + 1; - if (init_bridge_processor (&compare_to_bridge_processor, name)) { - if (compare_to_bridge_processor.reset_data == bridge_processor.reset_data) { - g_warning ("Cannot compare bridge implementation to itself - ignoring."); - memset (&compare_to_bridge_processor, 0, sizeof (SgenBridgeProcessor)); - } + BridgeProcessorSelection selection = bridge_processor_name (name); + + if (selection != BRIDGE_PROCESSOR_INVALID) { + // Compare processor doesn't get config + init_bridge_processor (&compare_to_bridge_processor, selection); } else { g_warning ("Invalid bridge implementation to compare against - ignoring."); }