[sgen] Use thread safe addition to block list
authorVlad Brezae <brezaevlad@gmail.com>
Mon, 16 May 2016 19:24:45 +0000 (22:24 +0300)
committerVlad Brezae <brezaevlad@gmail.com>
Thu, 19 Jan 2017 18:05:08 +0000 (20:05 +0200)
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
mono/sgen/sgen-array-list.h
mono/sgen/sgen-marksweep.c

index 09ac01dfd5e8ee88f365d618b551d1b9a84c5be4..4150e4b824e6aad234bb88b1a74a84a33cdd4a13 100644 (file)
@@ -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
index 5b9291693363250e7ab4916b887d6849d5397b65..c505833ae01c727e5b3a8e2dce5b77d1db71148b 100644 (file)
@@ -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
index 8ae553c23b3d90687ef6ac7720a4e0d68127b155..6373792522d49fefdb4aacd776e30928958590d7 100644 (file)
@@ -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;