[pypy-commit] stmgc default: c8: port major gc finalizer handling

Raemi noreply at buildbot.pypy.org
Tue Feb 24 23:50:39 CET 2015


Author: Remi Meier <remi.meier at gmail.com>
Branch: 
Changeset: r1662:df47b9331468
Date: 2015-02-24 23:20 +0100
http://bitbucket.org/pypy/stmgc/changeset/df47b9331468/

Log:	c8: port major gc finalizer handling

diff --git a/c8/stm/core.h b/c8/stm/core.h
--- a/c8/stm/core.h
+++ b/c8/stm/core.h
@@ -39,6 +39,7 @@
     GCFLAG_HAS_SHADOW = 0x02,
     GCFLAG_WB_EXECUTED = 0x04,
     GCFLAG_VISITED = 0x08,
+    GCFLAG_FINALIZATION_ORDERING = 0x10,
 };
 
 
diff --git a/c8/stm/finalizer.c b/c8/stm/finalizer.c
--- a/c8/stm/finalizer.c
+++ b/c8/stm/finalizer.c
@@ -228,195 +228,212 @@
     as well as rpython/memory/gc/minimark.py.
 */
 
-/* static inline int _finalization_state(object_t *obj) */
-/* { */
-/*     /\* Returns the state, "0", 1, 2 or 3, as per finalizer-order.rst. */
-/*        One difference is that the official state 0 is returned here */
-/*        as a number that is <= 0. *\/ */
-/*     uintptr_t lock_idx = mark_loc(obj); */
-/*     return write_locks[lock_idx] - (WL_FINALIZ_ORDER_1 - 1); */
-/* } */
+static inline int _finalization_state(object_t *obj)
+{
+    /* Returns the state, "0", 1, 2 or 3, as per finalizer-order.rst.
+       One difference is that the official state 0 is returned here
+       as a number that is <= 0. */
+    struct object_s *realobj = mark_loc(obj);
+    if (realobj->stm_flags & GCFLAG_VISITED) {
+        if (realobj->stm_flags & GCFLAG_FINALIZATION_ORDERING)
+            return 2;
+        return 3;
+    }
 
-/* static void _bump_finalization_state_from_0_to_1(object_t *obj) */
-/* { */
-/*     uintptr_t lock_idx = mark_loc(obj); */
-/*     assert(write_locks[lock_idx] < WL_FINALIZ_ORDER_1); */
-/*     write_locks[lock_idx] = WL_FINALIZ_ORDER_1; */
-/* } */
+    if (realobj->stm_flags & GCFLAG_FINALIZATION_ORDERING)
+        return 1;
 
-/* static struct list_s *_finalizer_tmpstack; */
-/* static struct list_s *_finalizer_emptystack; */
-/* static struct list_s *_finalizer_pending; */
+    return 0;
+}
 
-/* static inline void _append_to_finalizer_tmpstack(object_t **pobj) */
-/* { */
-/*     object_t *obj = *pobj; */
-/*     if (obj != NULL) */
-/*         LIST_APPEND(_finalizer_tmpstack, obj); */
-/* } */
+static void _bump_finalization_state_from_0_to_1(object_t *obj)
+{
+    assert(_finalization_state(obj) == 0);
+    struct object_s *realobj = mark_loc(obj);
+    realobj->stm_flags |= GCFLAG_FINALIZATION_ORDERING;
+}
 
-/* static inline struct list_s *finalizer_trace(char *base, object_t *obj, */
-/*                                              struct list_s *lst) */
-/* { */
-/*     struct object_s *realobj = (struct object_s *)REAL_ADDRESS(base, obj); */
-/*     _finalizer_tmpstack = lst; */
-/*     stmcb_trace(realobj, &_append_to_finalizer_tmpstack); */
-/*     return _finalizer_tmpstack; */
-/* } */
+static struct list_s *_finalizer_tmpstack;
+static struct list_s *_finalizer_emptystack;
+static struct list_s *_finalizer_pending;
 
-/* static void _recursively_bump_finalization_state(char *base, object_t *obj, */
-/*                                                  int to_state) */
-/* { */
-/*     struct list_s *tmpstack = _finalizer_emptystack; */
-/*     assert(list_is_empty(tmpstack)); */
+static inline void _append_to_finalizer_tmpstack(object_t **pobj)
+{
+    object_t *obj = *pobj;
+    if (obj != NULL)
+        LIST_APPEND(_finalizer_tmpstack, obj);
+}
 
