Author: Armin Rigo <ar...@tunes.org>
Branch: 
Changeset: r2685:381f8b0c2ee0
Date: 2016-04-24 13:46 +0200
http://bitbucket.org/cffi/cffi/changeset/381f8b0c2ee0/

Log:    merge heads

diff --git a/AUTHORS b/AUTHORS
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,3 +1,8 @@
 This package has been mostly done by Armin Rigo with help from
 Maciej Fija&#322;kowski. The idea is heavily based (although not directly
 copied) from LuaJIT ffi by Mike Pall.
+
+
+Other contributors:
+
+  Google Inc.
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/api.py b/cffi/api.py
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -397,20 +397,7 @@
         data.  Later, when this new cdata object is garbage-collected,
         'destructor(old_cdata_object)' will be called.
         """
-        try:
-            gcp = self._backend.gcp
-        except AttributeError:
-            pass
-        else:
-            return gcp(cdata, destructor)
-        #
-        with self._lock:
-            try:
-                gc_weakrefs = self.gc_weakrefs
-            except AttributeError:
-                from .gc_weakref import GcWeakrefs
-                gc_weakrefs = self.gc_weakrefs = GcWeakrefs(self)
-            return gc_weakrefs.build(cdata, destructor)
+        return self._backend.gcp(cdata, destructor)
 
     def _get_cached_btype(self, type):
         assert self._lock.acquire(False) is False
diff --git a/cffi/backend_ctypes.py b/cffi/backend_ctypes.py
--- a/cffi/backend_ctypes.py
+++ b/cffi/backend_ctypes.py
@@ -993,6 +993,31 @@
         assert onerror is None   # XXX not implemented
         return BType(source, error)
 
+    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):
+                    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
+        new_cdata._destructor = destructor
+        return new_cdata
+
     typeof = type
 
     def getcname(self, BType, replace_with):
diff --git a/cffi/gc_weakref.py b/cffi/gc_weakref.py
deleted file mode 100644
--- a/cffi/gc_weakref.py
+++ /dev/null
@@ -1,22 +0,0 @@
-from weakref import ref
-
-
-class GcWeakrefs(object):
-    def __init__(self, ffi):
-        self.ffi = ffi
-        self.data = {}
-
-    def build(self, cdata, destructor):
-        # make a new cdata of the same type as the original one
-        new_cdata = self.ffi.cast(self.ffi._backend.typeof(cdata), cdata)
-        #
-        def remove(key):
-            # careful, this function is not protected by any lock
-            old_key = self.data.pop(index)
-            assert old_key is key
-            destructor(cdata)
-        #
-        key = ref(new_cdata, remove)
-        index = object()
-        self.data[index] = key
-        return new_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,21 +1522,30 @@
         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())
-        public = not hasattr(ffi._backend, 'gcp')
         p = ffi.new("int *", 123)
         keepalive = []
         for i in range(10):
             keepalive.append(ffi.gc(p, lambda p: None))
-            if public:
-                assert len(ffi.gc_weakrefs.data) == i + 1
         del keepalive[:]
         import gc; gc.collect(); gc.collect()
         for i in range(10):
             keepalive.append(ffi.gc(p, lambda p: None))
-        if public:
-            assert len(ffi.gc_weakrefs.data) == 10
 
     def test_CData_CType(self):
         ffi = FFI(backend=self.Backend())
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to