diff options
author | Takano Akio <aljee@hyper.cx> | 2013-04-18 18:30:23 +0900 |
---|---|---|
committer | Ian Lynagh <ian@well-typed.com> | 2013-06-15 16:23:09 +0100 |
commit | d61c623ed6b2d352474a7497a65015dbf6a72e12 (patch) | |
tree | 13132eb4473fb8594bd72e168f918ea79a0c9da6 /rts/Weak.c | |
parent | 5d9e686c30a00be08a04d9fd1c860994153a1f7a (diff) | |
download | haskell-d61c623ed6b2d352474a7497a65015dbf6a72e12.tar.gz |
Allow multiple C finalizers to be attached to a Weak#
The commit replaces mkWeakForeignEnv# with addCFinalizerToWeak#.
This new primop mutates an existing Weak# object and adds a new
C finalizer to it.
This change removes an invariant in MarkWeak.c, namely that the relative
order of Weak# objects in the list needs to be preserved across GC. This
makes it easier to split the list into per-generation structures.
The patch also removes a race condition between two threads calling
finalizeWeak# on the same WEAK object at that same time.
Diffstat (limited to 'rts/Weak.c')
-rw-r--r-- | rts/Weak.c | 39 |
1 files changed, 13 insertions, 26 deletions
diff --git a/rts/Weak.c b/rts/Weak.c index 5546514243..e7a1257562 100644 --- a/rts/Weak.c +++ b/rts/Weak.c @@ -16,18 +16,21 @@ #include "Prelude.h" #include "Trace.h" -// ForeignPtrs with C finalizers rely on weak pointers inside weak_ptr_list -// to always be in the same order. - StgWeak *weak_ptr_list; void -runCFinalizer(void *fn, void *ptr, void *env, StgWord flag) +runCFinalizers(StgCFinalizerList *list) { - if (flag) - ((void (*)(void *, void *))fn)(env, ptr); - else - ((void (*)(void *))fn)(ptr); + StgCFinalizerList *head; + for (head = list; + (StgClosure *)head != &stg_NO_FINALIZER_closure; + head = (StgCFinalizerList *)head->link) + { + if (head->flag) + ((void (*)(void *, void *))head->fptr)(head->eptr, head->ptr); + else + ((void (*)(void *))head->fptr)(head->ptr); + } } void @@ -42,15 +45,7 @@ runAllCFinalizers(StgWeak *list) } for (w = list; w; w = w->link) { - StgArrWords *farr; - - farr = (StgArrWords *)UNTAG_CLOSURE(w->cfinalizer); - - if ((StgClosure *)farr != &stg_NO_FINALIZER_closure) - runCFinalizer((void *)farr->payload[0], - (void *)farr->payload[1], - (void *)farr->payload[2], - farr->payload[3]); + runCFinalizers((StgCFinalizerList *)w->cfinalizers); } if (task != NULL) { @@ -91,8 +86,6 @@ scheduleFinalizers(Capability *cap, StgWeak *list) // count number of finalizers, and kill all the weak pointers first... n = 0; for (w = list; w; w = w->link) { - StgArrWords *farr; - // Better not be a DEAD_WEAK at this stage; the garbage // collector removes DEAD_WEAKs from the weak pointer list. ASSERT(w->header.info != &stg_DEAD_WEAK_info); @@ -101,13 +94,7 @@ scheduleFinalizers(Capability *cap, StgWeak *list) n++; } - farr = (StgArrWords *)UNTAG_CLOSURE(w->cfinalizer); - - if ((StgClosure *)farr != &stg_NO_FINALIZER_closure) - runCFinalizer((void *)farr->payload[0], - (void *)farr->payload[1], - (void *)farr->payload[2], - farr->payload[3]); + runCFinalizers((StgCFinalizerList *)w->cfinalizers); #ifdef PROFILING // A weak pointer is inherently used, so we do not need to call |