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
