summaryrefslogtreecommitdiff
path: root/rts
diff options
context:
space:
mode:
authorSimon Marlow <marlowsd@gmail.com>2012-08-20 13:52:07 +0100
committerSimon Marlow <marlowsd@gmail.com>2012-08-21 09:59:04 +0100
commitcec899d9fb668d4adccf731a63902e5be49f0660 (patch)
tree35dbf86bd448bbc0479e650e1bff31ef4ea9b336 /rts
parent2fe4dbc729ba35640ee3b6ea7e196ba91521fa62 (diff)
downloadhaskell-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.c19
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",