[sgen] Enqueue preclean through a worker finish callback
authorVlad Brezae <brezaevlad@gmail.com>
Tue, 31 May 2016 20:55:41 +0000 (23:55 +0300)
committerVlad Brezae <brezaevlad@gmail.com>
Thu, 19 Jan 2017 22:45:08 +0000 (00:45 +0200)
It moves enqueuing back to the main gc giving more flexibility.

mono/sgen/sgen-gc.c
mono/sgen/sgen-workers.c
mono/sgen/sgen-workers.h

index a58213f6c9ac8bbc56cdcac57af3588a59f48f70..0f98b228f881f17dbb933ae2a8850d3da3110eca 100644 (file)
@@ -1417,6 +1417,18 @@ job_mod_union_preclean (void *worker_data_untyped, SgenThreadPoolJob *job)
        sgen_scan_pin_queue_objects (ctx);
 }
 
+static void
+workers_finish_callback (void)
+{
+       ScanJob *sj;
+       /* Mod union preclean job */
+       sj = (ScanJob*)sgen_thread_pool_job_alloc ("preclean mod union cardtable", job_mod_union_preclean, sizeof (ScanJob));
+       sj->ops = sgen_workers_get_idle_func_object_ops ();
+       sj->gc_thread_gray_queue = NULL;
+
+       sgen_workers_enqueue_job (&sj->job, TRUE);
+}
+
 static void
 init_gray_queue (SgenGrayQueue *gc_thread_gray_queue, gboolean use_workers)
 {
@@ -1852,12 +1864,7 @@ major_copy_or_mark_from_roots (SgenGrayQueue *gc_thread_gray_queue, size_t *old_
         */
        if (mode == COPY_OR_MARK_FROM_ROOTS_START_CONCURRENT) {
                if (precleaning_enabled) {
-                       ScanJob *sj;
-                       /* Mod union preclean job */
-                       sj = (ScanJob*)sgen_thread_pool_job_alloc ("preclean mod union cardtable", job_mod_union_preclean, sizeof (ScanJob));
-                       sj->ops = object_ops;
-                       sj->gc_thread_gray_queue = NULL;
-                       sgen_workers_start_all_workers (object_ops, &sj->job);
+                       sgen_workers_start_all_workers (object_ops, workers_finish_callback);
                } else {
                        sgen_workers_start_all_workers (object_ops, NULL);
                }
index f884d79a1d60a45f1ad4455086f162108a0ca838..49f5ccf3548cb0a9f677dc266cb8b4563bbe3265 100644 (file)
@@ -59,7 +59,11 @@ enum {
 typedef gint32 State;
 
 static SgenObjectOperations * volatile idle_func_object_ops;
-static SgenThreadPoolJob * volatile preclean_job;
+/*
+ * finished_callback is called only when the workers finish work normally (when they
+ * are not forced to finish). The callback is used to enqueue preclean jobs.
+ */
+static volatile SgenWorkersFinishCallback finish_callback;
 
 static guint64 stat_workers_num_finished;
 
@@ -126,12 +130,13 @@ worker_try_finish (WorkerData *data)
        }
 
        if (working == 1) {
-               SgenThreadPoolJob *job = preclean_job;
+               SgenWorkersFinishCallback callback = finish_callback;
                /* We are the last one left. Enqueue preclean job if we have one and awake everybody */
                SGEN_ASSERT (0, data->state != STATE_NOT_WORKING, "How did we get from doing idle work to NOT WORKING without setting it ourselves?");
-               if (job) {
-                       preclean_job = NULL;
-                       sgen_thread_pool_job_enqueue (job);
+               if (callback) {
+                       finish_callback = NULL;
+                       callback ();
+                       /* Make sure each worker has a chance of seeing the enqueued jobs */
                        sgen_workers_ensure_awake ();
                        SGEN_ASSERT (0, data->state == STATE_WORK_ENQUEUED, "Why did we fail to set our own state to ENQUEUED");
                        goto work_available;
@@ -326,7 +331,7 @@ sgen_workers_init (int num_workers)
 void
 sgen_workers_stop_all_workers (void)
 {
-       preclean_job = NULL;
+       finish_callback = NULL;
        mono_memory_write_barrier ();
        forced_stop = TRUE;
 
@@ -336,11 +341,11 @@ sgen_workers_stop_all_workers (void)
 }
 
 void
-sgen_workers_start_all_workers (SgenObjectOperations *object_ops, SgenThreadPoolJob *job)
+sgen_workers_start_all_workers (SgenObjectOperations *object_ops, SgenWorkersFinishCallback callback)
 {
        forced_stop = FALSE;
        idle_func_object_ops = object_ops;
-       preclean_job = job;
+       finish_callback = callback;
        mono_memory_write_barrier ();
 
        sgen_workers_ensure_awake ();
@@ -428,4 +433,10 @@ sgen_workers_take_from_queue_and_awake (SgenGrayQueue *queue)
        }
 }
 
+SgenObjectOperations*
+sgen_workers_get_idle_func_object_ops (void)
+{
+       return idle_func_object_ops;
+}
+
 #endif
index f13444691e68e4e331035685b6834740393b0b85..cae2da501233942c1811e778df83b4b8c5593ad5 100644 (file)
@@ -12,6 +12,9 @@
 
 #include "mono/sgen/sgen-thread-pool.h"
 
+
+typedef void (*SgenWorkersFinishCallback) (void);
+
 typedef struct _WorkerData WorkerData;
 struct _WorkerData {
        gint32 state;
@@ -20,7 +23,7 @@ struct _WorkerData {
 
 void sgen_workers_init (int num_workers);
 void sgen_workers_stop_all_workers (void);
-void sgen_workers_start_all_workers (SgenObjectOperations *object_ops, SgenThreadPoolJob *finish_job);
+void sgen_workers_start_all_workers (SgenObjectOperations *object_ops, SgenWorkersFinishCallback finish_job);
 void sgen_workers_init_distribute_gray_queue (void);
 void sgen_workers_enqueue_job (SgenThreadPoolJob *job, gboolean enqueue);
 void sgen_workers_wait_for_jobs_finished (void);
@@ -32,5 +35,6 @@ gboolean sgen_workers_all_done (void);
 gboolean sgen_workers_are_working (void);
 void sgen_workers_assert_gray_queue_is_empty (void);
 void sgen_workers_take_from_queue_and_awake (SgenGrayQueue *queue);
+SgenObjectOperations* sgen_workers_get_idle_func_object_ops (void);
 
 #endif