[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