[pypy-commit] pypy cpyext-gc-trialdeletion: Added tests
stevie_92
pypy.commits at gmail.com
Thu Aug 31 05:40:10 EDT 2017
Author: Stefan Beyer <home at sbeyer.at>
Branch: cpyext-gc-trialdeletion
Changeset: r92284:a478bda34d52
Date: 2017-08-31 11:38 +0200
http://bitbucket.org/pypy/pypy/changeset/a478bda34d52/
Log: Added tests Fixed bug in generic_cpy_call if called recursively
Fixed bug in cycle detection if object is buffered twice
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -200,10 +200,11 @@
# executes. In non-cpyext-related code, it will thus always be 0.
#
# **make_generic_cpy_call():** RPython to C, with the GIL held. Before
-# the call, must assert that the global variable is 0 and set the
-# current thread identifier into the global variable. After the call,
-# assert that the global variable still contains the current thread id,
-# and reset it to 0.
+# the call, must assert that the global variable is 0 or the current
+# thread identifier (recursive call) and set the current thread identifier
+# into the global variable. After the call, assert that the global variable
+# still contains the current thread id, and reset it to the value it held
+# before the call.
#
# **make_wrapper():** C to RPython; by default assume that the GIL is
# held, but accepts gil="acquire", "release", "around",
@@ -1598,7 +1599,8 @@
# see "Handling of the GIL" above
tid = rthread.get_ident()
- assert cpyext_glob_tid_ptr[0] == 0
+ tid_before = cpyext_glob_tid_ptr[0]
+ assert tid_before == 0 or tid_before == tid
cpyext_glob_tid_ptr[0] = tid
try:
@@ -1606,7 +1608,7 @@
result = call_external_function(func, *boxed_args)
finally:
assert cpyext_glob_tid_ptr[0] == tid
- cpyext_glob_tid_ptr[0] = 0
+ cpyext_glob_tid_ptr[0] = tid_before
keepalive_until_here(*keepalives)
if is_PyObject(RESULT_TYPE):
diff --git a/rpython/memory/gc/incminimark.py b/rpython/memory/gc/incminimark.py
--- a/rpython/memory/gc/incminimark.py
+++ b/rpython/memory/gc/incminimark.py
@@ -3205,9 +3205,7 @@
from rpython.rlib.rawrefcount import (REFCNT_CYCLE_BUFFERED,
REFCNT_CLR_MASK,
REFCNT_CLR_PURPLE,
- REFCNT_MASK,
- W_MARKER_DEALLOCATING,
- mark_deallocating)
+ REFCNT_MASK)
obj = self._pyobj(pyobject)
rc = obj.c_ob_refcnt
debug_print("_rrc_cycle_mark_roots", obj)
@@ -3218,8 +3216,8 @@
obj.c_ob_refcnt = rc & ~REFCNT_CYCLE_BUFFERED
self.rrc_buffered.remove(pyobject)
if rc & REFCNT_MASK == 0:
- mark_deallocating(W_MARKER_DEALLOCATING, obj)
- generic_cpy_call(True, obj.c_ob_type.c_tp_dealloc, obj)
+ if obj.c_ob_type.c_tp_dealloc:
+ generic_cpy_call(True, obj.c_ob_type.c_tp_dealloc, obj)
def _rrc_cycle_scan_roots(self, pyobject, ignore):
obj = self._pyobj(pyobject)
diff --git a/rpython/memory/gc/test/test_rawrefcount.py b/rpython/memory/gc/test/test_rawrefcount.py
--- a/rpython/memory/gc/test/test_rawrefcount.py
+++ b/rpython/memory/gc/test/test_rawrefcount.py
@@ -2,11 +2,15 @@
from rpython.rtyper.lltypesystem import lltype, llmemory
from rpython.memory.gc.incminimark import IncrementalMiniMarkGC
from rpython.memory.gc.test.test_direct import BaseDirectGCTest
-from rpython.rlib.rawrefcount import REFCNT_FROM_PYPY
-from rpython.rlib.rawrefcount import REFCNT_FROM_PYPY_LIGHT
+from rpython.rlib.rawrefcount import (REFCNT_FROM_PYPY, REFCNT_FROM_PYPY_LIGHT,
+ REFCNT_MASK)
from pypy.module.cpyext.api import (PyObject, PyTypeObject, PyTypeObjectPtr,
PyObjectFields, cpython_struct)
from pypy.module.cpyext.complexobject import PyComplexObject
+from rpython.rtyper.lltypesystem import rffi
+from pypy.module.cpyext.typeobjectdefs import visitproc, traverseproc
+from rpython.rtyper.annlowlevel import llhelper
+from rpython.rtyper.tool import rffi_platform
PYOBJ_HDR = IncrementalMiniMarkGC.PYOBJ_HDR
PYOBJ_HDR_PTR = IncrementalMiniMarkGC.PYOBJ_HDR_PTR
@@ -17,6 +21,17 @@
('prev', lltype.Ptr(S)),
('next', lltype.Ptr(S))))
+T = lltype.Ptr(lltype.ForwardReference())
+T.TO.become(lltype.Struct('test',
+ ('base', PyObject.TO),
+ ('next', T),
+ ('prev', T),
+ ('value', lltype.Signed)))
+
+TRAVERSE_FUNCTYPE = rffi.CCallback([PyObject, visitproc, rffi.VOIDP],
+ rffi.INT_real)
+t1 = lltype.malloc(PyTypeObject, flavor='raw', immortal=True)
+
class TestRawRefCount(BaseDirectGCTest):
GCClass = IncrementalMiniMarkGC
@@ -86,47 +101,38 @@
return p1, p1ref, r1, r1addr, check_alive
def _rawrefcount_cycle_obj(self):
- from pypy.module.cpyext.typeobjectdefs import visitproc, traverseproc
- from rpython.rtyper.lltypesystem import rffi
- from rpython.rtyper.annlowlevel import llhelper
- from rpython.rlib.rawrefcount import (REFCNT_CLR_PURPLE)
- from rpython.rtyper.tool import rffi_platform
-
- self.gc.rawrefcount_init(lambda: self.trigger.append(1))
-
- # construct test type
- TEST_P = lltype.Ptr(lltype.ForwardReference())
- TEST_P.TO.become(lltype.Struct('test',
- ('base', PyObject.TO),
- ('next', TEST_P),
- ('value', lltype.Signed)))
def test_tp_traverse(obj, visit, args):
- from pypy.module.cpyext.api import generic_cpy_call
- test = rffi.cast(TEST_P, obj)
+ test = rffi.cast(T, obj)
vret = 0
- if test.next is not None:
+ if llmemory.cast_ptr_to_adr(test.next).ptr is not None:
next = rffi.cast(PyObject, test.next)
vret = visit(next, args)
if vret != 0:
return vret
+ if llmemory.cast_ptr_to_adr(test.prev).ptr is not None:
+ next = rffi.cast(PyObject, test.prev)
+ vret = visit(next, args)
+ if vret != 0:
+ return vret
return vret
- TRAVERSE_FUNCTYPE = rffi.CCallback([PyObject, visitproc, rffi.VOIDP],
- rffi.INT_real)
func_ptr = llhelper(TRAVERSE_FUNCTYPE, test_tp_traverse)
rffi_func_ptr = rffi.cast(traverseproc, func_ptr)
- t1 = lltype.malloc(PyTypeObject, flavor='raw', immortal=True)
t1.c_tp_traverse = rffi_func_ptr
- # initialize object
- r1 = lltype.malloc(TEST_P.TO, flavor='raw', immortal=True)
- r1.base.c_ob_refcnt = 1 | REFCNT_CLR_PURPLE
+ r1 = lltype.malloc(T.TO, flavor='raw', immortal=True)
r1.base.c_ob_pypy_link = 0
r1.base.c_ob_type = t1
- r1addr = llmemory.cast_ptr_to_adr(r1)
+ r1.base.c_ob_refcnt = 1
+ return r1
- return r1, r1addr
+ def _rawrefcount_buffer_obj(self, obj):
+ from rpython.rlib.rawrefcount import REFCNT_CLR_MASK, REFCNT_CLR_PURPLE
+ rc = obj.base.c_ob_refcnt
+ obj.base.c_ob_refcnt = rc & ~REFCNT_CLR_MASK | REFCNT_CLR_PURPLE
+ objaddr = llmemory.cast_ptr_to_adr(obj)
+ self.gc.rawrefcount_buffer_pyobj(objaddr)
def test_rawrefcount_objects_basic(self, old=False):
p1, p1ref, r1, r1addr, check_alive = (
@@ -338,16 +344,100 @@
check_alive(0)
def test_cycle_self_reference_free(self):
- r1, r1addr = self._rawrefcount_cycle_obj()
+ self.gc.rawrefcount_init(lambda: self.trigger.append(1))
+ r1 = self._rawrefcount_cycle_obj()
r1.next = r1
- self.gc.rawrefcount_buffer_pyobj(r1addr)
+ self._rawrefcount_buffer_obj(r1)
self.gc.rrc_collect_cycles()
- assert r1.base.c_ob_refcnt == 0
+ assert r1.base.c_ob_refcnt & REFCNT_MASK == 0
def test_cycle_self_reference_not_free(self):
- r1, r1addr = self._rawrefcount_cycle_obj()
+ self.gc.rawrefcount_init(lambda: self.trigger.append(1))
+ r1 = self._rawrefcount_cycle_obj()
r1.base.c_ob_refcnt += 1
r1.next = r1
- self.gc.rawrefcount_buffer_pyobj(r1addr)
+ self._rawrefcount_buffer_obj(r1)
self.gc.rrc_collect_cycles()
- assert r1.base.c_ob_refcnt == 2
+ assert r1.base.c_ob_refcnt & REFCNT_MASK == 2
+
+ def test_simple_cycle_free(self):
+ self.gc.rawrefcount_init(lambda: self.trigger.append(1))
+ r1 = self._rawrefcount_cycle_obj()
+ r2 = self._rawrefcount_cycle_obj()
+ r1.next = r2
+ r2.next = r1
+ self._rawrefcount_buffer_obj(r1)
+ self.gc.rrc_collect_cycles()
+ assert r1.base.c_ob_refcnt & REFCNT_MASK == 0
+ assert r2.base.c_ob_refcnt & REFCNT_MASK == 0
+
+ def test_simple_cycle_not_free(self):
+ self.gc.rawrefcount_init(lambda: self.trigger.append(1))
+ r1 = self._rawrefcount_cycle_obj()
+ r2 = self._rawrefcount_cycle_obj()
+ r1.next = r2
+ r2.next = r1
+ r2.base.c_ob_refcnt += 1
+ self._rawrefcount_buffer_obj(r1)
+ self.gc.rrc_collect_cycles()
+ assert r1.base.c_ob_refcnt & REFCNT_MASK == 1
+ assert r2.base.c_ob_refcnt & REFCNT_MASK == 2
+
+ def test_complex_cycle_free(self):
+ self.gc.rawrefcount_init(lambda: self.trigger.append(1))
+ r1 = self._rawrefcount_cycle_obj()
+ r2 = self._rawrefcount_cycle_obj()
+ r3 = self._rawrefcount_cycle_obj()
+ r1.next = r2
+ r1.prev = r2
+ r2.base.c_ob_refcnt += 1
+ r2.next = r3
+ r3.prev = r1
+ self._rawrefcount_buffer_obj(r1)
+ self.gc.rrc_collect_cycles()
+ assert r1.base.c_ob_refcnt & REFCNT_MASK == 0
+ assert r2.base.c_ob_refcnt & REFCNT_MASK == 0
+ assert r3.base.c_ob_refcnt & REFCNT_MASK == 0
+
+ def test_complex_cycle_not_free(self):
+ self.gc.rawrefcount_init(lambda: self.trigger.append(1))
+ r1 = self._rawrefcount_cycle_obj()
+ r2 = self._rawrefcount_cycle_obj()
+ r3 = self._rawrefcount_cycle_obj()
+ r1.next = r2
+ r1.prev = r2
+ r2.base.c_ob_refcnt += 1
+ r2.next = r3
+ r3.prev = r1
+ r3.base.c_ob_refcnt += 1
+ self._rawrefcount_buffer_obj(r1)
+ self.gc.rrc_collect_cycles()
+ assert r1.base.c_ob_refcnt & REFCNT_MASK == 1
+ assert r2.base.c_ob_refcnt & REFCNT_MASK == 2
+ assert r3.base.c_ob_refcnt & REFCNT_MASK == 2
+
+ def test_cycle_2_buffered_free(self):
+ self.gc.rawrefcount_init(lambda: self.trigger.append(1))
+ r1 = self._rawrefcount_cycle_obj()
+ r2 = self._rawrefcount_cycle_obj()
+ r1.next = r2
+ r2.prev = r1
+ self._rawrefcount_buffer_obj(r1)
+ self._rawrefcount_buffer_obj(r2)
+ self.gc.rrc_collect_cycles()
+ assert r1.base.c_ob_refcnt & REFCNT_MASK == 0
+ assert r2.base.c_ob_refcnt & REFCNT_MASK == 0
+
+ def test_cycle_2_buffered_not_free(self):
+ self.gc.rawrefcount_init(lambda: self.trigger.append(1))
+ r1 = self._rawrefcount_cycle_obj()
+ r2 = self._rawrefcount_cycle_obj()
+ r1.next = r2
+ r2.prev = r1
+ r1.base.c_ob_refcnt += 1
+ self._rawrefcount_buffer_obj(r1)
+ self._rawrefcount_buffer_obj(r2)
+ self.gc.rrc_collect_cycles()
+ assert r1.base.c_ob_refcnt & REFCNT_MASK == 2
+ assert r2.base.c_ob_refcnt & REFCNT_MASK == 1
+
More information about the pypy-commit
mailing list