summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--includes/rts/storage/GC.h3
-rw-r--r--includes/stg/MiscClosures.h1
-rw-r--r--rts/PrimOps.cmm4
-rw-r--r--rts/RetainerProfile.c8
-rw-r--r--rts/RtsStartup.c6
-rw-r--r--rts/Weak.c2
-rw-r--r--rts/Weak.h2
-rw-r--r--rts/sm/Compact.c10
-rw-r--r--rts/sm/GC.c2
-rw-r--r--rts/sm/MarkWeak.c229
-rw-r--r--rts/sm/Storage.c3
-rw-r--r--utils/deriveConstants/DeriveConstants.hs1
12 files changed, 161 insertions, 110 deletions
diff --git a/includes/rts/storage/GC.h b/includes/rts/storage/GC.h
index 6ddd301c41..fb5e21e832 100644
--- a/includes/rts/storage/GC.h
+++ b/includes/rts/storage/GC.h
@@ -83,6 +83,8 @@ typedef struct generation_ {
StgTSO * threads; // threads in this gen
// linked via global_link
+ StgWeak * weak_ptr_list; // weak pointers in this gen
+
struct generation_ *to; // destination gen for live objects
// stats information
@@ -116,6 +118,7 @@ typedef struct generation_ {
bdescr * bitmap; // bitmap for compacting collection
StgTSO * old_threads;
+ StgWeak * old_weak_ptr_list;
} generation;
extern generation * generations;
diff --git a/includes/stg/MiscClosures.h b/includes/stg/MiscClosures.h
index db0a32eb67..ca5280f188 100644
--- a/includes/stg/MiscClosures.h
+++ b/includes/stg/MiscClosures.h
@@ -465,7 +465,6 @@ extern StgWord stg_stack_save_entries[];
// Storage.c
extern unsigned int RTS_VAR(g0);
extern unsigned int RTS_VAR(large_alloc_lim);
-extern StgWord RTS_VAR(weak_ptr_list);
extern StgWord RTS_VAR(atomic_modify_mutvar_mutex);
// RtsFlags
diff --git a/rts/PrimOps.cmm b/rts/PrimOps.cmm
index b44dfe7f5c..c12c6d8638 100644
--- a/rts/PrimOps.cmm
+++ b/rts/PrimOps.cmm
@@ -380,8 +380,8 @@ stg_mkWeakzh ( gcptr key,
StgWeak_cfinalizers(w) = stg_NO_FINALIZER_closure;
ACQUIRE_LOCK(sm_mutex);
- StgWeak_link(w) = W_[weak_ptr_list];
- W_[weak_ptr_list] = w;
+ StgWeak_link(w) = generation_weak_ptr_list(W_[g0]);
+ generation_weak_ptr_list(W_[g0]) = w;
RELEASE_LOCK(sm_mutex);
IF_DEBUG(weak, ccall debugBelch(stg_weak_msg,w));
diff --git a/rts/RetainerProfile.c b/rts/RetainerProfile.c
index 4e7ed3e222..10a947dda8 100644
--- a/rts/RetainerProfile.c
+++ b/rts/RetainerProfile.c
@@ -1767,9 +1767,11 @@ computeRetainerSet( void )
//
// The following code assumes that WEAK objects are considered to be roots
// for retainer profilng.
- for (weak = weak_ptr_list; weak != NULL; weak = weak->link)
- // retainRoot((StgClosure *)weak);
- retainRoot(NULL, (StgClosure **)&weak);
+ for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
+ for (weak = generations[g].weak_ptr_list; weak != NULL; weak = weak->link)
+ // retainRoot((StgClosure *)weak);
+ retainRoot(NULL, (StgClosure **)&weak);
+ }
// Consider roots from the stable ptr table.
markStableTables(retainRoot, NULL);
diff --git a/rts/RtsStartup.c b/rts/RtsStartup.c
index d8c2058526..39c5ef1f94 100644
--- a/rts/RtsStartup.c
+++ b/rts/RtsStartup.c
@@ -295,6 +295,8 @@ hs_add_root(void (*init_root)(void) STG_UNUSED)
static void
hs_exit_(rtsBool wait_foreign)
{
+ nat g;
+
if (hs_init_count <= 0) {
errorBelch("warning: too many hs_exit()s");
return;
@@ -325,7 +327,9 @@ hs_exit_(rtsBool wait_foreign)
exitScheduler(wait_foreign);
/* run C finalizers for all active weak pointers */
- runAllCFinalizers(weak_ptr_list);
+ for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
+ runAllCFinalizers(generations[g].weak_ptr_list);
+ }
#if defined(RTS_USER_SIGNALS)
if (RtsFlags.MiscFlags.install_signal_handlers) {
diff --git a/rts/Weak.c b/rts/Weak.c
index e7a1257562..98ac7603b7 100644
--- a/rts/Weak.c
+++ b/rts/Weak.c
@@ -16,8 +16,6 @@
#include "Prelude.h"
#include "Trace.h"
-StgWeak *weak_ptr_list;
-
void
runCFinalizers(StgCFinalizerList *list)
{
diff --git a/rts/Weak.h b/rts/Weak.h
index 7892277b11..fbdf18a861 100644
--- a/rts/Weak.h
+++ b/rts/Weak.h
@@ -14,7 +14,7 @@
#include "BeginPrivate.h"
extern rtsBool running_finalizers;
-extern StgWeak * weak_ptr_list;
+extern StgWeak * dead_weak_ptr_list;
void runCFinalizers(StgCFinalizerList *list);
void runAllCFinalizers(StgWeak *w);
diff --git a/rts/sm/Compact.c b/rts/sm/Compact.c
index ffa355ae9c..91ad8abb5a 100644
--- a/rts/sm/Compact.c
+++ b/rts/sm/Compact.c
@@ -917,11 +917,13 @@ compact(StgClosure *static_objects)
markScheduler((evac_fn)thread_root, NULL);
// the weak pointer lists...
- if (weak_ptr_list != NULL) {
- thread((void *)&weak_ptr_list);
+ for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
+ if (generations[g].weak_ptr_list != NULL)
+ thread((void *)&generations[g].weak_ptr_list);
}
- if (old_weak_ptr_list != NULL) {
- thread((void *)&old_weak_ptr_list); // tmp
+
+ if (dead_weak_ptr_list != NULL) {
+ thread((void *)&dead_weak_ptr_list); // tmp
}
// mutable lists
diff --git a/rts/sm/GC.c b/rts/sm/GC.c
index ddb538472f..28593f5c71 100644
--- a/rts/sm/GC.c
+++ b/rts/sm/GC.c
@@ -699,7 +699,7 @@ GarbageCollect (nat collect_gen,
// Start any pending finalizers. Must be after
// updateStableTables() and stableUnlock() (see #4221).
RELEASE_SM_LOCK;
- scheduleFinalizers(cap, old_weak_ptr_list);
+ scheduleFinalizers(cap, dead_weak_ptr_list);
ACQUIRE_SM_LOCK;
// check sanity after GC
diff --git a/rts/sm/MarkWeak.c b/rts/sm/MarkWeak.c
index f8ccaad7ea..5313eecb9b 100644
--- a/rts/sm/MarkWeak.c
+++ b/rts/sm/MarkWeak.c
@@ -75,34 +75,37 @@
typedef enum { WeakPtrs, WeakThreads, WeakDone } WeakStage;
static WeakStage weak_stage;
-/* Weak pointers
- */
-StgWeak *old_weak_ptr_list; // also pending finaliser list
-StgWeak *weak_ptr_list_tail;
+// List of weak pointers whose key is dead
+StgWeak *dead_weak_ptr_list;
// List of threads found to be unreachable
StgTSO *resurrected_threads;
+static void collectDeadWeakPtrs (generation *gen);
+static rtsBool tidyWeakList (generation *gen);
static void resurrectUnreachableThreads (generation *gen);
static rtsBool tidyThreadList (generation *gen);
void
initWeakForGC(void)
{
- old_weak_ptr_list = weak_ptr_list;
- weak_ptr_list = NULL;
- weak_ptr_list_tail = NULL;
+ nat g;
+
+ for (g = 0; g <= N; g++) {
+ generation *gen = &generations[g];
+ gen->old_weak_ptr_list = gen->weak_ptr_list;
+ gen->weak_ptr_list = NULL;
+ }
+
weak_stage = WeakPtrs;
+ dead_weak_ptr_list = NULL;
resurrected_threads = END_TSO_QUEUE;
}
rtsBool
traverseWeakPtrList(void)
{
- StgWeak *w, **last_w, *next_w;
- StgClosure *new;
rtsBool flag = rtsFalse;
- const StgInfoTable *info;
switch (weak_stage) {
@@ -110,73 +113,23 @@ traverseWeakPtrList(void)
return rtsFalse;
case WeakPtrs:
- /* doesn't matter where we evacuate values/finalizers to, since
- * these pointers are treated as roots (iff the keys are alive).
- */
- gct->evac_gen_no = 0;
-
- last_w = &old_weak_ptr_list;
- for (w = old_weak_ptr_list; w != NULL; w = next_w) {
-
- /* There might be a DEAD_WEAK on the list if finalizeWeak# was
- * called on a live weak pointer object. Just remove it.
- */
- if (w->header.info == &stg_DEAD_WEAK_info) {
- next_w = w->link;
- *last_w = next_w;
- continue;
- }
-
- info = get_itbl((StgClosure *)w);
- switch (info->type) {
-
- case WEAK:
- /* Now, check whether the key is reachable.
- */
- new = isAlive(w->key);
- if (new != NULL) {
- w->key = new;
- // evacuate the value and finalizer
- evacuate(&w->value);
- evacuate(&w->finalizer);
- // remove this weak ptr from the old_weak_ptr list
- *last_w = w->link;
- next_w = w->link;
-
- // and put it on the new weak ptr list.
- 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",
- w, w->key);
- continue;
- }
- else {
- last_w = &(w->link);
- next_w = w->link;
- continue;
- }
-
- default:
- barf("traverseWeakPtrList: not WEAK");
- }
+ {
+ nat g;
+
+ for (g = 0; g <= N; g++) {
+ if (tidyWeakList(&generations[g])) {
+ flag = rtsTrue;
+ }
}
/* If we didn't make any changes, then we can go round and kill all
- * the dead weak pointers. The old_weak_ptr list is used as a list
+ * the dead weak pointers. The dead_weak_ptr list is used as a list
* of pending finalizers later on.
*/
if (flag == rtsFalse) {
- for (w = old_weak_ptr_list; w; w = w->link) {
- evacuate(&w->finalizer);
- }
+ for (g = 0; g <= N; g++) {
+ collectDeadWeakPtrs(&generations[g]);
+ }
// Next, move to the WeakThreads stage after fully
// scavenging the finalizers we've just evacuated.
@@ -184,6 +137,7 @@ traverseWeakPtrList(void)
}
return rtsTrue;
+ }
case WeakThreads:
/* Now deal with the step->threads lists, which behave somewhat like
@@ -229,6 +183,17 @@ traverseWeakPtrList(void)
}
}
+static void collectDeadWeakPtrs (generation *gen)
+{
+ StgWeak *w, *next_w;
+ for (w = gen->old_weak_ptr_list; w != NULL; w = next_w) {
+ evacuate(&w->finalizer);
+ next_w = w->link;
+ w->link = dead_weak_ptr_list;
+ dead_weak_ptr_list = w;
+ }
+}
+
static void resurrectUnreachableThreads (generation *gen)
{
StgTSO *t, *tmp, *next;
@@ -253,6 +218,80 @@ traverseWeakPtrList(void)
}
}
+static rtsBool tidyWeakList(generation *gen)
+{
+ StgWeak *w, **last_w, *next_w;
+ const StgInfoTable *info;
+ StgClosure *new;
+ rtsBool flag = rtsFalse;
+ last_w = &gen->old_weak_ptr_list;
+ for (w = gen->old_weak_ptr_list; w != NULL; w = next_w) {
+
+ /* There might be a DEAD_WEAK on the list if finalizeWeak# was
+ * called on a live weak pointer object. Just remove it.
+ */
+ if (w->header.info == &stg_DEAD_WEAK_info) {
+ next_w = w->link;
+ *last_w = next_w;
+ continue;
+ }
+
+ info = get_itbl((StgClosure *)w);
+ switch (info->type) {
+
+ case WEAK:
+ /* Now, check whether the key is reachable.
+ */
+ new = isAlive(w->key);
+ if (new != NULL) {
+ generation *new_gen;
+
+ w->key = new;
+
+ // Find out which generation this weak ptr is in, and
+ // move it onto the weak ptr list of that generation.
+
+ new_gen = Bdescr((P_)w)->gen;
+ gct->evac_gen_no = new_gen->no;
+
+ // evacuate the value and finalizer
+ evacuate(&w->value);
+ evacuate(&w->finalizer);
+ // remove this weak ptr from the old_weak_ptr list
+ *last_w = w->link;
+ next_w = w->link;
+
+ // and put it on the correct weak ptr list.
+ w->link = new_gen->weak_ptr_list;
+ new_gen->weak_ptr_list = w;
+ flag = rtsTrue;
+
+ if (gen->no != new_gen->no) {
+ debugTrace(DEBUG_weak,
+ "moving weak pointer %p from %d to %d",
+ w, gen->no, new_gen->no);
+ }
+
+
+ debugTrace(DEBUG_weak,
+ "weak pointer still alive at %p -> %p",
+ w, w->key);
+ continue;
+ }
+ else {
+ last_w = &(w->link);
+ next_w = w->link;
+ continue;
+ }
+
+ default:
+ barf("tidyWeakList: not WEAK: %d, %p", info->type, w);
+ }
+ }
+
+ return flag;
+}
+
static rtsBool tidyThreadList (generation *gen)
{
StgTSO *t, *tmp, *next, **prev;
@@ -303,38 +342,40 @@ static rtsBool tidyThreadList (generation *gen)
/* -----------------------------------------------------------------------------
Evacuate every weak pointer object on the weak_ptr_list, and update
the link fields.
-
- ToDo: with a lot of weak pointers, this will be expensive. We
- should have a per-GC weak pointer list, just like threads.
-------------------------------------------------------------------------- */
void
markWeakPtrList ( void )
{
- StgWeak *w, **last_w;
+ nat g;
+
+ for (g = 0; g <= N; g++) {
+ generation *gen = &generations[g];
+ StgWeak *w, **last_w;
- last_w = &weak_ptr_list;
- for (w = weak_ptr_list; w; w = w->link) {
- // w might be WEAK, EVACUATED, or DEAD_WEAK (actually CON_STATIC) here
+ last_w = &gen->weak_ptr_list;
+ for (w = gen->weak_ptr_list; w != NULL; w = w->link) {
+ // w might be WEAK, EVACUATED, or DEAD_WEAK (actually CON_STATIC) here
#ifdef DEBUG
- { // careful to do this assertion only reading the info ptr
- // once, because during parallel GC it might change under our feet.
- const StgInfoTable *info;
- info = w->header.info;
- ASSERT(IS_FORWARDING_PTR(info)
- || info == &stg_DEAD_WEAK_info
- || INFO_PTR_TO_STRUCT(info)->type == WEAK);
- }
+ { // careful to do this assertion only reading the info ptr
+ // once, because during parallel GC it might change under our feet.
+ const StgInfoTable *info;
+ info = w->header.info;
+ ASSERT(IS_FORWARDING_PTR(info)
+ || info == &stg_DEAD_WEAK_info
+ || INFO_PTR_TO_STRUCT(info)->type == WEAK);
+ }
#endif
- evacuate((StgClosure **)last_w);
- w = *last_w;
- if (w->header.info == &stg_DEAD_WEAK_info) {
- last_w = &(w->link);
- } else {
- last_w = &(w->link);
- }
- }
+ evacuate((StgClosure **)last_w);
+ w = *last_w;
+ if (w->header.info == &stg_DEAD_WEAK_info) {
+ last_w = &(w->link);
+ } else {
+ last_w = &(w->link);
+ }
+ }
+ }
}
diff --git a/rts/sm/Storage.c b/rts/sm/Storage.c
index 5d5470b025..a5337bc5b2 100644
--- a/rts/sm/Storage.c
+++ b/rts/sm/Storage.c
@@ -93,6 +93,8 @@ initGeneration (generation *gen, int g)
#endif
gen->threads = END_TSO_QUEUE;
gen->old_threads = END_TSO_QUEUE;
+ gen->weak_ptr_list = NULL;
+ gen->old_weak_ptr_list = NULL;
}
void
@@ -169,7 +171,6 @@ initStorage (void)
generations[0].max_blocks = 0;
- weak_ptr_list = NULL;
caf_list = END_OF_STATIC_LIST;
revertible_caf_list = END_OF_STATIC_LIST;
diff --git a/utils/deriveConstants/DeriveConstants.hs b/utils/deriveConstants/DeriveConstants.hs
index c731b9ea72..3173c27cec 100644
--- a/utils/deriveConstants/DeriveConstants.hs
+++ b/utils/deriveConstants/DeriveConstants.hs
@@ -346,6 +346,7 @@ wanteds = concat
,structSize C "generation"
,structField C "generation" "n_new_large_words"
+ ,structField C "generation" "weak_ptr_list"
,structSize Both "CostCentreStack"
,structField C "CostCentreStack" "ccsID"