Skip to content
Snippets Groups Projects
Commit 58f0da57 authored by Martin Killenberg's avatar Martin Killenberg
Browse files

wip: changed constructor of ExceptionHandlingDecorator to have a...

wip: changed constructor of ExceptionHandlingDecorator to have a VariableNetworkNode as argument instead of a bunch of details
parent b3a8233b
No related branches found
No related tags found
No related merge requests found
......@@ -20,14 +20,12 @@ namespace ChimeraTK {
class ExceptionHandlingDecorator : public ChimeraTK::NDRegisterAccessorDecorator<UserType> {
public:
/**
* Decorate the accessors which is handed in the constuctor. It needs the device module to implement
* the exception handling. Accessors which write to the device in addition need a recovery accessor
* so the variables can be written again after a device has recovered from an error. Accessors
* which only read don't specify the third parameter.
* Decorate the accessors which is handed in the constuctor.
* All information to get the DeviceModule and to create a recovery accessor are
* taken from the VariableNetworkNode.
*/
ExceptionHandlingDecorator(boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> accessor,
DeviceModule& devMod, VariableDirection direction,
boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> recoveryAccessor = {nullptr});
ExceptionHandlingDecorator(
boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> accessor, VariableNetworkNode networkNode);
void doPreWrite(TransferType type, VersionNumber versionNumber) override;
......@@ -47,16 +45,18 @@ namespace ChimeraTK {
using ChimeraTK::TransferElement::_dataValidity;
using ChimeraTK::TransferElement::_activeException;
DeviceModule& _deviceModule;
DeviceModule* _deviceModule;
bool previousReadFailed{true};
boost::shared_ptr<RecoveryHelper> _recoveryHelper{nullptr};
// store the recoveryAccessor separately. The RecoveryHelper only contains a pointer to TransferElement and can't be used to fill in data.
boost::shared_ptr<NDRegisterAccessor<UserType>> _recoveryAccessor{nullptr};
VariableDirection _direction;
bool _hasThrownToInhibitTransfer{false};
bool _hasThrownLogicError{false};
bool _dataLostInPreviousWrite{false};
};
......
......@@ -368,22 +368,7 @@ boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> Application::createDe
// obtain the register accessor from the device
auto accessor = deviceMap[deviceAlias]->getRegisterAccessor<UserType>(registerName, nElements, 0, flags);
assert(deviceModuleMap.count(deviceAlias) != 0);
DeviceModule* devmod = deviceModuleMap[deviceAlias];
// decorate the accessor with a ExceptionHandlingDecorator and return it
// Consuming from the network means writing to the device what you consumed.
if(direction.dir == VariableDirection::consuming) {
// writable registers additionally get a recoveryAccessor
// Notice: Don't use the fact that there is a recovery accessor to determine the direction in the ExceptionHandlingDecorator.
// There will be write-accessors without recovery accessors in future (intentionally turned off by the application programmer)
auto recoveryAccessor = deviceMap[deviceAlias]->getRegisterAccessor<UserType>(registerName, nElements, 0, flags);
return boost::make_shared<ExceptionHandlingDecorator<UserType>>(accessor, *devmod, direction, recoveryAccessor);
}
else {
return boost::make_shared<ExceptionHandlingDecorator<UserType>>(accessor, *devmod, direction);
}
return boost::make_shared<ExceptionHandlingDecorator<UserType>>(accessor, node);
}
/*********************************************************************************************************************/
......
......@@ -7,15 +7,31 @@ namespace ChimeraTK {
template<typename UserType>
ExceptionHandlingDecorator<UserType>::ExceptionHandlingDecorator(
boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> accessor, DeviceModule& devMod,
VariableDirection direction, boost::shared_ptr<NDRegisterAccessor<UserType>> recoveryAccessor)
: ChimeraTK::NDRegisterAccessorDecorator<UserType>(accessor), _deviceModule(devMod),
_recoveryAccessor(recoveryAccessor), _direction(direction) {
// Register recoveryAccessor at the DeviceModule
if(recoveryAccessor != nullptr) {
boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> accessor, VariableNetworkNode networkNode)
: ChimeraTK::NDRegisterAccessorDecorator<UserType>(accessor), _direction(networkNode.getDirection()) {
auto deviceAlias = networkNode.getDeviceAlias();
assert(Application::getInstance().deviceModuleMap.count(deviceAlias) != 0);
_deviceModule = Application::getInstance().deviceModuleMap[deviceAlias];
// Consuming from the network means writing to the device what you consumed.
if(_direction.dir == VariableDirection::consuming) {
// writable registers get a recoveryAccessor
// Notice: There will be write-accessors without recovery accessors in future (intentionally turned off by the application programmer)
// When this feature is added the VariableNetworkNode will get a new data member to indicate this.
auto registerName = networkNode.getRegisterName();
auto nElements = networkNode.getNumberOfElements();
// The device in the deviceModule does not have a valid backend yet. It is set when open() is called, which has not happened yet.
// We have to get the backend from the application.
assert(Application::getInstance().deviceMap.count(deviceAlias) != 0);
auto deviceBackend = Application::getInstance().deviceMap[deviceAlias];
_recoveryAccessor = deviceBackend->getRegisterAccessor<UserType>(
registerName, nElements, 0, {}); // recovery accessors don't have wait_for_new_data
// version number and write order are still {nullptr} and 0 (i.e. invalid)
_recoveryHelper = boost::make_shared<RecoveryHelper>(recoveryAccessor, VersionNumber(nullptr), 0);
_deviceModule.addRecoveryAccessor(_recoveryHelper);
_recoveryHelper = boost::make_shared<RecoveryHelper>(_recoveryAccessor, VersionNumber(nullptr), 0);
_deviceModule->addRecoveryAccessor(_recoveryHelper);
}
}
......@@ -30,8 +46,9 @@ namespace ChimeraTK {
*/
{
_hasThrownToInhibitTransfer = false;
_hasThrownLogicError = false;
_dataLostInPreviousWrite = false;
auto recoverylock{_deviceModule.getRecoverySharedLock()};
auto recoverylock{_deviceModule->getRecoverySharedLock()};
if(_recoveryAccessor != nullptr) {
if(!_recoveryHelper->wasWritten && (_recoveryHelper->writeOrder != 0)) {
......@@ -43,22 +60,23 @@ namespace ChimeraTK {
_recoveryAccessor->accessChannel(ch) = buffer_2D[ch];
}
_recoveryHelper->versionNumber = versionNumber;
_recoveryHelper->writeOrder = _deviceModule.writeOrder();
_recoveryHelper->writeOrder = _deviceModule->writeOrder();
_recoveryHelper->wasWritten = false;
}
else {
_hasThrownLogicError = true;
throw ChimeraTK::logic_error(
"ChimeraTK::ExceptionhandlingDecorator: Calling write() on a non-writeable accessor is not supported ");
}
boost::shared_lock<boost::shared_mutex> errorLock(_deviceModule.errorMutex);
if(_deviceModule.deviceHasError) {
boost::shared_lock<boost::shared_mutex> errorLock(_deviceModule->errorMutex);
if(_deviceModule->deviceHasError) {
_hasThrownToInhibitTransfer = true;
throw ChimeraTK::runtime_error(
"ExceptionHandlingDecorator is preventing the write transfer."); // writing will be delayed, done by the recovery accessor
}
++_deviceModule.synchronousTransferCounter; // must be under the lock
++_deviceModule->synchronousTransferCounter; // must be under the lock
} // lock guard goes out of scope
......@@ -69,13 +87,23 @@ namespace ChimeraTK {
template<typename UserType>
void ExceptionHandlingDecorator<UserType>::doPostWrite(TransferType type, VersionNumber versionNumber) {
if(_hasThrownLogicError) {
// preWrite has not been delegated, so there is nothing to do here. Let
// postWrite() throw the active exception we have. Don't clear logic erros here.
return;
}
if(!_hasThrownToInhibitTransfer) {
--_deviceModule.synchronousTransferCounter;
{
auto recoverylock{_deviceModule->getRecoverySharedLock()};
_recoveryHelper->wasWritten = true; // the transfer was successful, so this data was written
} // end scope for recovery lock
--_deviceModule->synchronousTransferCounter;
try {
ChimeraTK::NDRegisterAccessorDecorator<UserType>::doPostWrite(type, versionNumber);
}
catch(ChimeraTK::runtime_error& e) {
_deviceModule.reportException(e.what());
_deviceModule->reportException(e.what());
}
}
else {
......@@ -91,13 +119,13 @@ namespace ChimeraTK {
if(!_hasThrownToInhibitTransfer) {
try {
if(!TransferElement::_accessModeFlags.has(AccessMode::wait_for_new_data)) { // was as synchronous transfer
--_deviceModule.synchronousTransferCounter;
--_deviceModule->synchronousTransferCounter;
}
_target->setActiveException(this->_activeException);
_target->postRead(type, hasNewData);
}
catch(ChimeraTK::runtime_error& e) {
_deviceModule.reportException(e.what());
_deviceModule->reportException(e.what());
hasException = true;
}
}
......@@ -127,19 +155,19 @@ namespace ChimeraTK {
if(TransferElement::_versionNumber == VersionNumber(nullptr)) {
Application::testableModeUnlock("ExceptionHandling_doPreRead");
_deviceModule.getInitialValueSharedLock();
_deviceModule->getInitialValueSharedLock();
Application::testableModeLock("ExceptionHandling_doPreRead");
// we don't have to store the shared lock. Once we acquired it the deviceModule will never take it again.
}
if(!TransferElement::_accessModeFlags.has(AccessMode::wait_for_new_data)) {
boost::shared_lock<boost::shared_mutex> recoveryLock(_deviceModule.errorMutex);
if(_deviceModule.deviceHasError) {
boost::shared_lock<boost::shared_mutex> recoveryLock(_deviceModule->errorMutex);
if(_deviceModule->deviceHasError) {
_hasThrownToInhibitTransfer = true;
throw ChimeraTK::runtime_error("ExceptionHandlingDecorator has thrown to skip read transfer");
}
++_deviceModule.synchronousTransferCounter;
++_deviceModule->synchronousTransferCounter;
}
ChimeraTK::NDRegisterAccessorDecorator<UserType>::doPreRead(type);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment