diff options
author | Armin Rigo <arigo@tunes.org> | 2017-06-15 10:19:26 +0200 |
---|---|---|
committer | Armin Rigo <arigo@tunes.org> | 2017-06-15 10:19:26 +0200 |
commit | 6be5300516f261cd3b8a11cc3a64146c11b75f67 (patch) | |
tree | 35ddf92a64e870e5e70d225ff786147548392b10 /cffi/model.py | |
parent | 737f2cac34bc9387d9ca99e9ccfedbbe316afcf5 (diff) | |
download | cffi-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.py | 24 |
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: |