Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mono / metadata / sgen-bridge.c
index bf0c523399918da0ad7e6012ff2cc7992a29cd83..9d7809a211a4a550269488fa7dc2b18be7bb0e33 100644 (file)
@@ -1,5 +1,6 @@
-/*
- * sgen-bridge.c: Simple generational GC.
+/**
+ * \file
+ * Simple generational GC.
  *
  * Copyright 2011 Novell, Inc (http://www.novell.com)
  * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
@@ -20,7 +21,6 @@
 #include "sgen/sgen-hash-table.h"
 #include "sgen/sgen-qsort.h"
 #include "utils/mono-logger-internals.h"
-#include "utils/mono-once.h"
 
 typedef enum {
        BRIDGE_PROCESSOR_INVALID,
@@ -34,6 +34,8 @@ typedef enum {
 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;
 
@@ -44,31 +46,10 @@ static SgenBridgeProcessor compare_to_bridge_processor;
 
 volatile gboolean bridge_processing_in_progress = FALSE;
 
-// Mutex guarding pending_bridge_callbacks
-// Must use OS mutex because can be used before runtime init
-static mono_mutex_t pending_bridge_callbacks_mutex;
-
-static void
-pending_bridge_callbacks_mutex_init ()
-{
-       mono_os_mutex_init (&pending_bridge_callbacks_mutex);
-}
-
-static void
-pending_bridge_callbacks_mutex_lock ()
-{
-       static mono_once_t init_once=MONO_ONCE_INIT;
-       mono_once (&init_once, pending_bridge_callbacks_mutex_init);
-       mono_os_mutex_lock (&pending_bridge_callbacks_mutex);
-}
-
-static void
-pending_bridge_callbacks_mutex_unlock ()
-{
-       mono_os_mutex_unlock (&pending_bridge_callbacks_mutex);
-}
-
 // FIXME: The current usage pattern for this function is unsafe. Bridge processing could start immediately after unlock
+/**
+ * mono_gc_wait_for_bridge_processing:
+ */
 void
 mono_gc_wait_for_bridge_processing (void)
 {
@@ -81,7 +62,9 @@ mono_gc_wait_for_bridge_processing (void)
        sgen_gc_unlock ();
 }
 
-// This function is currently called only once, but it can be called at any time, including before or during sgen initialization.
+/**
+ * mono_gc_register_bridge_callbacks:
+ */
 void
 mono_gc_register_bridge_callbacks (MonoGCBridgeCallbacks *callbacks)
 {
@@ -89,9 +72,8 @@ mono_gc_register_bridge_callbacks (MonoGCBridgeCallbacks *callbacks)
                g_error ("Invalid bridge callback version. Expected %d but got %d\n", SGEN_BRIDGE_VERSION, callbacks->bridge_version);
 
        // Defer assigning to bridge_callbacks until we have the gc lock.
-       pending_bridge_callbacks_mutex_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;
-       pending_bridge_callbacks_mutex_unlock ();
 
        // If sgen has started, will assign bridge callbacks and init bridge
        sgen_init_bridge ();
@@ -111,6 +93,12 @@ bridge_processor_name (const char *name)
        }
 }
 
+static gboolean
+bridge_processor_started (void)
+{
+       return bridge_processor.reset_data != NULL;
+}
+
 // Initialize a single bridge processor
 static void
 init_bridge_processor (SgenBridgeProcessor *processor, BridgeProcessorSelection selection)
@@ -151,20 +139,26 @@ init_bridge_processor (SgenBridgeProcessor *processor, BridgeProcessorSelection
  * is done initing. Actual initialization then only occurs if it is ready.
  */
 void
-sgen_init_bridge ()
+sgen_init_bridge (void)
 {
        if (sgen_gc_initialized ()) {
                // This lock is not initialized until the GC is
                sgen_gc_lock ();
 
-               pending_bridge_callbacks_mutex_lock ();
                bridge_callbacks = pending_bridge_callbacks;
-               pending_bridge_callbacks_mutex_unlock ();
 
                // If a bridge was registered but there is no bridge processor yet
-               if (bridge_callbacks.cross_references && !bridge_processor.reset_data)
+               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 ();
        }
 }
@@ -176,7 +170,7 @@ sgen_set_bridge_implementation (const char *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.reset_data)
+       else if (bridge_processor_started ())
                g_warning ("Cannot set bridge processor implementation once bridge has already started");
        else
                bridge_processor_selection = selection;
@@ -509,12 +503,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 */
@@ -681,22 +672,39 @@ register_test_bridge_callbacks (const char *bridge_class_name)
        mono_gc_register_bridge_callbacks (&callbacks);
 }
 
+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;
                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.");