-/*     while (1) { */
-/*         if (_finalization_state(obj) == to_state - 1) { */
-/*             /\* bump to the next state *\/ */
-/*             write_locks[mark_loc(obj)]++; */
+static inline struct list_s *finalizer_trace(char *base, object_t *obj,
+                                             struct list_s *lst)
+{
+    struct object_s *realobj = (struct object_s *)REAL_ADDRESS(base, obj);
+    _finalizer_tmpstack = lst;
+    stmcb_trace(realobj, &_append_to_finalizer_tmpstack);
+    return _finalizer_tmpstack;
+}
 
-/*             /\* trace *\/ */
-/*             tmpstack = finalizer_trace(base, obj, tmpstack); */
-/*         } */
 
-/*         if (list_is_empty(tmpstack)) */
-/*             break; */
+static void _recursively_bump_finalization_state_from_2_to_3(char *base, object_t *obj)
+{
+    assert(_finalization_state(obj) == 2);
+    struct list_s *tmpstack = _finalizer_emptystack;
+    assert(list_is_empty(tmpstack));
 
-/*         obj = (object_t *)list_pop_item(tmpstack); */
-/*     } */
-/*     _finalizer_emptystack = tmpstack; */
-/* } */
+    while (1) {
+        struct object_s *realobj = mark_loc(obj);
+        if (realobj->stm_flags & GCFLAG_FINALIZATION_ORDERING) {
+            realobj->stm_flags &= ~GCFLAG_FINALIZATION_ORDERING;
 
-/* static struct list_s *mark_finalize_step1(char *base, struct finalizers_s *f) */
-/* { */
-/*     if (f == NULL) */
-/*         return NULL; */
+            /* trace */
+            tmpstack = finalizer_trace(base, obj, tmpstack);
+        }
 
-/*     struct list_s *marked = list_create(); */
+        if (list_is_empty(tmpstack))
+            break;
 
-/*     struct list_s *lst = f->objects_with_finalizers; */
-/*     long i, count = list_count(lst); */
-/*     lst->count = 0; */
-/*     f->count_non_young = 0; */
+        obj = (object_t *)list_pop_item(tmpstack);
+    }
+    _finalizer_emptystack = tmpstack;
+}
 
-/*     for (i = 0; i < count; i++) { */
-/*         object_t *x = (object_t *)list_item(lst, i); */
+static void _recursively_bump_finalization_state_from_1_to_2(char *base, object_t *obj)
+{
+    assert(_finalization_state(obj) == 1);
+    /* The call will add GCFLAG_VISITED recursively, thus bump state 1->2 */
+    mark_visit_possibly_new_object(base, obj);
+}
 
-/*         assert(_finalization_state(x) != 1); */
-/*         if (_finalization_state(x) >= 2) { */
-/*             list_set_item(lst, lst->count++, (uintptr_t)x); */
-/*             continue; */
-/*         } */
-/*         LIST_APPEND(marked, x); */
+static struct list_s *mark_finalize_step1(char *base, struct finalizers_s *f)
+{
+    if (f == NULL)
+        return NULL;
 
-/*         struct list_s *pending = _finalizer_pending; */
-/*         LIST_APPEND(pending, x); */
-/*         while (!list_is_empty(pending)) { */
-/*             object_t *y = (object_t *)list_pop_item(pending); */
-/*             int state = _finalization_state(y); */
-/*             if (state <= 0) { */
-/*                 _bump_finalization_state_from_0_to_1(y); */
-/*                 pending = finalizer_trace(base, y, pending); */
-/*             } */
-/*             else if (state == 2) { */
-/*                 _recursively_bump_finalization_state(base, y, 3); */
-/*             } */
-/*         } */
-/*         _finalizer_pending = pending; */
-/*         assert(_finalization_state(x) == 1); */
-/*         _recursively_bump_finalization_state(base, x, 2); */
-/*     } */
-/*     return marked; */
-/* } */
+    struct list_s *marked = list_create();
 
-/* static void mark_finalize_step2(char *base, struct finalizers_s *f, */
-/*                                 struct list_s *marked) */
-/* { */
-/*     if (f == NULL) */
-/*         return; */
+    struct list_s *lst = f->objects_with_finalizers;
+    long i, count = list_count(lst);
+    lst->count = 0;
+    f->count_non_young = 0;
 
-/*     struct list_s *run_finalizers = f->run_finalizers; */
+    for (i = 0; i < count; i++) {
+        object_t *x = (object_t *)list_item(lst, i);
 
-/*     long i, count = list_count(marked); */
-/*     for (i = 0; i < count; i++) { */
-/*         object_t *x = (object_t *)list_item(marked, i); */
+        assert(_finalization_state(x) != 1);
+        if (_finalization_state(x) >= 2) {
+            list_set_item(lst, lst->count++, (uintptr_t)x);
+            continue;
+        }
+        LIST_APPEND(marked, x);
 
-/*         int state = _finalization_state(x); */
-/*         assert(state >= 2); */
-/*         if (state == 2) { */
-/*             if (run_finalizers == NULL) */
-/*                 run_finalizers = list_create(); */
-/*             LIST_APPEND(run_finalizers, x); */
-/*             _recursively_bump_finalization_state(base, x, 3); */
-/*         } */
-/*         else { */
-/*             struct list_s *lst = f->objects_with_finalizers; */
-/*             list_set_item(lst, lst->count++, (uintptr_t)x); */
-/*         } */
-/*     } */
-/*     list_free(marked); */
+        struct list_s *pending = _finalizer_pending;
+        LIST_APPEND(pending, x);
+        while (!list_is_empty(pending)) {
+            object_t *y = (object_t *)list_pop_item(pending);
+            int state = _finalization_state(y);
+            if (state <= 0) {
+                _bump_finalization_state_from_0_to_1(y);
+                pending = finalizer_trace(base, y, pending);
+            }
+            else if (state == 2) {
+                _recursively_bump_finalization_state_from_2_to_3(base, y);
+            }
+        }
+        _finalizer_pending = pending;
+        assert(_finalization_state(x) == 1);
+        _recursively_bump_finalization_state_from_1_to_2(base, x);
+    }
+    return marked;
+}
 
-/*     f->run_finalizers = run_finalizers; */
-/* } */
+static void mark_finalize_step2(char *base, struct finalizers_s *f,
+                                struct list_s *marked)
+{
+    if (f == NULL)
+        return;
 
-/* static void deal_with_objects_with_finalizers(void) */
-/* { */
-/*     /\* for non-light finalizers *\/ */
+    struct list_s *run_finalizers = f->run_finalizers;
 
-/*     /\* there is one 'objects_with_finalizers' list per segment. */
-/*        Objects that die at a major collection running in the same */
-/*        transaction as they were created will be put in the */
-/*        'run_finalizers' list of that segment.  Objects that survive at */
-/*        least one commit move to the global g_objects_with_finalizers, */
-/*        and when they die they go to g_run_finalizers.  The former kind */
-/*        of dying object must have its finalizer called in the correct */
-/*        thread; the latter kind can be called in any thread, through */
-/*        any segment, because they all should see the same old content */
-/*        anyway.  (If the content was different between segments at this */
-/*        point, the object would be in a 'modified_old_objects' list */
-/*        somewhere, and so it wouldn't be dead). */
-/*     *\/ */
-/*     struct list_s *marked_seg[NB_SEGMENTS + 1]; */
-/*     LIST_CREATE(_finalizer_emptystack); */
-/*     LIST_CREATE(_finalizer_pending); */
+    long i, count = list_count(marked);
+    for (i = 0; i < count; i++) {
+        object_t *x = (object_t *)list_item(marked, i);
 
-/*     long j; */
-/*     for (j = 1; j <= NB_SEGMENTS; j++) { */
-/*         struct stm_priv_segment_info_s *pseg = get_priv_segment(j); */
-/*         marked_seg[j] = mark_finalize_step1(pseg->pub.segment_base, */
-/*                                             pseg->finalizers); */
-/*     } */
-/*     marked_seg[0] = mark_finalize_step1(stm_object_pages, &g_finalizers); */
+        int state = _finalization_state(x);
+        assert(state >= 2);
+        if (state == 2) {
+            if (run_finalizers == NULL)
+                run_finalizers = list_create();
+            LIST_APPEND(run_finalizers, x);
+            _recursively_bump_finalization_state_from_2_to_3(base, x);
+        }
+        else {
+            struct list_s *lst = f->objects_with_finalizers;
+            list_set_item(lst, lst->count++, (uintptr_t)x);
+        }
+    }
+    list_free(marked);
 
-/*     LIST_FREE(_finalizer_pending); */
+    f->run_finalizers = run_finalizers;
+}
 
