summaryrefslogtreecommitdiff
path: root/rts/Weak.c
diff options
context:
space:
mode:
authorSimon Marlow <marlowsd@gmail.com>2015-06-01 21:34:02 +0100
committerSimon Marlow <marlowsd@gmail.com>2015-06-01 21:34:02 +0100
commitdfdc50d666498c5a1118557d67209fe067c61cc1 (patch)
tree0009f57ff2a980d636ac4730368485a0fa06711a /rts/Weak.c
parentf82e866504259c674d6fb3f66e67ae943a688b3f (diff)
downloadhaskell-dfdc50d666498c5a1118557d67209fe067c61cc1.tar.gz
Don't call DEAD_WEAK finalizer again on shutdown (#7170)
Summary: There's a race condition like this: # A foreign pointer gets promoted to the last generation # It has its finalizer called manually # We start shutting down the runtime in `hs_exit_` from the main thread # A minor GC starts running (`scheduleDoGC`) on one of the threads # The minor GC notices that we're in `SCHED_INTERRUPTING` state and advances to `SCHED_SHUTTING_DOWN` # The main thread tries to do major GC (with `scheduleDoGC`), but it exits early because we're in `SCHED_SHUTTING_DOWN` state # We end up with a `DEAD_WEAK` left on the list of weak pointers of the last generation, because it relied on major GC removing it from that list This change: * Ignores DEAD_WEAK finalizers when shutting down * Makes the major GC on shutdown more likely * Fixes a bogus assert Test Plan: before this diff https://ghc.haskell.org/trac/ghc/ticket/7170#comment:5 reproduced and after it doesn't Reviewers: ezyang, austin, simonmar Reviewed By: simonmar Subscribers: bgamari, thomie Differential Revision: https://phabricator.haskell.org/D921 GHC Trac Issues: #7170
Diffstat (limited to 'rts/Weak.c')
-rw-r--r--rts/Weak.c11
1 files changed, 10 insertions, 1 deletions
diff --git a/rts/Weak.c b/rts/Weak.c
index f8faa4e1f5..92f1bdbd02 100644
--- a/rts/Weak.c
+++ b/rts/Weak.c
@@ -43,7 +43,16 @@ runAllCFinalizers(StgWeak *list)
}
for (w = list; w; w = w->link) {
- runCFinalizers((StgCFinalizerList *)w->cfinalizers);
+ // We need to filter out DEAD_WEAK objects, because it's not guaranteed
+ // that the list will not have them when shutting down.
+ // They only get filtered out during GC for the generation they
+ // belong to.
+ // If there's no major GC between the time that the finalizer for the
+ // object from the oldest generation is manually called and shutdown
+ // we end up running the same finalizer twice. See #7170.
+ if (w->header.info != &stg_DEAD_WEAK_info) {
+ runCFinalizers((StgCFinalizerList *)w->cfinalizers);
+ }
}
if (task != NULL) {