Author: Armin Rigo <[email protected]>
Branch: cffi-1.0
Changeset: r77248:38f5a771c73d
Date: 2015-05-09 13:18 +0200
http://bitbucket.org/pypy/pypy/changeset/38f5a771c73d/

Log:    ffi.gc()

diff --git a/pypy/module/_cffi_backend/cgc.py b/pypy/module/_cffi_backend/cgc.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/cgc.py
@@ -0,0 +1,29 @@
+from rpython.rlib import jit
+
+
[email protected]_look_inside
+def gc_weakrefs_build(ffi, w_cdata, w_destructor):
+    from pypy.module._weakref import interp__weakref
+
+    space = ffi.space
+    if ffi.w_gc_wref_remove is None:
+        ffi.gc_wref_dict = {}
+        ffi.w_gc_wref_remove = space.getattr(space.wrap(ffi),
+                                             space.wrap("__gc_wref_remove"))
+
+    w_new_cdata = w_cdata.ctype.cast(w_cdata)
+    assert w_new_cdata is not w_cdata
+
+    w_ref = interp__weakref.make_weakref_with_callback(
+        space,
+        space.gettypefor(interp__weakref.W_Weakref),
+        w_new_cdata,
+        ffi.w_gc_wref_remove)
+
+    ffi.gc_wref_dict[w_ref] = (w_destructor, w_cdata)
+    return w_new_cdata
+
+
+def gc_wref_remove(ffi, w_ref):
+    (w_destructor, w_cdata) = ffi.gc_wref_dict.pop(w_ref)
+    ffi.space.call_function(w_destructor, w_cdata)
diff --git a/pypy/module/_cffi_backend/ffi_obj.py 
b/pypy/module/_cffi_backend/ffi_obj.py
--- a/pypy/module/_cffi_backend/ffi_obj.py
+++ b/pypy/module/_cffi_backend/ffi_obj.py
@@ -8,7 +8,7 @@
 from pypy.module._cffi_backend import parse_c_type, realize_c_type
 from pypy.module._cffi_backend import newtype, cerrno, ccallback, ctypearray
 from pypy.module._cffi_backend import ctypestruct, ctypeptr, handle
-from pypy.module._cffi_backend import cbuffer, func
+from pypy.module._cffi_backend import cbuffer, func, cgc
 from pypy.module._cffi_backend.ctypeobj import W_CType
 from pypy.module._cffi_backend.cdataobj import W_CData
 
@@ -34,6 +34,7 @@
 
 
 class W_FFIObject(W_Root):
+    w_gc_wref_remove = None
 
     @jit.dont_look_inside
     def __init__(self, space, src_ctx):
@@ -244,6 +245,19 @@
         return handle.from_handle(self.space, w_arg)
 
 
+    @unwrap_spec(w_cdata=W_CData)
+    def descr_gc(self, w_cdata, w_destructor):
+        """\
+Return a new cdata object that points to the same data.
+Later, when this new cdata object is garbage-collected,
+'destructor(old_cdata_object)' will be called."""
+        #
+        return cgc.gc_weakrefs_build(self, w_cdata, w_destructor)
+
+    def descr___gc_wref_remove(self, w_ref):
+        return cgc.gc_wref_remove(self, w_ref)
+
+
     @unwrap_spec(replace_with=str)
     def descr_getctype(self, w_cdecl, replace_with=''):
         """\
@@ -416,6 +430,7 @@
                                      W_FFIObject.set_errno,
                                      doc=W_FFIObject.doc_errno,
                                      cls=W_FFIObject),
+        __gc_wref_remove = interp2app(W_FFIObject.descr___gc_wref_remove),
         addressof   = interp2app(W_FFIObject.descr_addressof),
         alignof     = interp2app(W_FFIObject.descr_alignof),
         buffer      = interp2app(W_FFIObject.descr_buffer),
@@ -423,7 +438,7 @@
         cast        = interp2app(W_FFIObject.descr_cast),
         from_buffer = interp2app(W_FFIObject.descr_from_buffer),
         from_handle = interp2app(W_FFIObject.descr_from_handle),
-        #gc          = interp2app(W_FFIObject.descr_gc),
+        gc          = interp2app(W_FFIObject.descr_gc),
         getctype    = interp2app(W_FFIObject.descr_getctype),
         #getwinerror = interp2app(W_FFIObject.descr_getwinerror),
         new         = interp2app(W_FFIObject.descr_new),
diff --git a/pypy/module/_cffi_backend/test/test_ffi_obj.py 
b/pypy/module/_cffi_backend/test/test_ffi_obj.py
--- a/pypy/module/_cffi_backend/test/test_ffi_obj.py
+++ b/pypy/module/_cffi_backend/test/test_ffi_obj.py
@@ -205,3 +205,20 @@
         ffi = _cffi1_backend.FFI()
         assert isinstance(ffi.cast("int", 42), CData)
         assert isinstance(ffi.typeof("int"), CType)
+
+    def test_ffi_gc(self):
+        import _cffi_backend as _cffi1_backend
+        ffi = _cffi1_backend.FFI()
+        p = ffi.new("int *", 123)
+        seen = []
+        def destructor(p1):
+            assert p1 is p
+            assert p1[0] == 123
+            seen.append(1)
+        ffi.gc(p, destructor=destructor)    # instantly forgotten
+        for i in range(5):
+            if seen:
+                break
+            import gc
+            gc.collect()
+        assert seen == [1]
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to