From a35134978ad951afb6eb9236d3f46b6172045865 Mon Sep 17 00:00:00 2001 From: Markus Zolliker Date: Mon, 11 Apr 2022 16:21:09 +0200 Subject: [PATCH] avoid deadlock in proxy in secop.proxy the callers modules method announceUpdate is called from an other thread while the accessLock is locked, creating a deadlock. solve this by creating an other lock 'updateLock' for the update. + add status parameter even to non-Readable proxy modules, in order to indicate a failed connection + fix an error in secop_psi/softcal.py Change-Id: Iae7c6d5a74001150a47aa9dc99209c15d972cd5e Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/28130 Tested-by: Jenkins Automated Tests Reviewed-by: Enrico Faulhaber Reviewed-by: Markus Zolliker --- secop/modules.py | 5 +++-- secop/proxy.py | 6 ++++-- secop_psi/softcal.py | 4 ++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/secop/modules.py b/secop/modules.py index c3d625c..883815f 100644 --- a/secop/modules.py +++ b/secop/modules.py @@ -318,7 +318,8 @@ class Module(HasAccessibles): self.initModuleDone = False self.startModuleDone = False self.remoteLogHandler = None - self.accessLock = threading.RLock() + self.accessLock = threading.RLock() # for read_* / write_* methods + self.updateLock = threading.RLock() # for announceUpdate self.polledModules = [] # modules polled by thread started in self.startModules errors = [] @@ -495,7 +496,7 @@ class Module(HasAccessibles): def announceUpdate(self, pname, value=None, err=None, timestamp=None): """announce a changed value or readerror""" - with self.accessLock: + with self.updateLock: # TODO: remove readerror 'property' and replace value with exception pobj = self.parameters[pname] timestamp = timestamp or time.time() diff --git a/secop/proxy.py b/secop/proxy.py index 2c25838..b372c82 100644 --- a/secop/proxy.py +++ b/secop/proxy.py @@ -33,6 +33,7 @@ from secop.io import HasIO class ProxyModule(HasIO, Module): module = Property('remote module name', datatype=StringType(), default='') + status = Parameter('connection status', Readable.status.datatype) # add status even when not a Readable _consistency_check_done = False _secnode = None @@ -182,11 +183,12 @@ def proxy_class(remote_class, name=None): for aname, aobj in rcls.accessibles.items(): if isinstance(aobj, Parameter): - pobj = aobj.merge(dict(handler=None, needscfg=False)) + pobj = aobj.copy() + pobj.merge(dict(handler=None, needscfg=False)) attrs[aname] = pobj def rfunc(self, pname=aname): - value, _, readerror = self._secnode.getParameter(self.name, pname) + value, _, readerror = self._secnode.getParameter(self.name, pname, True) if readerror: raise readerror return value diff --git a/secop_psi/softcal.py b/secop_psi/softcal.py index 8095cbf..530c7be 100644 --- a/secop_psi/softcal.py +++ b/secop_psi/softcal.py @@ -191,7 +191,7 @@ class Sensor(Readable): def initModule(self): super().initModule() - self._rawsensor.registerCallbacks(self, ['status']) # auto update status + self.rawsensor.registerCallbacks(self, ['status']) # auto update status self._calib = CalCurve(self.calib) if self.description == '_': self.description = '%r calibrated with curve %r' % (self.rawsensor, self.calib) @@ -220,4 +220,4 @@ class Sensor(Readable): self.status = self.Status.ERROR, self._value_error def read_value(self): - return self._calib(self._rawsensor.read_value()) + return self._calib(self.rawsensor.read_value())