+static SgenMinor
+parse_sgen_minor (const char *opt)
+{
+ if (!opt)
+ return SGEN_MINOR_DEFAULT;
+
+ if (!strcmp (opt, "simple")) {
+ return SGEN_MINOR_SIMPLE;
+ } else if (!strcmp (opt, "simple-par")) {
+ return SGEN_MINOR_SIMPLE_PARALLEL;
+ } else if (!strcmp (opt, "split")) {
+ return SGEN_MINOR_SPLIT;
+ } else {
+ sgen_env_var_error (MONO_GC_PARAMS_NAME, "Using default instead.", "Unknown minor collector `%s'.", opt);
+ return SGEN_MINOR_DEFAULT;
+ }
+}
+
+static SgenMajor
+parse_sgen_major (const char *opt)
+{
+ if (!opt)
+ return SGEN_MAJOR_DEFAULT;
+
+ if (!strcmp (opt, "marksweep")) {
+ return SGEN_MAJOR_SERIAL;
+ } else if (!strcmp (opt, "marksweep-conc")) {
+ return SGEN_MAJOR_CONCURRENT;
+ } else if (!strcmp (opt, "marksweep-conc-par")) {
+ return SGEN_MAJOR_CONCURRENT_PARALLEL;
+ } else {
+ sgen_env_var_error (MONO_GC_PARAMS_NAME, "Using default instead.", "Unknown major collector `%s'.", opt);
+ return SGEN_MAJOR_DEFAULT;
+ }
+
+}
+
+static SgenMode
+parse_sgen_mode (const char *opt)
+{
+ if (!opt)
+ return SGEN_MODE_NONE;
+
+ if (!strcmp (opt, "balanced")) {
+ return SGEN_MODE_BALANCED;
+ } else if (!strcmp (opt, "throughput")) {
+ return SGEN_MODE_THROUGHPUT;
+ } else if (!strcmp (opt, "pause") || g_str_has_prefix (opt, "pause:")) {
+ return SGEN_MODE_PAUSE;
+ } else {
+ sgen_env_var_error (MONO_GC_PARAMS_NAME, "Using default configurations.", "Unknown mode `%s'.", opt);
+ return SGEN_MODE_NONE;
+ }
+}
+
+static void
+init_sgen_minor (SgenMinor minor)
+{
+ switch (minor) {
+ case SGEN_MINOR_DEFAULT:
+ case SGEN_MINOR_SIMPLE:
+ sgen_simple_nursery_init (&sgen_minor_collector, FALSE);
+ break;
+ case SGEN_MINOR_SIMPLE_PARALLEL:
+ sgen_simple_nursery_init (&sgen_minor_collector, TRUE);
+ break;
+ case SGEN_MINOR_SPLIT:
+ sgen_split_nursery_init (&sgen_minor_collector);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static void
+init_sgen_major (SgenMajor major)
+{
+ if (major == SGEN_MAJOR_DEFAULT)
+ major = DEFAULT_MAJOR;
+
+ switch (major) {
+ case SGEN_MAJOR_SERIAL:
+ sgen_marksweep_init (&major_collector);
+ break;
+ case SGEN_MAJOR_CONCURRENT:
+ sgen_marksweep_conc_init (&major_collector);
+ break;
+ case SGEN_MAJOR_CONCURRENT_PARALLEL:
+ sgen_marksweep_conc_par_init (&major_collector);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+/*
+ * If sgen mode is set, major/minor configuration is fixed. The other gc_params
+ * are parsed and processed after major/minor initialization, so it can potentially
+ * override some knobs set by the sgen mode. We can consider locking out additional
+ * configurations when gc_modes are used.
+ */
+static void
+init_sgen_mode (SgenMode mode)
+{
+ SgenMinor minor = SGEN_MINOR_DEFAULT;
+ SgenMajor major = SGEN_MAJOR_DEFAULT;
+
+ switch (mode) {
+ case SGEN_MODE_BALANCED:
+ /*
+ * Use a dynamic parallel nursery with a major concurrent collector.
+ * This uses the default values for max pause time and nursery size.
+ */
+ minor = SGEN_MINOR_SIMPLE;
+ major = SGEN_MAJOR_CONCURRENT;
+ dynamic_nursery = TRUE;
+ break;
+ case SGEN_MODE_THROUGHPUT:
+ /*
+ * Use concurrent major to let the mutator do more work. Use a larger
+ * nursery, without pause time constraints, in order to collect more
+ * objects in parallel and avoid repetitive collection tasks (pinning,
+ * root scanning etc)
+ */
+ minor = SGEN_MINOR_SIMPLE_PARALLEL;
+ major = SGEN_MAJOR_CONCURRENT;
+ dynamic_nursery = TRUE;
+ sgen_max_pause_time = 0;
+ break;
+ case SGEN_MODE_PAUSE:
+ /*
+ * Use concurrent major and dynamic nursery with a more
+ * aggressive shrinking relative to pause times.
+ */
+ minor = SGEN_MINOR_SIMPLE_PARALLEL;
+ major = SGEN_MAJOR_CONCURRENT;
+ dynamic_nursery = TRUE;
+ sgen_max_pause_margin = SGEN_PAUSE_MODE_MAX_PAUSE_MARGIN;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ init_sgen_minor (minor);
+ init_sgen_major (major);
+}
+