-/*     for (j = 1; j <= NB_SEGMENTS; j++) { */
-/*         struct stm_priv_segment_info_s *pseg = get_priv_segment(j); */
-/*         mark_finalize_step2(pseg->pub.segment_base, pseg->finalizers, */
-/*                             marked_seg[j]); */
-/*     } */
-/*     mark_finalize_step2(stm_object_pages, &g_finalizers, marked_seg[0]); */
+static void deal_with_objects_with_finalizers(void)
+{
+    /* for non-light finalizers */
 
-/*     LIST_FREE(_finalizer_emptystack); */
-/* } */
+    /* there is one 'objects_with_finalizers' list per segment.
+       Objects that die at a major collection running in the same
+       transaction as they were created will be put in the
+       'run_finalizers' list of that segment.  Objects that survive at
+       least one commit move to the global g_objects_with_finalizers,
+       and when they die they go to g_run_finalizers.  The former kind
+       of dying object must have its finalizer called in the correct
+       thread; the latter kind can be called in any thread, through
+       any segment, because they all should see the same old content
+       anyway.  (If the content was different between segments at this
+       point, the object would be in a 'modified_old_objects' list
+       somewhere, and so it wouldn't be dead).
+    */
+    struct list_s *marked_seg[NB_SEGMENTS];
+    LIST_CREATE(_finalizer_emptystack);
+    LIST_CREATE(_finalizer_pending);
 
-/* static void mark_visit_from_finalizer1(char *base, struct finalizers_s *f) */
-/* { */
-/*     if (f != NULL && f->run_finalizers != NULL) { */
-/*         LIST_FOREACH_R(f->run_finalizers, object_t * /\*item*\/, */
-/*                        mark_visit_object(item, base)); */
-/*     } */
-/* } */
+    long j;
+    for (j = 1; j < NB_SEGMENTS; j++) {
+        struct stm_priv_segment_info_s *pseg = get_priv_segment(j);
+        marked_seg[j] = mark_finalize_step1(pseg->pub.segment_base,
+                                            pseg->finalizers);
+    }
+    marked_seg[0] = mark_finalize_step1(stm_object_pages, &g_finalizers);
 
-/* static void mark_visit_from_finalizer_pending(void) */
-/* { */
-/*     long j; */
-/*     for (j = 1; j <= NB_SEGMENTS; j++) { */
-/*         struct stm_priv_segment_info_s *pseg = get_priv_segment(j); */
-/*         mark_visit_from_finalizer1(pseg->pub.segment_base, pseg->finalizers); */
-/*     } */
-/*     mark_visit_from_finalizer1(stm_object_pages, &g_finalizers); */
-/* } */
+    LIST_FREE(_finalizer_pending);
+
+    for (j = 1; j < NB_SEGMENTS; j++) {
+        struct stm_priv_segment_info_s *pseg = get_priv_segment(j);
+        mark_finalize_step2(pseg->pub.segment_base, pseg->finalizers,
+                            marked_seg[j]);
+    }
+    mark_finalize_step2(stm_object_pages, &g_finalizers, marked_seg[0]);
+
+    LIST_FREE(_finalizer_emptystack);
+}
+
+static void mark_visit_from_finalizer1(char *base, struct finalizers_s *f)
+{
+    if (f != NULL && f->run_finalizers != NULL) {
+        LIST_FOREACH_R(f->run_finalizers, object_t * /*item*/,
+                       mark_visit_object(item, base));
+    }
+}
+
+static void mark_visit_from_finalizer_pending(void)
+{
+    long j;
+    for (j = 1; j < NB_SEGMENTS; j++) {
+        struct stm_priv_segment_info_s *pseg = get_priv_segment(j);
+        mark_visit_from_finalizer1(pseg->pub.segment_base, pseg->finalizers);
+    }
+    mark_visit_from_finalizer1(stm_object_pages, &g_finalizers);
+}
 
 static void _execute_finalizers(struct finalizers_s *f)
 {
diff --git a/c8/stm/gcpage.c b/c8/stm/gcpage.c
--- a/c8/stm/gcpage.c
+++ b/c8/stm/gcpage.c
@@ -146,6 +146,7 @@
     }
 
     s_mutex_unlock();
+    exec_local_finalizers();
 }
 
 
@@ -456,6 +457,9 @@
                 mark_visited_test_and_clear(item);
                 realobj = (struct object_s*)REAL_ADDRESS(stm_object_pages, item);
                 realobj->stm_flags |= GCFLAG_WB_EXECUTED;
+
+                /* make sure this flag is cleared as well */
+                realobj->stm_flags &= ~GCFLAG_FINALIZATION_ORDERING;
             }));
     }
 #pragma pop_macro("STM_SEGMENT")
@@ -657,9 +661,16 @@
     LIST_CREATE(marked_objects_to_trace);
     mark_visit_from_modified_objects();
     mark_visit_from_roots();
+    mark_visit_from_finalizer_pending();
+
+    /* finalizer support: will mark as visited all objects with a
+       finalizer and all objects reachable from there, and also moves
+       some objects from 'objects_with_finalizers' to 'run_finalizers'. */
+    deal_with_objects_with_finalizers();
+
     LIST_FREE(marked_objects_to_trace);
 
-    /* weakrefs */
+    /* weakrefs and execute old light finalizers */
     stm_visit_old_weakrefs();
     deal_with_old_objects_with_finalizers();
 


More information about the pypy-commit mailing list