1
0
mirror of https://github.com/ARM-software/devlib.git synced 2025-09-23 12:21:54 +01:00

target: Create new connection for reentrant calls

When Target.conn property is required while the current connection is
already in use, provide a fresh connection to avoid deadlocks. This is
enabled by the @call_conn decorator that is used on all Target methods
that use self.conn directly.
This commit is contained in:
douglas-raillard-arm
2021-05-12 16:46:40 +01:00
committed by Marc Bonnici
parent 796536d67d
commit 79783fa09a
2 changed files with 105 additions and 1 deletions

View File

@@ -37,6 +37,7 @@ import string
import subprocess
import sys
import threading
import types
import wrapt
import warnings
@@ -883,10 +884,14 @@ class _BoundTLSProperty:
class InitCheckpointMeta(type):
"""
Metaclass providing an ``initialized`` boolean attributes on instances.
Metaclass providing an ``initialized`` and ``is_in_use`` boolean attributes
on instances.
``initialized`` is set to ``True`` once the ``__init__`` constructor has
returned. It will deal cleanly with nested calls to ``super().__init__``.
``is_in_use`` is set to ``True`` when an instance method is being called.
This allows to detect reentrance.
"""
def __new__(metacls, name, bases, dct, **kwargs):
cls = super().__new__(metacls, name, bases, dct, **kwargs)
@@ -895,6 +900,7 @@ class InitCheckpointMeta(type):
@wraps(init_f)
def init_wrapper(self, *args, **kwargs):
self.initialized = False
self.is_in_use = False
# Track the nesting of super()__init__ to set initialized=True only
# when the outer level is finished
@@ -918,6 +924,45 @@ class InitCheckpointMeta(type):
cls.__init__ = init_wrapper
# Set the is_in_use attribute to allow external code to detect if the
# methods are about to be re-entered.
def make_wrapper(f):
if f is None:
return None
@wraps(f)
def wrapper(self, *args, **kwargs):
f_ = f.__get__(self, self.__class__)
initial_state = self.is_in_use
try:
self.is_in_use = True
return f_(*args, **kwargs)
finally:
self.is_in_use = initial_state
return wrapper
# This will not decorate methods defined in base classes, but we cannot
# use inspect.getmembers() as it uses __get__ to bind the attributes to
# the class, making staticmethod indistinguishible from instance
# methods.
for name, attr in cls.__dict__.items():
# Only wrap the methods (exposed as functions), not things like
# classmethod or staticmethod
if (
name not in ('__init__', '__new__') and
isinstance(attr, types.FunctionType)
):
setattr(cls, name, make_wrapper(attr))
elif isinstance(attr, property):
prop = property(
fget=make_wrapper(attr.fget),
fset=make_wrapper(attr.fset),
fdel=make_wrapper(attr.fdel),
doc=attr.__doc__,
)
setattr(cls, name, prop)
return cls