summaryrefslogtreecommitdiff
path: root/rts/Weak.c
diff options
context:
space:
mode:
authorSimon Marlow <marlowsd@gmail.com>2008-12-10 15:04:25 +0000
committerSimon Marlow <marlowsd@gmail.com>2008-12-10 15:04:25 +0000
commit6c095bfa3c8c81b52ad92853acd326453d320d7b (patch)
tree3f7658288a4f7f0744bb4959ca5a6113cf02babd /rts/Weak.c
parentd4a17c3a253d02c2ebf2315e71a29cb740278977 (diff)
downloadhaskell-6c095bfa3c8c81b52ad92853acd326453d320d7b.tar.gz
FIX #1364: added support for C finalizers that run as soon as the value is not longer reachable.
Patch originally by Ivan Tomac <tomac@pacific.net.au>, amended by Simon Marlow: - mkWeakFinalizer# commoned up with mkWeakFinalizerEnv# - GC parameters to ALLOC_PRIM fixed
Diffstat (limited to 'rts/Weak.c')
-rw-r--r--rts/Weak.c39
1 files changed, 39 insertions, 0 deletions
diff --git a/rts/Weak.c b/rts/Weak.c
index e97ff57e9a..a50a72e59c 100644
--- a/rts/Weak.c
+++ b/rts/Weak.c
@@ -17,8 +17,38 @@
#include "RtsAPI.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(StgVoid *fn, StgVoid *ptr, StgVoid *env, StgWord flag)
+{
+ if (flag)
+ ((void (*)(void *, void *))fn)(env, ptr);
+ else
+ ((void (*)(void *))fn)(ptr);
+}
+
+void
+runAllCFinalizers(StgWeak *list)
+{
+ StgWeak *w;
+
+ for (w = list; w; w = w->link) {
+ StgArrWords *farr;
+
+ farr = (StgArrWords *)UNTAG_CLOSURE(w->cfinalizer);
+
+ if ((StgClosure *)farr != &stg_NO_FINALIZER_closure)
+ runCFinalizer((StgVoid *)farr->payload[0],
+ (StgVoid *)farr->payload[1],
+ (StgVoid *)farr->payload[2],
+ farr->payload[3]);
+ }
+}
+
/*
* scheduleFinalizers() is called on the list of weak pointers found
* to be dead after a garbage collection. It overwrites each object
@@ -45,6 +75,7 @@ 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.
@@ -54,6 +85,14 @@ scheduleFinalizers(Capability *cap, StgWeak *list)
n++;
}
+ farr = (StgArrWords *)UNTAG_CLOSURE(w->cfinalizer);
+
+ if ((StgClosure *)farr != &stg_NO_FINALIZER_closure)
+ runCFinalizer((StgVoid *)farr->payload[0],
+ (StgVoid *)farr->payload[1],
+ (StgVoid *)farr->payload[2],
+ farr->payload[3]);
+
#ifdef PROFILING
// A weak pointer is inherently used, so we do not need to call
// LDV_recordDead().