summaryrefslogtreecommitdiff
path: root/rts/sm/MarkWeak.c
diff options
context:
space:
mode:
authorNicolas Frisby <nicolas.frisby@gmail.com>2013-08-22 15:00:41 -0500
committerNicolas Frisby <nicolas.frisby@gmail.com>2013-08-22 15:00:54 -0500
commit84f9927c1a04b8e35b97101771d8f6d625643d9b (patch)
tree050d7265a24fa1ff9aecc4081bb01bc444520587 /rts/sm/MarkWeak.c
parent2eaf46fb1bb8c661c03f3e5e80622207ef2509d9 (diff)
parentc24be4b761df558d9edc9c0b1554bb558c261b14 (diff)
downloadhaskell-late-dmd.tar.gz
merged master into late-dmdlate-dmd
Diffstat (limited to 'rts/sm/MarkWeak.c')
-rw-r--r--rts/sm/MarkWeak.c316
1 files changed, 180 insertions, 136 deletions
diff --git a/rts/sm/MarkWeak.c b/rts/sm/MarkWeak.c
index d57f7a094b..f0ab5d19d7 100644
--- a/rts/sm/MarkWeak.c
+++ b/rts/sm/MarkWeak.c
@@ -75,164 +75,133 @@
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 resurrectUnreachableThreads (generation *gen);
-static rtsBool tidyThreadList (generation *gen);
+static void collectDeadWeakPtrs (generation *gen);
+static rtsBool tidyWeakList (generation *gen);
+static rtsBool resurrectUnreachableThreads (generation *gen);
+static void tidyThreadList (generation *gen);
void
initWeakForGC(void)
{
- old_weak_ptr_list = weak_ptr_list;
- weak_ptr_list = NULL;
- weak_ptr_list_tail = NULL;
- weak_stage = WeakPtrs;
+ 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 = WeakThreads;
+ 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) {
case WeakDone:
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 = ((StgDeadWeak *)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.
- // 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",
- w, w->key);
- continue;
- }
- else {
- last_w = &(w->link);
- next_w = w->link;
- continue;
- }
-
- default:
- barf("traverseWeakPtrList: not WEAK");
- }
- }
-
- /* 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
- * of pending finalizers later on.
- */
- if (flag == rtsFalse) {
- for (w = old_weak_ptr_list; w; w = w->link) {
- evacuate(&w->finalizer);
- }
-
- // Next, move to the WeakThreads stage after fully
- // scavenging the finalizers we've just evacuated.
- weak_stage = WeakThreads;
- }
-
- return rtsTrue;
-
case WeakThreads:
- /* Now deal with the step->threads lists, which behave somewhat like
+ /* Now deal with the gen->threads lists, which behave somewhat like
* the weak ptr list. If we discover any threads that are about to
* become garbage, we wake them up and administer an exception.
*/
{
nat g;
- // Traverse thread lists for generations we collected...
-// ToDo when we have one gen per capability:
-// for (n = 0; n < n_capabilities; n++) {
-// if (tidyThreadList(&nurseries[n])) {
-// flag = rtsTrue;
-// }
-// }
for (g = 0; g <= N; g++) {
- if (tidyThreadList(&generations[g])) {
+ tidyThreadList(&generations[g]);
+ }
+
+ // Use weak pointer relationships (value is reachable if
+ // key is reachable):
+ for (g = 0; g <= N; g++) {
+ if (tidyWeakList(&generations[g])) {
flag = rtsTrue;
}
}
+
+ // if we evacuated anything new, we must scavenge thoroughly
+ // before we can determine which threads are unreachable.
+ if (flag) return rtsTrue;
- /* If we evacuated any threads, we need to go back to the scavenger.
- */
+ // Resurrect any threads which were unreachable
+ for (g = 0; g <= N; g++) {
+ if (resurrectUnreachableThreads(&generations[g])) {
+ flag = rtsTrue;
+ }
+ }
+
+ // Next, move to the WeakPtrs stage after fully
+ // scavenging the finalizers we've just evacuated.
+ weak_stage = WeakPtrs;
+
+ // if we evacuated anything new, we must scavenge thoroughly
+ // before entering the WeakPtrs stage.
if (flag) return rtsTrue;
- /* And resurrect any threads which were about to become garbage.
+ // otherwise, fall through...
+ }
+
+ case WeakPtrs:
+ {
+ nat g;
+
+ // resurrecting threads might have made more weak pointers
+ // alive, so traverse those lists again:
+ 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 dead_weak_ptr list is used as a list
+ * of pending finalizers later on.
*/
- {
- nat g;
+ if (flag == rtsFalse) {
for (g = 0; g <= N; g++) {
- resurrectUnreachableThreads(&generations[g]);
+ collectDeadWeakPtrs(&generations[g]);
}
+
+ weak_stage = WeakDone; // *now* we're done,
}
-
- weak_stage = WeakDone; // *now* we're done,
+
return rtsTrue; // but one more round of scavenging, please
}
-
+
default:
barf("traverse_weak_ptr_list");
return rtsTrue;
}
}
- static void resurrectUnreachableThreads (generation *gen)
+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 rtsBool resurrectUnreachableThreads (generation *gen)
{
StgTSO *t, *tmp, *next;
+ rtsBool flag = rtsFalse;
for (t = gen->old_threads; t != END_TSO_QUEUE; t = next) {
next = t->global_link;
@@ -250,14 +219,89 @@ traverseWeakPtrList(void)
evacuate((StgClosure **)&tmp);
tmp->global_link = resurrected_threads;
resurrected_threads = tmp;
+ flag = rtsTrue;
}
}
+ return flag;
}
-static rtsBool tidyThreadList (generation *gen)
+static rtsBool tidyWeakList(generation *gen)
{
- StgTSO *t, *tmp, *next, **prev;
+ 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 void tidyThreadList (generation *gen)
+{
+ StgTSO *t, *tmp, *next, **prev;
prev = &gen->old_threads;
@@ -297,45 +341,45 @@ static rtsBool tidyThreadList (generation *gen)
new_gen->threads = t;
}
}
-
- return flag;
}
/* -----------------------------------------------------------------------------
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 = &(((StgDeadWeak*)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);
+ }
+ }
+ }
}