From: Vlad Brezae Date: Tue, 31 May 2016 20:55:41 +0000 (+0300) Subject: [sgen] Enqueue preclean through a worker finish callback X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=commitdiff_plain;h=5f2d0db2babca3623a67a11d2b26198281a93b65;p=mono.git [sgen] Enqueue preclean through a worker finish callback It moves enqueuing back to the main gc giving more flexibility. --- diff --git a/mono/sgen/sgen-gc.c b/mono/sgen/sgen-gc.c index a58213f6c9a..0f98b228f88 100644 --- a/mono/sgen/sgen-gc.c +++ b/mono/sgen/sgen-gc.c @@ -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); } diff --git a/mono/sgen/sgen-workers.c b/mono/sgen/sgen-workers.c index f884d79a1d6..49f5ccf3548 100644 --- a/mono/sgen/sgen-workers.c +++ b/mono/sgen/sgen-workers.c @@ -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 diff --git a/mono/sgen/sgen-workers.h b/mono/sgen/sgen-workers.h index f13444691e6..cae2da50123 100644 --- a/mono/sgen/sgen-workers.h +++ b/mono/sgen/sgen-workers.h @@ -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