[sgen] Don't wait for sweep finish when allocating major object
authorVlad Brezae <brezaevlad@gmail.com>
Wed, 6 Apr 2016 19:33:09 +0000 (22:33 +0300)
committerVlad Brezae <brezaevlad@gmail.com>
Fri, 27 May 2016 18:10:58 +0000 (21:10 +0300)
Allocating a major block needs addition to the allocated_blocks array, operation that needs sweep to be finished because sweep moves elements and changes the size when compacting the array. Do this operation in the sweep start instead, when we are not racing.

mono/sgen/sgen-marksweep.c

index 7442c632c75c8b06525f6a471ff41cde2e66a4c8..23ad02041cd306c5ccbb2b8977ab3280305c723c 100644 (file)
@@ -198,12 +198,16 @@ static size_t num_empty_blocks = 0;
        volatile gpointer *slot;                                                \
        SGEN_ASSERT (0, !sweep_in_progress (), "Can't iterate blocks while sweep is in progress."); \
        SGEN_ARRAY_LIST_FOREACH_SLOT (&allocated_blocks, slot) {        \
-               (bl) = BLOCK_UNTAG (*slot);
+               (bl) = BLOCK_UNTAG (*slot);                             \
+               if (!(bl))                                              \
+                       continue;
 #define FOREACH_BLOCK_HAS_REFERENCES_NO_LOCK(bl,hr) {                  \
        volatile gpointer *slot;                                                \
        SGEN_ASSERT (0, !sweep_in_progress (), "Can't iterate blocks while sweep is in progress."); \
        SGEN_ARRAY_LIST_FOREACH_SLOT (&allocated_blocks, slot) {        \
                (bl) = (MSBlockInfo *) (*slot);                 \
+               if (!(bl))                                              \
+                       continue;                                       \
                (hr) = BLOCK_IS_TAGGED_HAS_REFERENCES ((bl));           \
                (bl) = BLOCK_UNTAG ((bl));
 #define END_FOREACH_BLOCK_NO_LOCK      } SGEN_ARRAY_LIST_END_FOREACH_SLOT; }
@@ -549,16 +553,6 @@ ms_alloc_block (int size_index, gboolean pinned, gboolean has_references)
 
        add_free_block (free_blocks, size_index, info);
 
-       /*
-        * Adding to the allocated_blocks array is racy with the removal of nulls when
-        * sweeping. We wait for sweep to finish to avoid that.
-        *
-        * The memory barrier here and in `sweep_job_func()` are required because we need
-        * `allocated_blocks` synchronized between this and the sweep thread.
-        */
-       major_finish_sweep_checking ();
-       mono_memory_barrier ();
-
        sgen_array_list_add (&allocated_blocks, BLOCK_TAG (info), 0, FALSE);
 
        SGEN_ATOMIC_ADD_P (num_major_sections, 1);
@@ -1432,6 +1426,8 @@ 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);
@@ -1586,9 +1582,12 @@ static void
 sweep_blocks_job_func (void *thread_data_untyped, SgenThreadPoolJob *job)
 {
        volatile gpointer *slot;
+       MSBlockInfo *bl;
 
        SGEN_ARRAY_LIST_FOREACH_SLOT (&allocated_blocks, slot) {
-               sweep_block (BLOCK_UNTAG (*slot));
+               bl = BLOCK_UNTAG (*slot);
+               if (bl)
+                       sweep_block (bl);
        } SGEN_ARRAY_LIST_END_FOREACH_SLOT;
 
        mono_memory_write_barrier ();
@@ -1635,8 +1634,6 @@ sweep_job_func (void *thread_data_untyped, SgenThreadPoolJob *job)
                }
        }
 
-       sgen_array_list_remove_nulls (&allocated_blocks);
-
        /*
         * Concurrently sweep all the blocks to reduce workload during minor
         * pauses where we need certain blocks to be swept. At the start of