It moves enqueuing back to the main gc giving more flexibility.
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)
{
*/
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);
}
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;
}
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;
void
sgen_workers_stop_all_workers (void)
{
- preclean_job = NULL;
+ finish_callback = NULL;
mono_memory_write_barrier ();
forced_stop = TRUE;
}
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 ();
}
}
+SgenObjectOperations*
+sgen_workers_get_idle_func_object_ops (void)
+{
+ return idle_func_object_ops;
+}
+
#endif
#include "mono/sgen/sgen-thread-pool.h"
+
+typedef void (*SgenWorkersFinishCallback) (void);
+
typedef struct _WorkerData WorkerData;
struct _WorkerData {
gint32 state;
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);
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