[pypy-commit] pypy default: Trying to implement Boehm support for rgc.FinalizerQueue

arigo pypy.commits at gmail.com
Sun Jun 26 04:23:33 EDT 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r85380:827cb0a67372
Date: 2016-06-26 10:24 +0200
http://bitbucket.org/pypy/pypy/changeset/827cb0a67372/

Log:	Trying to implement Boehm support for rgc.FinalizerQueue

diff --git a/rpython/memory/gctransform/boehm.py b/rpython/memory/gctransform/boehm.py
--- a/rpython/memory/gctransform/boehm.py
+++ b/rpython/memory/gctransform/boehm.py
@@ -1,6 +1,7 @@
 from rpython.memory.gctransform.transform import GCTransformer, mallocHelpers
 from rpython.memory.gctransform.support import (get_rtti,
-    _static_deallocator_body_for_type, LLTransformerOp, ll_call_destructor)
+    _static_deallocator_body_for_type, LLTransformerOp, ll_call_destructor,
+    ll_report_finalizer_error)
 from rpython.rtyper.lltypesystem import lltype, llmemory
 from rpython.flowspace.model import Constant
 from rpython.rtyper.lltypesystem.lloperation import llop
@@ -58,6 +59,9 @@
             self.mixlevelannotator.finish()   # for now
             self.mixlevelannotator.backend_optimize()
 
+        self.finalizer_triggers = []
+        self.finalizer_queue_indexes = {}    # {fq: index}
+
     def gct_fv_gc_malloc(self, hop, flags, TYPE, c_size):
         # XXX same behavior for zero=True: in theory that's wrong
         if TYPE._is_atomic():
@@ -115,6 +119,39 @@
         self.finalizer_funcptrs[TYPE] = fptr
         return fptr
 
+    def get_finalizer_queue_index(self, hop):
+        fq_tag = hop.spaceop.args[0].value
+        assert 'FinalizerQueue TAG' in fq_tag.expr
+        fq = fq_tag.default
+        try:
+            index = self.finalizer_queue_indexes[fq]
+        except KeyError:
+            index = len(self.finalizer_queue_indexes)
+            assert index == len(self.finalizer_triggers)
+            #
+            def ll_finalizer_trigger():
+                try:
+                    fq.finalizer_trigger()
+                except Exception as e:
+                    ll_report_finalizer_error(e)
+            ll_trigger = self.annotate_finalizer(ll_finalizer_trigger, [],
+                                                 lltype.Void)
+            self.finalizer_triggers.append(ll_trigger)
+            self.finalizer_queue_indexes[fq] = index
+        return index
+
+    def gct_gc_fq_register(self, hop):
+        index = self.get_finalizer_queue_index(hop)
+        c_index = rmodel.inputconst(lltype.Signed, index)
+        v_ptr = hop.spaceop.args[1]
+        hop.genop("boehm_fq_register", [c_index, v_ptr])
+
+    def gct_gc_fq_next_dead(self, hop):
+        index = self.get_finalizer_queue_index(hop)
+        c_index = rmodel.inputconst(lltype.Signed, index)
+        hop.genop("boehm_fq_next_dead", [c_index],
+                  resultvar = hop.spaceop.result)
+
     def gct_weakref_create(self, hop):
         v_instance, = hop.spaceop.args
         v_addr = hop.genop("cast_ptr_to_adr", [v_instance],
diff --git a/rpython/translator/c/gc.py b/rpython/translator/c/gc.py
--- a/rpython/translator/c/gc.py
+++ b/rpython/translator/c/gc.py
@@ -212,6 +212,24 @@
             compile_extra=['-DPYPY_USING_BOEHM_GC'],
             ))
 
+        gct = self.db.gctransformer
+        gct.finalizer_triggers = tuple(gct.finalizer_triggers)  # stop changing
+        sourcelines = ['']
+        for trig in gct.finalizer_triggers:
+            sourcelines.append('RPY_EXTERN void %s(void);' % (
+                self.db.get(trig),))
+        sourcelines.append('')
+        sourcelines.append('void (*boehm_fq_trigger[])(void) = {')
+        for trig in gct.finalizer_triggers:
+            sourcelines.append('\t%s,' % (self.db.get(trig),))
+        sourcelines.append('\tNULL')
+        sourcelines.append('};')
+        sourcelines.append('struct boehm_fq_s *boehm_fq_queues[%d];' % (
+            len(gct.finalizer_triggers),))
+        sourcelines.append('')
+        eci = eci.merge(ExternalCompilationInfo(
+            separate_module_sources=['\n'.join(sourcelines)]))
+
         return eci
 
     def gc_startup_code(self):
diff --git a/rpython/translator/c/src/mem.c b/rpython/translator/c/src/mem.c
--- a/rpython/translator/c/src/mem.c
+++ b/rpython/translator/c/src/mem.c
@@ -73,9 +73,17 @@
 
 #ifdef PYPY_USING_BOEHM_GC
 
