summaryrefslogtreecommitdiff
path: root/cffi/model.py
diff options
context:
space:
mode:
authorArmin Rigo <arigo@tunes.org>2017-06-15 10:19:26 +0200
committerArmin Rigo <arigo@tunes.org>2017-06-15 10:19:26 +0200
commit6be5300516f261cd3b8a11cc3a64146c11b75f67 (patch)
tree35ddf92a64e870e5e70d225ff786147548392b10 /cffi/model.py
parent737f2cac34bc9387d9ca99e9ccfedbbe316afcf5 (diff)
downloadcffi-6be5300516f261cd3b8a11cc3a64146c11b75f67.tar.gz
Issue #319
Fix a race condition: we can't stick an attribute to ffi._backend, because another thread might be in the middle of ``for name in ffi._backend.__dict__``. To minimize damage if I reintroduce an attribute-adding function in the future, also tweak the ``for``.
Diffstat (limited to 'cffi/model.py')
-rw-r--r--cffi/model.py24
1 files changed, 14 insertions, 10 deletions
diff --git a/cffi/model.py b/cffi/model.py
index af0b6df..fb30f7d 100644
--- a/cffi/model.py
+++ b/cffi/model.py
@@ -568,22 +568,26 @@ def unknown_ptr_type(name, structname=None):
global_lock = allocate_lock()
+_typecache_cffi_backend = weakref.WeakValueDictionary()
+
+def get_typecache(backend):
+ # returns _typecache_cffi_backend if backend is the _cffi_backend
+ # module, or type(backend).__typecache if backend is an instance of
+ # CTypesBackend (or some FakeBackend class during tests)
+ if isinstance(backend, types.ModuleType):
+ return _typecache_cffi_backend
+ with global_lock:
+ if not hasattr(type(backend), '__typecache'):
+ type(backend).__typecache = weakref.WeakValueDictionary()
+ return type(backend).__typecache
def global_cache(srctype, ffi, funcname, *args, **kwds):
key = kwds.pop('key', (funcname, args))
assert not kwds
try:
- return ffi._backend.__typecache[key]
+ return ffi._typecache[key]
except KeyError:
pass
- except AttributeError:
- # initialize the __typecache attribute, either at the module level
- # if ffi._backend is a module, or at the class level if ffi._backend
- # is some instance.
- if isinstance(ffi._backend, types.ModuleType):
- ffi._backend.__typecache = weakref.WeakValueDictionary()
- else:
- type(ffi._backend).__typecache = weakref.WeakValueDictionary()
try:
res = getattr(ffi._backend, funcname)(*args)
except NotImplementedError as e:
@@ -591,7 +595,7 @@ def global_cache(srctype, ffi, funcname, *args, **kwds):
# note that setdefault() on WeakValueDictionary is not atomic
# and contains a rare bug (http://bugs.python.org/issue19542);
# we have to use a lock and do it ourselves
- cache = ffi._backend.__typecache
+ cache = ffi._typecache
with global_lock:
res1 = cache.get(key)
if res1 is None: