[pypy-commit] stmgc finalizer: Copying directly the algorithm from pypy's minimark.py. Compiles but not

arigo noreply at buildbot.pypy.org
Mon Oct 6 17:39:29 CEST 2014


Author: Armin Rigo <arigo at tunes.org>
Branch: finalizer
Changeset: r1464:b18fbe29f7f7
Date: 2014-10-06 17:39 +0200
http://bitbucket.org/pypy/stmgc/changeset/b18fbe29f7f7/

Log:	Copying directly the algorithm from pypy's minimark.py. Compiles
	but not tested so far (and missing ways to register non-light
	finalizers).

diff --git a/c7/stm/core.h b/c7/stm/core.h
--- a/c7/stm/core.h
+++ b/c7/stm/core.h
@@ -199,9 +199,10 @@
     /* marker where this thread became inevitable */
     stm_loc_marker_t marker_inev;
 
-    /* Lightweight finalizers */
+    /* finalizers */
     struct list_s *young_objects_with_light_finalizers;
     struct list_s *old_objects_with_light_finalizers;
+    struct list_s *objects_with_finalizers;
 };
 
 enum /* safe_point */ {
diff --git a/c7/stm/finalizer.c b/c7/stm/finalizer.c
--- a/c7/stm/finalizer.c
+++ b/c7/stm/finalizer.c
@@ -4,18 +4,15 @@
 
 void stm_enable_light_finalizer(object_t *obj)
 {
-    if (_is_young(obj)) {
-        STM_PSEGMENT->young_objects_with_light_finalizers = list_append(
-            STM_PSEGMENT->young_objects_with_light_finalizers, (uintptr_t)obj);
-    }
-    else {
-        STM_PSEGMENT->old_objects_with_light_finalizers = list_append(
-            STM_PSEGMENT->old_objects_with_light_finalizers, (uintptr_t)obj);
-    }
+    if (_is_young(obj))
+        LIST_APPEND(STM_PSEGMENT->young_objects_with_light_finalizers, obj);
+    else
+        LIST_APPEND(STM_PSEGMENT->old_objects_with_light_finalizers, obj);
 }
 
 static void deal_with_young_objects_with_finalizers(void)
 {
+    /* for light finalizers */
     struct list_s *lst = STM_PSEGMENT->young_objects_with_light_finalizers;
     long i, count = list_count(lst);
     for (i = 0; i < count; i++) {
@@ -30,8 +27,7 @@
         else {
             obj = pforwarded_array[1]; /* moved location */
             assert(!_is_young(obj));
-            STM_PSEGMENT->old_objects_with_light_finalizers = list_append(
-               STM_PSEGMENT->old_objects_with_light_finalizers, (uintptr_t)obj);
+            LIST_APPEND(STM_PSEGMENT->old_objects_with_light_finalizers, obj);
         }
     }
     list_clear(lst);
@@ -39,6 +35,7 @@
 
 static void deal_with_old_objects_with_finalizers(void)
 {
+    /* for light finalizers */
     long j;
     for (j = 1; j <= NB_SEGMENTS; j++) {
         struct stm_priv_segment_info_s *pseg = get_priv_segment(j);
@@ -63,3 +60,131 @@
         }
     }
 }
+
+
+/************************************************************/
+/*  Algorithm for regular (non-light) finalizers.
+    Follows closely pypy/doc/discussion/finalizer-order.rst
+    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 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;
+}
+
+static struct list_s *_finalizer_tmpstack;
+
+static inline void append_to_finalizer_tmpstack(object_t **pobj)
+{
+    object_t *obj = *pobj;
+    if (obj != NULL)
+        LIST_APPEND(_finalizer_tmpstack, obj);
+}
+
+static void _recursively_bump_finalization_state(object_t *obj, int from_state,
+                                                 struct list_s *tmpstack)
+{
+    assert(_finalization_state(obj) == from_state);
+    assert(list_is_empty(tmpstack));
+    _finalizer_tmpstack = tmpstack;
+
+    while (1) {
+        if (_finalization_state(obj) == from_state) {
+            /* bump to the next state */
+            write_locks[mark_loc(obj)]++;
+
+            /* trace */
+            struct object_s *realobj =
+                (struct object_s *)REAL_ADDRESS(stm_object_pages, obj);
+            stmcb_trace(realobj, &append_to_finalizer_tmpstack);
+        }
+
+        if (list_is_empty(tmpstack))
+            break;
+
+        obj = (object_t *)list_pop_item(tmpstack);
+    }
+}
+
+static void deal_with_objects_with_finalizers(void)
+{
+    /* for non-light finalizers */
+
+    /* there is one 'objects_with_finalizers' list per segment, but it
+       doesn't really matter: all objects are considered equal, and if
+       they survive, they are added again into one list that is attached
+       at the end to an arbitrary segment. */
+    struct list_s *new_with_finalizer = list_create();
+    struct list_s *marked = list_create();
+    struct list_s *pending = list_create();
+    struct list_s *tmpstack = list_create();
+
+    long j;
+    for (j = 1; j <= NB_SEGMENTS; j++) {
+        struct stm_priv_segment_info_s *pseg = get_priv_segment(j);
+
+        struct list_s *lst = pseg->objects_with_finalizers;
+        long i, count = list_count(lst);
+        for (i = 0; i < count; i++) {
+            object_t *x = (object_t *)list_item(lst, i);
+
+            assert(_finalization_state(x) != 1);
+            if (_finalization_state(x) >= 2) {
+                LIST_APPEND(new_with_finalizer, x);
+                continue;
+            }
+            LIST_APPEND(marked, x);
+            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);
+                    /* trace into the 'pending' list */
+                    struct object_s *realobj =
+                        (struct object_s *)REAL_ADDRESS(stm_object_pages, y);
+                    _finalizer_tmpstack = pending;
+                    stmcb_trace(realobj, &append_to_finalizer_tmpstack);
+                }
+                else if (state == 2) {
+                    _recursively_bump_finalization_state(y, 2, tmpstack);
+                }
+            }
+            _recursively_bump_finalization_state(x, 1, tmpstack);
+        }
+        list_clear(lst);
+    }
+
+    long i, count = list_count(marked);
+    for (i = 0; i < count; i++) {
+        object_t *x = (object_t *)list_item(marked, i);
+
+        int state = _finalization_state(x);
+        assert(state >= 2);
+        if (state == 2) {
+            LIST_APPEND(run_finalizers, x);
+            _recursively_bump_finalization_state(x, 2, tmpstack);
+        }
+        else {
+            LIST_APPEND(new_with_finalizer, x);
+        }
+    }
+
+    list_free(tmpstack);
+    list_free(pending);
+    list_free(marked);
+    list_free(get_priv_segment(1)->objects_with_finalizers);
+    get_priv_segment(1)->objects_with_finalizers = new_with_finalizer;
+}
diff --git a/c7/stm/finalizer.h b/c7/stm/finalizer.h
--- a/c7/stm/finalizer.h
+++ b/c7/stm/finalizer.h
@@ -1,3 +1,6 @@
 
 static void deal_with_young_objects_with_finalizers(void);
 static void deal_with_old_objects_with_finalizers(void);
