[pypy-commit] cffi default: Keep the loaded libraries alive as long as the 'ffi' object is kept alive.

arigo noreply at buildbot.pypy.org
Tue Oct 9 11:20:38 CEST 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r990:a4f49af3db3c
Date: 2012-10-09 11:18 +0200
http://bitbucket.org/cffi/cffi/changeset/a4f49af3db3c/

Log:	Keep the loaded libraries alive as long as the 'ffi' object is kept
	alive.

diff --git a/cffi/api.py b/cffi/api.py
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -50,6 +50,7 @@
         self._parsed_types = types.ModuleType('parsed_types').__dict__
         self._new_types = types.ModuleType('new_types').__dict__
         self._function_caches = []
+        self._libraries = []
         self._cdefsources = []
         self._pointer_type_cache = {}
         if hasattr(backend, 'set_ffi'):
@@ -97,6 +98,7 @@
         assert isinstance(name, str) or name is None
         lib, function_cache = _make_ffi_library(self, name, flags)
         self._function_caches.append(function_cache)
+        self._libraries.append(lib)
         return lib
 
     def _typeof(self, cdecl, consider_function_as_funcptr=False):
@@ -281,7 +283,9 @@
         from .verifier import Verifier, _caller_dir_pycache
         tmpdir = tmpdir or _caller_dir_pycache()
         self.verifier = Verifier(self, source, tmpdir, **kwargs)
-        return self.verifier.load_library()
+        lib = self.verifier.load_library()
+        self._libraries.append(lib)
+        return lib
 
     def _get_errno(self):
         return self._backend.get_errno()
diff --git a/cffi/vengine_cpy.py b/cffi/vengine_cpy.py
--- a/cffi/vengine_cpy.py
+++ b/cffi/vengine_cpy.py
@@ -140,6 +140,7 @@
         # pointers, and store them as attributes on the 'library' object.
         class FFILibrary(object):
             _cffi_python_module = module
+            _cffi_ffi = self.ffi
         library = FFILibrary()
         module._cffi_setup(lst, ffiplatform.VerificationError, library)
         #
diff --git a/cffi/vengine_gen.py b/cffi/vengine_gen.py
--- a/cffi/vengine_gen.py
+++ b/cffi/vengine_gen.py
@@ -53,6 +53,7 @@
         # build the FFILibrary class and instance
         class FFILibrary(object):
             _cffi_generic_module = module
+            _cffi_ffi = self.ffi
         library = FFILibrary()
         #
         # finally, call the loaded_gen_xxx() functions.  This will set
diff --git a/testing/test_ownlib.py b/testing/test_ownlib.py
--- a/testing/test_ownlib.py
+++ b/testing/test_ownlib.py
@@ -1,5 +1,5 @@
 import py, sys
-import subprocess
+import subprocess, weakref
 from cffi import FFI
 from cffi.backend_ctypes import CTypesBackend
 
@@ -98,3 +98,40 @@
         ownlib.my_array = list(range(7))
         for i in range(7):
             assert ownlib.my_array[i] == i
+
+    def test_keepalive_lib(self):
+        if sys.platform == 'win32':
+            py.test.skip("fix the auto-generation of the tiny test lib")
+        ffi = FFI(backend=self.Backend())
+        ffi.cdef("""
+            int test_getting_errno(void);
+        """)
+        ownlib = ffi.dlopen(self.module)
+        ffi_r = weakref.ref(ffi)
+        ownlib_r = weakref.ref(ownlib)
+        func = ownlib.test_getting_errno
+        del ffi
+        import gc; gc.collect()       # ownlib stays alive
+        assert ownlib_r() is not None
+        assert ffi_r() is not None    # kept alive by ownlib
+        res = func()
+        assert res == -1
+
+    def test_keepalive_ffi(self):
+        if sys.platform == 'win32':
+            py.test.skip("fix the auto-generation of the tiny test lib")
+        ffi = FFI(backend=self.Backend())
+        ffi.cdef("""
+            int test_getting_errno(void);
+        """)
+        ownlib = ffi.dlopen(self.module)
+        ffi_r = weakref.ref(ffi)
+        ownlib_r = weakref.ref(ownlib)
+        func = ownlib.test_getting_errno
+        del ownlib
+        import gc; gc.collect()       # ffi stays alive
+        assert ffi_r() is not None
+        assert ownlib_r() is not None # kept alive by ffi
+        res = func()
+        assert res == -1
+        assert ffi.errno == 123
diff --git a/testing/test_verify.py b/testing/test_verify.py
--- a/testing/test_verify.py
+++ b/testing/test_verify.py
@@ -1,5 +1,5 @@
 import py
-import sys, math
+import sys, math, weakref
 from cffi import FFI, VerificationError, VerificationMissing, model
 from testing.support import *
 
@@ -1192,3 +1192,29 @@
     g = subprocess.Popen([sys.executable, arg])
     result = g.wait()
     assert result == 0
+
+def test_keepalive_lib():
+    ffi = FFI()
+    ffi.cdef("int foobar(void);")
+    lib = ffi.verify("int foobar(void) { return 42; }")
+    func = lib.foobar
+    ffi_r = weakref.ref(ffi)
+    lib_r = weakref.ref(lib)
+    del ffi
+    import gc; gc.collect()       # lib stays alive
+    assert lib_r() is not None
+    assert ffi_r() is not None
+    assert func() == 42
+
+def test_keepalive_ffi():
+    ffi = FFI()
+    ffi.cdef("int foobar(void);")
+    lib = ffi.verify("int foobar(void) { return 42; }")
+    func = lib.foobar
+    ffi_r = weakref.ref(ffi)
+    lib_r = weakref.ref(lib)
+    del lib
+    import gc; gc.collect()       # ffi stays alive
+    assert ffi_r() is not None
+    assert lib_r() is not None
+    assert func() == 42


More information about the pypy-commit mailing list