avoid race conditions in read_*/write_* methods

using one RLock per Module
+ init generalConfig for all tests

Change-Id: I88db6cacdb4aaac2ecd56644ccd6a3e5fd2d1cf2
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/28005
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
This commit is contained in:
zolliker 2022-03-03 15:42:29 +01:00
parent 9858973ba1
commit 16a9550080
3 changed files with 95 additions and 80 deletions

View File

@ -25,6 +25,7 @@
import time
from queue import Queue, Empty
import threading
from collections import OrderedDict
from functools import wraps
@ -136,6 +137,7 @@ class HasAccessibles(HasProperties):
@wraps(rfunc) # handles __wrapped__ and __doc__
def new_rfunc(self, pname=pname, rfunc=rfunc):
with self.accessLock:
try:
value = rfunc(self)
self.log.debug("read_%s returned %r", pname, value)
@ -175,6 +177,7 @@ class HasAccessibles(HasProperties):
@wraps(wfunc) # handles __wrapped__ and __doc__
def new_wfunc(self, value, pname=pname, wfunc=wfunc):
with self.accessLock:
pobj = self.accessibles[pname]
self.log.debug('validate %r for %r', value, pname)
# we do not need to handle errors here, we do not
@ -293,6 +296,7 @@ class Module(HasAccessibles):
self.startModuleDone = False
self.remoteLogHandler = None
self.changePollinterval = Queue() # used for waiting between polls and transmit info to the thread
self.accessLock = threading.RLock()
errors = []
# handle module properties
@ -468,6 +472,7 @@ class Module(HasAccessibles):
def announceUpdate(self, pname, value=None, err=None, timestamp=None):
"""announce a changed value or readerror"""
with self.accessLock:
# TODO: remove readerror 'property' and replace value with exception
pobj = self.parameters[pname]
timestamp = timestamp or time.time()
@ -486,7 +491,7 @@ class Module(HasAccessibles):
if err:
err = secop_error(err)
if str(err) == str(pobj.readerror):
return # do call updates for repeated errors
return # no updates for repeated errors
elif not changed and timestamp < (pobj.timestamp or 0) + self.omit_unchanged_within:
# no change within short time -> omit
return

View File

@ -127,6 +127,7 @@ class ReadHandler(Handler):
def wrap(self, key):
def method(module, pname=key, func=self.func):
with module.accessLock:
value = func(module, pname)
if value is Done:
return getattr(module, pname)
@ -148,6 +149,7 @@ class CommonReadHandler(ReadHandler):
def wrap(self, key):
def method(module, pname=key, func=self.func):
with module.accessLock:
ret = func(module)
if ret not in (None, Done):
raise ProgrammingError('a method wrapped with CommonReadHandler must not return any value')
@ -165,6 +167,7 @@ class WriteHandler(Handler):
def wrap(self, key):
@wraps(self.func)
def method(module, value, pname=key, func=self.func):
with module.accessLock:
value = func(module, pname, value)
if value is not Done:
setattr(module, pname, value)
@ -201,6 +204,7 @@ class CommonWriteHandler(WriteHandler):
def wrap(self, key):
@wraps(self.func)
def method(module, value, pname=key, func=self.func):
with module.accessLock:
values = WriteParameters(module)
values[pname] = value
ret = func(module, values)

View File

@ -1,6 +1,12 @@
# content of conftest.py
import pytest
from secop.lib import generalConfig
@pytest.fixture(scope="session", autouse=True)
def general_config():
generalConfig.testinit()
@pytest.fixture(scope="module")