+struct boehm_fq_s {
+    void *obj;
+    struct boehm_fq_s *next;
+};
+RPY_EXTERN void (*boehm_fq_trigger[])(void);
+
 int boehm_gc_finalizer_lock = 0;
 void boehm_gc_finalizer_notifier(void)
 {
+    int i;
+
     boehm_gc_finalizer_lock++;
     while (GC_should_invoke_finalizers()) {
         if (boehm_gc_finalizer_lock > 1) {
@@ -86,6 +94,11 @@
         }
         GC_invoke_finalizers();
     }
+
+    i = 0;
+    while (boehm_fq_trigger[i])
+        boehm_fq_trigger[i++]();
+
     boehm_gc_finalizer_lock--;
 }
 
@@ -100,6 +113,28 @@
     GC_finalize_on_demand = 1;
     GC_set_warn_proc(mem_boehm_ignore);
 }
+
+void boehm_fq_callback(void *obj, void *rawfqueue)
+{
+    struct boehm_fq_s **fqueue = rawfqueue;
+    struct boehm_fq_s *node = GC_malloc(sizeof(void *) * 2);
+    if (!node)
+        return;   /* ouch, too bad */
+    node->obj = obj;
+    node->next = *fqueue;
+    *fqueue = node;
+}
+
+void *boehm_fq_next_dead(struct boehm_fq_s **fqueue)
+{
+    struct boehm_fq_s *node = *fqueue;
+    if (node != NULL) {
+        *fqueue = node->next;
+        return node->obj;
+    }
+    else
+        return NULL;
+}
 #endif /* BOEHM GC */
 
 
diff --git a/rpython/translator/c/src/mem.h b/rpython/translator/c/src/mem.h
--- a/rpython/translator/c/src/mem.h
+++ b/rpython/translator/c/src/mem.h
@@ -104,13 +104,21 @@
 RPY_EXTERN int boehm_gc_finalizer_lock;
 RPY_EXTERN void boehm_gc_startup_code(void);
 RPY_EXTERN void boehm_gc_finalizer_notifier(void);
+struct boehm_fq_s;
+RPY_EXTERN struct boehm_fq_s *boehm_fq_queues[];
+RPY_EXTERN void (*boehm_fq_trigger[])(void);
+RPY_EXTERN void boehm_fq_callback(void *, void *);
+RPY_EXTERN void *boehm_fq_next_dead(struct boehm_fq_s **);
 
 #define OP_GC__DISABLE_FINALIZERS(r)  boehm_gc_finalizer_lock++
 #define OP_GC__ENABLE_FINALIZERS(r)  (boehm_gc_finalizer_lock--,	\
 				      boehm_gc_finalizer_notifier())
 
-#define OP_GC_FQ_REGISTER(tag, obj, r)   /* ignored so far */
-#define OP_GC_FQ_NEXT_DEAD(tag, r)       (r = NULL)
+#define OP_BOEHM_FQ_REGISTER(tagindex, obj, r)                          \
+    GC_REGISTER_FINALIZER(obj, boehm_fq_callback,                       \
+                          boehm_fq_queues + tagindex, NULL, NULL)
+#define OP_BOEHM_FQ_NEXT_DEAD(tagindex, r)                              \
+    r = boehm_fq_next_dead(boehm_fq_queues + tagindex)
 
 #endif /* PYPY_USING_BOEHM_GC */
 
diff --git a/rpython/translator/c/test/test_boehm.py b/rpython/translator/c/test/test_boehm.py
--- a/rpython/translator/c/test/test_boehm.py
+++ b/rpython/translator/c/test/test_boehm.py
@@ -393,20 +393,36 @@
         assert res[3] == compute_hash(d)
         assert res[4] == compute_hash(("Hi", None, (7.5, 2, d)))
 
-    def test_finalizer_queue_is_at_least_ignored(self):
+    def test_finalizer_queue(self):
         class A(object):
-            pass
+            def __init__(self, i):
+                self.i = i
+        class Glob:
+            triggered = 0
+        glob = Glob()
         class FQ(rgc.FinalizerQueue):
             Class = A
+            triggered = 0
             def finalizer_trigger(self):
-                debug.debug_print("hello!")    # not called so far
+                glob.triggered += 1
         fq = FQ()
         #
         def fn():
-            fq.register_finalizer(A())
+            for i in range(1000):
+                fq.register_finalizer(A(i))
             rgc.collect()
             rgc.collect()
-            fq.next_dead()
+            if glob.triggered == 0:
+                print "not triggered!"
+                return 50
+            seen = {}
+            for i in range(1000):
+                a = fq.next_dead()
+                assert a.i not in seen
+                seen[a.i] = True
+            if len(seen) < 500:
+                print "seen only %d!" % len(seen)
+                return 51
             return 42
 
         f = self.getcompiled(fn)


More information about the pypy-commit mailing list