From c313d437511a8c5ffc3e1b89a70be23b20db9c0a Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Mon, 16 May 2016 22:24:45 +0300 Subject: [PATCH] [sgen] Use thread safe addition to block list This will enable us to to parallel block allocation, which is useful when doing parallel copying. We no longer compact the array (using the default array list allocator instead) so we need to account for unallocated slots (slots with null value) in the array at any time (see FOREACH_BLOCK). --- mono/sgen/sgen-array-list.c | 32 ++++++++++++++------------------ mono/sgen/sgen-array-list.h | 4 +++- mono/sgen/sgen-marksweep.c | 16 ++++------------ 3 files changed, 21 insertions(+), 31 deletions(-) diff --git a/mono/sgen/sgen-array-list.c b/mono/sgen/sgen-array-list.c index 09ac01dfd5e..4150e4b824e 100644 --- a/mono/sgen/sgen-array-list.c +++ b/mono/sgen/sgen-array-list.c @@ -176,24 +176,6 @@ retry: return index; } -/* - * Removes all NULL pointers from the array. Not thread safe - */ -void -sgen_array_list_remove_nulls (SgenArrayList *array) -{ - guint32 start = 0; - volatile gpointer *slot; - - SGEN_ARRAY_LIST_FOREACH_SLOT (array, slot) { - if (*slot) - *sgen_array_list_get_slot (array, start++) = *slot; - } SGEN_ARRAY_LIST_END_FOREACH_SLOT; - - mono_memory_write_barrier (); - array->next_slot = start; -} - /* * Does a linear search through the pointer array to find `ptr`. Returns the index if * found, otherwise (guint32)-1. @@ -210,4 +192,18 @@ sgen_array_list_find (SgenArrayList *array, gpointer ptr) return (guint32)-1; } +gboolean +sgen_array_list_default_cas_setter (volatile gpointer *slot, gpointer ptr, int data) +{ + if (InterlockedCompareExchangePointer (slot, ptr, NULL) == NULL) + return TRUE; + return FALSE; +} + +gboolean +sgen_array_list_default_is_slot_set (volatile gpointer *slot) +{ + return *slot != NULL; +} + #endif diff --git a/mono/sgen/sgen-array-list.h b/mono/sgen/sgen-array-list.h index 5b929169336..c505833ae01 100644 --- a/mono/sgen/sgen-array-list.h +++ b/mono/sgen/sgen-array-list.h @@ -132,6 +132,8 @@ sgen_array_list_get_slot (SgenArrayList *array, guint32 index) guint32 sgen_array_list_alloc_block (SgenArrayList *array, guint32 slots_to_add); guint32 sgen_array_list_add (SgenArrayList *array, gpointer ptr, int data, gboolean increase_size_before_set); guint32 sgen_array_list_find (SgenArrayList *array, gpointer ptr); -void sgen_array_list_remove_nulls (SgenArrayList *array); +gboolean sgen_array_list_default_cas_setter (volatile gpointer *slot, gpointer ptr, int data); +gboolean sgen_array_list_default_is_slot_set (volatile gpointer *slot); + #endif diff --git a/mono/sgen/sgen-marksweep.c b/mono/sgen/sgen-marksweep.c index 8ae553c23b3..6373792522d 100644 --- a/mono/sgen/sgen-marksweep.c +++ b/mono/sgen/sgen-marksweep.c @@ -188,7 +188,7 @@ static gboolean concurrent_sweep = TRUE; #define BLOCK_TAG(bl) ((bl)->has_references ? BLOCK_TAG_HAS_REFERENCES ((bl)) : (bl)) /* all allocated blocks in the system */ -static SgenArrayList allocated_blocks = SGEN_ARRAY_LIST_INIT (NULL, NULL, NULL, INTERNAL_MEM_PIN_QUEUE); +static SgenArrayList allocated_blocks = SGEN_ARRAY_LIST_INIT (NULL, sgen_array_list_default_is_slot_set, sgen_array_list_default_cas_setter, INTERNAL_MEM_PIN_QUEUE); /* non-allocated block free-list */ static void *empty_blocks = NULL; @@ -1417,8 +1417,6 @@ sweep_start (void) for (j = 0; j < num_block_obj_sizes; ++j) free_blocks [j] = NULL; } - - sgen_array_list_remove_nulls (&allocated_blocks); } static void sweep_finish (void); @@ -1560,6 +1558,7 @@ ensure_block_is_checked_for_sweeping (guint32 block_index, gboolean wait, gboole ms_free_block (block); SGEN_ATOMIC_ADD_P (num_major_sections, -1); + SGEN_ATOMIC_ADD_P (num_major_sections_freed_in_sweep, 1); tagged_block = NULL; } @@ -1606,13 +1605,8 @@ sweep_job_func (void *thread_data_untyped, SgenThreadPoolJob *job) * cooperate with the sweep thread to finish sweeping, and they will traverse from * low to high, to avoid constantly colliding on the same blocks. */ - for (block_index = num_blocks; block_index-- > 0;) { - /* - * The block might have been freed by another thread doing some checking - * work. - */ - if (!ensure_block_is_checked_for_sweeping (block_index, TRUE, NULL)) - ++num_major_sections_freed_in_sweep; + for (block_index = allocated_blocks.next_slot; block_index-- > 0;) { + ensure_block_is_checked_for_sweeping (block_index, TRUE, NULL); } while (!try_set_sweep_state (SWEEP_STATE_COMPACTING, SWEEP_STATE_SWEEPING)) { @@ -1681,8 +1675,6 @@ major_sweep (void) sweep_start (); - SGEN_ASSERT (0, num_major_sections == allocated_blocks.next_slot, "We don't know how many blocks we have?"); - num_major_sections_before_sweep = num_major_sections; num_major_sections_freed_in_sweep = 0; -- 2.25.1