if (num_workers < 1)
num_workers = 1;
}
- sgen_workers_init (num_workers);
+ sgen_workers_init (num_workers, (SgenWorkerCallback) major_collector.worker_init_cb);
}
sgen_memgov_init (max_heap, soft_limit, debug_print_allowance, allowance_ratio, save_target);
guint8* (*get_cardtable_mod_union_for_reference) (char *object);
long long (*get_and_reset_num_major_objects_marked) (void);
void (*count_cards) (long long *num_total_cards, long long *num_marked_cards);
+
+ void (*worker_init_cb) (gpointer worker);
};
extern SgenMajorCollector major_collector;
* thread only ever adds blocks to the free list, so the ABA problem can't occur.
*/
static MSBlockInfo * volatile *free_block_lists [MS_BLOCK_TYPE_MAX];
+static MonoNativeTlsKey worker_block_free_list_key;
static guint64 stat_major_blocks_alloced = 0;
static guint64 stat_major_blocks_freed = 0;
static volatile size_t num_major_sections_before_sweep;
static volatile size_t num_major_sections_freed_in_sweep;
+static void
+sgen_worker_clear_free_block_lists (WorkerData *worker)
+{
+ int i, j;
+
+ if (!worker->free_block_lists)
+ return;
+
+ for (i = 0; i < MS_BLOCK_TYPE_MAX; i++) {
+ for (j = 0; j < num_block_obj_sizes; j++) {
+ ((MSBlockInfo***) worker->free_block_lists) [i][j] = NULL;
+ }
+ }
+}
+
static void
sweep_start (void)
{
for (j = 0; j < num_block_obj_sizes; ++j)
free_blocks [j] = NULL;
}
+
+ sgen_workers_foreach (sgen_worker_clear_free_block_lists);
}
static void sweep_finish (void);
collector->needs_thread_pool = concurrent_mark || concurrent_sweep;
}
+/* We are guaranteed to be called by the worker in question */
+static void
+sgen_worker_init_callback (gpointer worker_untyped)
+{
+ int i;
+ WorkerData *worker = (WorkerData*) worker_untyped;
+ MSBlockInfo ***worker_free_blocks = (MSBlockInfo ***) sgen_alloc_internal_dynamic (sizeof (MSBlockInfo**) * MS_BLOCK_TYPE_MAX, INTERNAL_MEM_MS_TABLES, TRUE);
+
+ for (i = 0; i < MS_BLOCK_TYPE_MAX; i++)
+ worker_free_blocks [i] = (MSBlockInfo **) sgen_alloc_internal_dynamic (sizeof (MSBlockInfo*) * num_block_obj_sizes, INTERNAL_MEM_MS_TABLES, TRUE);
+
+ worker->free_block_lists = worker_free_blocks;
+
+ mono_native_tls_set_value (worker_block_free_list_key, worker_free_blocks);
+}
+
static void
sgen_marksweep_init_internal (SgenMajorCollector *collector, gboolean is_concurrent, gboolean is_parallel)
{
/* FIXME use parallel obj ops */
collector->major_ops_conc_par_finish = collector->major_ops_concurrent_finish;
+
+ collector->worker_init_cb = sgen_worker_init_callback;
+
+ mono_native_tls_alloc (&worker_block_free_list_key, NULL);
}
}
static int workers_num;
static volatile gboolean forced_stop;
static WorkerData *workers_data;
+static SgenWorkerCallback worker_init_cb;
/*
* When using multiple workers, we need to have the last worker
return;
init_private_gray_queue (data);
+
+ if (worker_init_cb)
+ worker_init_cb (data);
}
static gboolean
}
void
-sgen_workers_init (int num_workers)
+sgen_workers_init (int num_workers, SgenWorkerCallback callback)
{
int i;
void **workers_data_ptrs = (void **)alloca(num_workers * sizeof(void *));
for (i = 0; i < num_workers; ++i)
workers_data_ptrs [i] = (void *) &workers_data [i];
+ worker_init_cb = callback;
+
sgen_thread_pool_init (num_workers, thread_pool_init_func, marker_idle_func, continue_idle_func, workers_data_ptrs);
mono_counters_register ("# workers finished", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_workers_num_finished);
return (workers_num > 1) ? workers_num * 4 : 1;
}
+void
+sgen_workers_foreach (SgenWorkerCallback callback)
+{
+ int i;
+
+ for (i = 0; i < workers_num; i++)
+ callback (&workers_data [i]);
+}
+
#endif
#include "mono/sgen/sgen-thread-pool.h"
-
-typedef void (*SgenWorkersFinishCallback) (void);
-
typedef struct _WorkerData WorkerData;
struct _WorkerData {
gint32 state;
SgenGrayQueue private_gray_queue; /* only read/written by worker thread */
+ /*
+ * Workers allocate major objects only from here. It has same structure as the
+ * global one. This is normally accessed from the worker_block_free_list_key.
+ * We hold it here so we can clear free lists from all threads before sweep
+ * starts.
+ */
+ gpointer free_block_lists;
};
-void sgen_workers_init (int num_workers);
+typedef void (*SgenWorkersFinishCallback) (void);
+typedef void (*SgenWorkerCallback) (WorkerData *data);
+
+void sgen_workers_init (int num_workers, SgenWorkerCallback callback);
void sgen_workers_stop_all_workers (void);
void sgen_workers_start_all_workers (SgenObjectOperations *object_ops, SgenWorkersFinishCallback finish_job);
void sgen_workers_init_distribute_gray_queue (void);
void sgen_workers_take_from_queue_and_awake (SgenGrayQueue *queue);
SgenObjectOperations* sgen_workers_get_idle_func_object_ops (void);
int sgen_workers_get_job_split_count (void);
+void sgen_workers_foreach (SgenWorkerCallback callback);
#endif