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:
parent
9858973ba1
commit
16a9550080
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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")
|
||||
|
Loading…
x
Reference in New Issue
Block a user