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 <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
This commit is contained in:
zolliker 2022-04-11 16:21:09 +02:00
parent 7891c281e1
commit a35134978a
3 changed files with 9 additions and 6 deletions

View File

@ -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()

View File

@ -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

View File

@ -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())