+static void deal_with_objects_with_finalizers(void);
+
+static struct list_s *run_finalizers;
diff --git a/c7/stm/gcpage.c b/c7/stm/gcpage.c
--- a/c7/stm/gcpage.c
+++ b/c7/stm/gcpage.c
@@ -161,7 +161,11 @@
 
 static struct list_s *mark_objects_to_trace;
 
-#define WL_VISITED   255
+#define WL_FINALIZ_ORDER_1    253
+#define WL_FINALIZ_ORDER_2    254
+#define WL_FINALIZ_ORDER_3    WL_VISITED
+
+#define WL_VISITED            255
 
 
 static inline uintptr_t mark_loc(object_t *obj)
@@ -626,6 +630,11 @@
     mark_visit_from_roots();
     LIST_FREE(mark_objects_to_trace);
 
+    /* finalizer support: will mark as WL_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();
+
     /* weakrefs and old light finalizers */
     stm_visit_old_weakrefs();
     deal_with_old_objects_with_finalizers();
diff --git a/c7/stm/setup.c b/c7/stm/setup.c
--- a/c7/stm/setup.c
+++ b/c7/stm/setup.c
@@ -113,7 +113,7 @@
 
         /* Initialize STM_PSEGMENT */
         struct stm_priv_segment_info_s *pr = get_priv_segment(i);
-        assert(1 <= i && i < 255);   /* 255 is WL_VISITED in gcpage.c */
+        assert(1 <= i && i < 253);   /* 253 is WL_FINALIZ_ORDER_1 in gcpage.c */
         pr->write_lock_num = i;
         pr->pub.segment_num = i;
         pr->pub.segment_base = segment_base;
@@ -130,10 +130,12 @@
         pr->callbacks_on_commit_and_abort[1] = tree_create();
         pr->young_objects_with_light_finalizers = list_create();
         pr->old_objects_with_light_finalizers = list_create();
+        pr->objects_with_finalizers = list_create();
         pr->overflow_number = GCFLAG_OVERFLOW_NUMBER_bit0 * i;
         highest_overflow_number = pr->overflow_number;
         pr->pub.transaction_read_version = 0xff;
     }
+    run_finalizers = list_create();
 
     /* The pages are shared lazily, as remap_file_pages() takes a relatively
        long time for each page.
@@ -173,7 +175,9 @@
         tree_free(pr->callbacks_on_commit_and_abort[1]);
         list_free(pr->young_objects_with_light_finalizers);
         list_free(pr->old_objects_with_light_finalizers);
+        list_free(pr->objects_with_finalizers);
     }
+    list_free(run_finalizers);
 
     munmap(stm_object_pages, TOTAL_MEMORY);
     stm_object_pages = NULL;


More information about the pypy-commit mailing list