Author: Amaury Forgeot d'Arc <[email protected]>
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
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit