summaryrefslogtreecommitdiff
path: root/rts/sm
diff options
context:
space:
mode:
authorBen Gamari <ben@smart-cactus.org>2020-03-02 18:13:52 -0500
committerMarge Bot <ben+marge-bot@smart-cactus.org>2020-03-09 06:10:52 -0400
commit70d2b9956d1ecc9d40d1e2d4920983af00ea846d (patch)
treea1bda450d47a274098e779432415a18108c342f6 /rts/sm
parent067632342cf2f063b0f23c255740e2717e5e14c7 (diff)
downloadhaskell-70d2b9956d1ecc9d40d1e2d4920983af00ea846d.tar.gz
nonmoving: Fix collection of sparks
Previously sparks living in the non-moving heap would be promptly GC'd by the minor collector since pruneSparkQueue uses the BF_EVACUATED flag, which non-moving heap blocks do not have set. Fix this by implementing proper support in pruneSparkQueue for determining reachability in the non-moving heap. The story is told in Note [Spark management in the nonmoving heap].
Diffstat (limited to 'rts/sm')
-rw-r--r--rts/sm/GC.c6
-rw-r--r--rts/sm/NonMoving.c27
2 files changed, 30 insertions, 3 deletions
diff --git a/rts/sm/GC.c b/rts/sm/GC.c
index 16d8c77453..f6698f5b9e 100644
--- a/rts/sm/GC.c
+++ b/rts/sm/GC.c
@@ -470,12 +470,12 @@ GarbageCollect (uint32_t collect_gen,
#if defined(THREADED_RTS)
if (n_gc_threads == 1) {
for (n = 0; n < n_capabilities; n++) {
- pruneSparkQueue(capabilities[n]);
+ pruneSparkQueue(false, capabilities[n]);
}
} else {
for (n = 0; n < n_capabilities; n++) {
if (n == cap->no || idle_cap[n]) {
- pruneSparkQueue(capabilities[n]);
+ pruneSparkQueue(false, capabilities[n]);
}
}
}
@@ -1250,7 +1250,7 @@ gcWorkerThread (Capability *cap)
// non-deterministic whether a spark will be retained if it is
// only reachable via weak pointers. To fix this problem would
// require another GC barrier, which is too high a price.
- pruneSparkQueue(cap);
+ pruneSparkQueue(false, cap);
#endif
// Wait until we're told to continue
diff --git a/rts/sm/NonMoving.c b/rts/sm/NonMoving.c
index 2dd201f0f9..fe9d22b479 100644
--- a/rts/sm/NonMoving.c
+++ b/rts/sm/NonMoving.c
@@ -9,6 +9,7 @@
#include "Rts.h"
#include "RtsUtils.h"
#include "Capability.h"
+#include "Sparks.h"
#include "Printer.h"
#include "Storage.h"
// We call evacuate, which expects the thread-local gc_thread to be valid;
@@ -368,6 +369,24 @@ Mutex concurrent_coll_finished_lock;
* approximate due to concurrent collection and ultimately seems more costly
* than the problem demands.
*
+ * Note [Spark management under the nonmoving collector]
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * Every GC, both minor and major, prunes the spark queue (using
+ * Sparks.c:pruneSparkQueue) of sparks which are no longer reachable.
+ * Doing this with concurrent collection is a tad subtle since the minor
+ * collections cannot rely on the mark bitmap to accurately reflect the
+ * reachability of a spark.
+ *
+ * We use a conservative reachability approximation:
+ *
+ * - Minor collections assume that all sparks living in the non-moving heap
+ * are reachable.
+ *
+ * - Major collections prune the spark queue during the final sync. This pruning
+ * assumes that all sparks in the young generations are reachable (since the
+ * BF_EVACUATED flag won't be set on the nursery blocks) and will consequently
+ * only prune dead sparks living in the non-moving heap.
+ *
*/
memcount nonmoving_live_words = 0;
@@ -1056,6 +1075,14 @@ static void nonmovingMark_(MarkQueue *mark_queue, StgWeak **dead_weaks, StgTSO *
nonmoving_old_weak_ptr_list = NULL;
}
+ // Prune spark lists
+ // See Note [Spark management under the nonmoving collector].
+#if defined(THREADED_RTS)
+ for (uint32_t n = 0; n < n_capabilities; n++) {
+ pruneSparkQueue(true, capabilities[n]);
+ }
+#endif
+
// Everything has been marked; allow the mutators to proceed
#if defined(THREADED_RTS)
nonmoving_write_barrier_enabled = false;