diff options
author | Simon Marlow <marlowsd@gmail.com> | 2012-08-20 13:52:07 +0100 |
---|---|---|
committer | Simon Marlow <marlowsd@gmail.com> | 2012-08-21 09:59:04 +0100 |
commit | cec899d9fb668d4adccf731a63902e5be49f0660 (patch) | |
tree | 35dbf86bd448bbc0479e650e1bff31ef4ea9b336 /rts | |
parent | 2fe4dbc729ba35640ee3b6ea7e196ba91521fa62 (diff) | |
download | haskell-cec899d9fb668d4adccf731a63902e5be49f0660.tar.gz |
Retain ordering of finalizers during GC (#7160)
This came up since the addition of C finalizers, since Haskell
finalizers are already stored in an explicit list. C finalizers on
the other hand get a WEAK object each, so in order to run them in the
right order we have to make sure that list stays in the correct
order. I hate adding new invariants, but this is the quickest way to
fix the bug for now. A better way to fix it would be to have a single
WEAK object with a list of finaliers attached to it, and a primop
for adding finalizers to the list.
Diffstat (limited to 'rts')
-rw-r--r-- | rts/sm/MarkWeak.c | 19 |
1 files changed, 14 insertions, 5 deletions
diff --git a/rts/sm/MarkWeak.c b/rts/sm/MarkWeak.c index f9275ecb62..b7d6226ee7 100644 --- a/rts/sm/MarkWeak.c +++ b/rts/sm/MarkWeak.c @@ -78,6 +78,7 @@ static WeakStage weak_stage; /* Weak pointers */ StgWeak *old_weak_ptr_list; // also pending finaliser list +StgWeak *weak_ptr_list_tail; // List of threads found to be unreachable StgTSO *resurrected_threads; @@ -90,6 +91,7 @@ initWeakForGC(void) { old_weak_ptr_list = weak_ptr_list; weak_ptr_list = NULL; + weak_ptr_list_tail = NULL; weak_stage = WeakPtrs; resurrected_threads = END_TSO_QUEUE; } @@ -139,11 +141,18 @@ traverseWeakPtrList(void) evacuate(&w->finalizer); // remove this weak ptr from the old_weak_ptr list *last_w = w->link; - // and put it on the new weak ptr list - next_w = w->link; - w->link = weak_ptr_list; - weak_ptr_list = w; - flag = rtsTrue; + next_w = w->link; + + // and put it on the new weak ptr list. + // NB. we must retain the order of the weak_ptr_list (#7160) + if (weak_ptr_list == NULL) { + weak_ptr_list = w; + } else { + weak_ptr_list_tail->link = w; + } + weak_ptr_list_tail = w; + w->link = NULL; + flag = rtsTrue; debugTrace(DEBUG_weak, "weak pointer still alive at %p -> %p", |