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

Reply via email to