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
|
import time
|
||||||
from queue import Queue, Empty
|
from queue import Queue, Empty
|
||||||
|
import threading
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
@ -136,6 +137,7 @@ class HasAccessibles(HasProperties):
|
|||||||
|
|
||||||
@wraps(rfunc) # handles __wrapped__ and __doc__
|
@wraps(rfunc) # handles __wrapped__ and __doc__
|
||||||
def new_rfunc(self, pname=pname, rfunc=rfunc):
|
def new_rfunc(self, pname=pname, rfunc=rfunc):
|
||||||
|
with self.accessLock:
|
||||||
try:
|
try:
|
||||||
value = rfunc(self)
|
value = rfunc(self)
|
||||||
self.log.debug("read_%s returned %r", pname, value)
|
self.log.debug("read_%s returned %r", pname, value)
|
||||||
@ -175,6 +177,7 @@ class HasAccessibles(HasProperties):
|
|||||||
|
|
||||||
@wraps(wfunc) # handles __wrapped__ and __doc__
|
@wraps(wfunc) # handles __wrapped__ and __doc__
|
||||||
def new_wfunc(self, value, pname=pname, wfunc=wfunc):
|
def new_wfunc(self, value, pname=pname, wfunc=wfunc):
|
||||||
|
with self.accessLock:
|
||||||
pobj = self.accessibles[pname]
|
pobj = self.accessibles[pname]
|
||||||
self.log.debug('validate %r for %r', value, pname)
|
self.log.debug('validate %r for %r', value, pname)
|
||||||
# we do not need to handle errors here, we do not
|
# we do not need to handle errors here, we do not
|
||||||
@ -293,6 +296,7 @@ class Module(HasAccessibles):
|
|||||||
self.startModuleDone = False
|
self.startModuleDone = False
|
||||||
self.remoteLogHandler = None
|
self.remoteLogHandler = None
|
||||||
self.changePollinterval = Queue() # used for waiting between polls and transmit info to the thread
|
self.changePollinterval = Queue() # used for waiting between polls and transmit info to the thread
|
||||||
|
self.accessLock = threading.RLock()
|
||||||
errors = []
|
errors = []
|
||||||
|
|
||||||
# handle module properties
|
# handle module properties
|
||||||
@ -468,6 +472,7 @@ class Module(HasAccessibles):
|
|||||||
def announceUpdate(self, pname, value=None, err=None, timestamp=None):
|
def announceUpdate(self, pname, value=None, err=None, timestamp=None):
|
||||||
"""announce a changed value or readerror"""
|
"""announce a changed value or readerror"""
|
||||||
|
|
||||||
|
with self.accessLock:
|
||||||
# TODO: remove readerror 'property' and replace value with exception
|
# TODO: remove readerror 'property' and replace value with exception
|
||||||
pobj = self.parameters[pname]
|
pobj = self.parameters[pname]
|
||||||
timestamp = timestamp or time.time()
|
timestamp = timestamp or time.time()
|
||||||
@ -486,7 +491,7 @@ class Module(HasAccessibles):
|
|||||||
if err:
|
if err:
|
||||||
err = secop_error(err)
|
err = secop_error(err)
|
||||||
if str(err) == str(pobj.readerror):
|
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:
|
elif not changed and timestamp < (pobj.timestamp or 0) + self.omit_unchanged_within:
|
||||||
# no change within short time -> omit
|
# no change within short time -> omit
|
||||||
return
|
return
|
||||||
|
@ -127,6 +127,7 @@ class ReadHandler(Handler):
|
|||||||
|
|
||||||
def wrap(self, key):
|
def wrap(self, key):
|
||||||
def method(module, pname=key, func=self.func):
|
def method(module, pname=key, func=self.func):
|
||||||
|
with module.accessLock:
|
||||||
value = func(module, pname)
|
value = func(module, pname)
|
||||||
if value is Done:
|
if value is Done:
|
||||||
return getattr(module, pname)
|
return getattr(module, pname)
|
||||||
@ -148,6 +149,7 @@ class CommonReadHandler(ReadHandler):
|
|||||||
|
|
||||||
def wrap(self, key):
|
def wrap(self, key):
|
||||||
def method(module, pname=key, func=self.func):
|
def method(module, pname=key, func=self.func):
|
||||||
|
with module.accessLock:
|
||||||
ret = func(module)
|
ret = func(module)
|
||||||
if ret not in (None, Done):
|
if ret not in (None, Done):
|
||||||
raise ProgrammingError('a method wrapped with CommonReadHandler must not return any value')
|
raise ProgrammingError('a method wrapped with CommonReadHandler must not return any value')
|
||||||
@ -165,6 +167,7 @@ class WriteHandler(Handler):
|
|||||||
def wrap(self, key):
|
def wrap(self, key):
|
||||||
@wraps(self.func)
|
@wraps(self.func)
|
||||||
def method(module, value, pname=key, func=self.func):
|
def method(module, value, pname=key, func=self.func):
|
||||||
|
with module.accessLock:
|
||||||
value = func(module, pname, value)
|
value = func(module, pname, value)
|
||||||
if value is not Done:
|
if value is not Done:
|
||||||
setattr(module, pname, value)
|
setattr(module, pname, value)
|
||||||
@ -201,6 +204,7 @@ class CommonWriteHandler(WriteHandler):
|
|||||||
def wrap(self, key):
|
def wrap(self, key):
|
||||||
@wraps(self.func)
|
@wraps(self.func)
|
||||||
def method(module, value, pname=key, func=self.func):
|
def method(module, value, pname=key, func=self.func):
|
||||||
|
with module.accessLock:
|
||||||
values = WriteParameters(module)
|
values = WriteParameters(module)
|
||||||
values[pname] = value
|
values[pname] = value
|
||||||
ret = func(module, values)
|
ret = func(module, values)
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
# content of conftest.py
|
# content of conftest.py
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
from secop.lib import generalConfig
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="session", autouse=True)
|
||||||
|
def general_config():
|
||||||
|
generalConfig.testinit()
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user