Merge pull request #2810 from kumpera/fix_hazard_free
[mono.git] / mono / sgen / sgen-gc.c
index dcce323e982bb2d735db7c3d67ec4ddd57ddcfca..57e6f6931fc85ae980bee580694ee17c045b6d6f 100644 (file)
  * Copyright 2011 Xamarin, Inc.
  * Copyright (C) 2012 Xamarin Inc
  *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  *
  * Important: allocation provides always zeroed memory, having to do
  * a memset after allocation is deadly for performance.
@@ -1712,7 +1701,7 @@ major_copy_or_mark_from_roots (size_t *old_next_pin_slot, CopyOrMarkFromRootsMod
 
        sgen_client_pre_collection_checks ();
 
-       if (!concurrent) {
+       if (mode != COPY_OR_MARK_FROM_ROOTS_START_CONCURRENT) {
                /* Remsets are not useful for a major collection */
                remset.clear_cards ();
        }
@@ -1723,8 +1712,20 @@ major_copy_or_mark_from_roots (size_t *old_next_pin_slot, CopyOrMarkFromRootsMod
        sgen_init_pinning ();
        SGEN_LOG (6, "Collecting pinned addresses");
        pin_from_roots ((void*)lowest_heap_address, (void*)highest_heap_address, ctx);
-
+       if (mode == COPY_OR_MARK_FROM_ROOTS_FINISH_CONCURRENT) {
+               /* Pin cemented objects that were forced */
+               sgen_pin_cemented_objects ();
+       }
        sgen_optimize_pin_queue ();
+       if (mode == COPY_OR_MARK_FROM_ROOTS_START_CONCURRENT) {
+               /*
+                * Cemented objects that are in the pinned list will be marked. When
+                * marking concurrently we won't mark mod-union cards for these objects.
+                * Instead they will remain cemented until the next major collection,
+                * when we will recheck if they are still pinned in the roots.
+                */
+               sgen_cement_force_pinned ();
+       }
 
        sgen_client_collecting_major_1 ();
 
@@ -1782,25 +1783,12 @@ major_copy_or_mark_from_roots (size_t *old_next_pin_slot, CopyOrMarkFromRootsMod
        major_collector.init_to_space ();
 
        SGEN_ASSERT (0, sgen_workers_all_done (), "Why are the workers not done when we start or finish a major collection?");
-       /*
-        * The concurrent collector doesn't move objects, neither on
-        * the major heap nor in the nursery, so we can mark even
-        * before pinning has finished.  For the non-concurrent
-        * collector we start the workers after pinning.
-        */
-       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;
-                       sgen_workers_start_all_workers (object_ops, &sj->job);
-               } else {
-                       sgen_workers_start_all_workers (object_ops, NULL);
-               }
-               gray_queue_enable_redirect (WORKERS_DISTRIBUTE_GRAY_QUEUE);
-       } else if (mode == COPY_OR_MARK_FROM_ROOTS_FINISH_CONCURRENT) {
+       if (mode == COPY_OR_MARK_FROM_ROOTS_FINISH_CONCURRENT) {
                if (sgen_workers_have_idle_work ()) {
+                       /*
+                        * We force the finish of the worker with the new object ops context
+                        * which can also do copying. We need to have finished pinning.
+                        */
                        sgen_workers_start_all_workers (object_ops, NULL);
                        sgen_workers_join ();
                }
@@ -1817,15 +1805,29 @@ major_copy_or_mark_from_roots (size_t *old_next_pin_slot, CopyOrMarkFromRootsMod
 
        sgen_client_collecting_major_3 (&fin_ready_queue, &critical_fin_queue);
 
-       /*
-        * FIXME: is this the right context?  It doesn't seem to contain a copy function
-        * unless we're concurrent.
-        */
-       enqueue_scan_from_roots_jobs (heap_start, heap_end, object_ops, mode == COPY_OR_MARK_FROM_ROOTS_START_CONCURRENT);
+       enqueue_scan_from_roots_jobs (heap_start, heap_end, object_ops, FALSE);
 
        TV_GETTIME (btv);
        time_major_scan_roots += TV_ELAPSED (atv, btv);
 
+       /*
+        * We start the concurrent worker after pinning and after we scanned the roots
+        * in order to make sure that the worker does not finish before handling all
+        * the roots.
+        */
+       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;
+                       sgen_workers_start_all_workers (object_ops, &sj->job);
+               } else {
+                       sgen_workers_start_all_workers (object_ops, NULL);
+               }
+               gray_queue_enable_redirect (WORKERS_DISTRIBUTE_GRAY_QUEUE);
+       }
+
        if (mode == COPY_OR_MARK_FROM_ROOTS_FINISH_CONCURRENT) {
                ScanJob *sj;
 
@@ -1849,11 +1851,6 @@ static void
 major_finish_copy_or_mark (CopyOrMarkFromRootsMode mode)
 {
        if (mode == COPY_OR_MARK_FROM_ROOTS_START_CONCURRENT) {
-               /*
-                * Prepare the pin queue for the next collection.  Since pinning runs on the worker
-                * threads we must wait for the jobs to finish before we can reset it.
-                */
-               sgen_workers_wait_for_jobs_finished ();
                sgen_finish_pinning ();
 
                sgen_pin_stats_reset ();