Author: Amaury Forgeot d'Arc <amaur...@gmail.com> Branch: Changeset: r2681:4d19ce180883 Date: 2016-04-23 11:02 +0200 http://bitbucket.org/cffi/cffi/changeset/4d19ce180883/
Log: Add ffi.gc(ptr, None) which *removes* the destructor in-place on a ffi.gc() object. diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -6065,6 +6065,17 @@ &CData_Type, &origobj, &destructor)) return NULL; + if (destructor == Py_None) { + if (!PyObject_TypeCheck(origobj, &CDataGCP_Type)) { + PyErr_SetString(PyExc_TypeError, + "Can remove destructor only on a object " + "previously returned by ffi.gc()"); + return NULL; + } + Py_CLEAR(((CDataObject_gcp *)origobj)->destructor); + Py_RETURN_NONE; + } + cd = allocate_gcp_object(origobj, origobj->c_type, destructor); return (PyObject *)cd; } diff --git a/cffi/backend_ctypes.py b/cffi/backend_ctypes.py --- a/cffi/backend_ctypes.py +++ b/cffi/backend_ctypes.py @@ -995,13 +995,23 @@ def gcp(self, cdata, destructor): BType = self.typeof(cdata) + + if destructor is None: + if not (hasattr(BType, '_gcp_type') and + BType._gcp_type is BType): + raise TypeError("Can remove destructor only on a object " + "previously returned by ffi.gc()") + cdata._destructor = None + return None + try: gcp_type = BType._gcp_type except AttributeError: class CTypesDataGcp(BType): __slots__ = ['_orig', '_destructor'] def __del__(self): - self._destructor(self._orig) + if self._destructor is not None: + self._destructor(self._orig) gcp_type = BType._gcp_type = CTypesDataGcp new_cdata = self.cast(gcp_type, cdata) new_cdata._orig = cdata diff --git a/doc/source/ref.rst b/doc/source/ref.rst --- a/doc/source/ref.rst +++ b/doc/source/ref.rst @@ -318,6 +318,11 @@ which means the destructor is called as soon as *this* exact returned object is garbage-collected. +**ffi.gc(ptr, None)**: removes the ownership on a object returned by a +regular call to ``ffi.gc``, and no destructor will be called when it +is garbage-collected. The object is modified in-place, and the +function returns ``None``. + Note that this should be avoided for large memory allocations or for limited resources. This is particularly true on PyPy: its GC does not know how much memory or how many resources the returned ``ptr`` diff --git a/doc/source/whatsnew.rst b/doc/source/whatsnew.rst --- a/doc/source/whatsnew.rst +++ b/doc/source/whatsnew.rst @@ -3,6 +3,13 @@ ====================== +v1.next +======= + +* ``ffi.gc(p, None)`` removes the destructor on an object previously + created by another call to ``ffi.gc()`` + + v1.6 ==== diff --git a/testing/cffi0/backend_tests.py b/testing/cffi0/backend_tests.py --- a/testing/cffi0/backend_tests.py +++ b/testing/cffi0/backend_tests.py @@ -1522,6 +1522,20 @@ import gc; gc.collect(); gc.collect(); gc.collect() assert seen == [3] + def test_gc_disable(self): + ffi = FFI(backend=self.Backend()) + p = ffi.new("int *", 123) + py.test.raises(TypeError, ffi.gc, p, None) + seen = [] + q1 = ffi.gc(p, lambda p: seen.append(1)) + q2 = ffi.gc(q1, lambda p: seen.append(2)) + import gc; gc.collect() + assert seen == [] + assert ffi.gc(q1, None) is None + del q1, q2 + import gc; gc.collect(); gc.collect(); gc.collect() + assert seen == [2] + def test_gc_finite_list(self): ffi = FFI(backend=self.Backend()) p = ffi.new("int *", 123) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit