diff --git a/include/TestableMode.h b/include/TestableMode.h index ddd64b40a5b64e11c03e5f3f1f7d270d3c67f341..e842ea28b76ce1075591f26677faf6f6424ec338 100644 --- a/include/TestableMode.h +++ b/include/TestableMode.h @@ -15,6 +15,10 @@ #include <map> #include <mutex> +namespace ChimeraTK { + class ConnectionMaker; +} + namespace ChimeraTK::detail { struct TestableMode { /** Special exception class which will be thrown if tests with the testable @@ -68,7 +72,7 @@ namespace ChimeraTK::detail { /** Test if the testable mode mutex is locked by the current thread. * * This function should generally not be used in user code. */ - bool testLock(); + [[nodiscard]] bool testLock() const; [[nodiscard]] bool canStep() const { return counter != 0; } @@ -211,6 +215,9 @@ namespace ChimeraTK::detail { * output of the testable mode. Will return "*UNKNOWN_THREAD*" if the name for the given ID has not yet been set. */ std::string threadName(const boost::thread::id& threadId = boost::this_thread::get_id()); + + bool _debugDecorating{false}; + friend class ChimeraTK::ConnectionMaker; }; /********************************************************************************************************************/ @@ -224,6 +231,11 @@ namespace ChimeraTK::detail { AccessorPair<T> other, const VariableNetworkNode& producer, const VariableNetworkNode& consumer) { if(not enabled) return other; + if(_debugDecorating) { + std::cout << " Decorating pair " << producer.getQualifiedName() << "[" << other.first->getId() << "] -> " + << consumer.getQualifiedName() << "[" << other.second->getId() << "]" << std::endl; + } + // create variable IDs size_t varId = detail::TestableMode::getNextVariableId(); size_t varIdReturn; @@ -264,6 +276,11 @@ namespace ChimeraTK::detail { return other; } + if(_debugDecorating) { + std::cout << " Decorating single " << (direction == DecoratorType::READ ? "consumer " : "feeder ") << name + << "[" << other->getId() << "]" << std::endl; + } + if(varId == 0) { varId = detail::TestableMode::getNextVariableId(); } diff --git a/src/ConnectionMaker.cc b/src/ConnectionMaker.cc index fb71410a1713cbfafbfaf7cf64d10e2cb7647161..8a3479aeb92d202040c4c61f76351f17e4e3908c 100644 --- a/src/ConnectionMaker.cc +++ b/src/ConnectionMaker.cc @@ -121,6 +121,8 @@ namespace ChimeraTK { void ConnectionMaker::connect() { debug("Calling Connect..."); + _app.getTestableMode()._debugDecorating = _debugConnections; + debug(" Preparing trigger networks"); debug(" Collecting triggers"); std::set<Model::ProcessVariableProxy> triggers; diff --git a/src/TestFacility.cc b/src/TestFacility.cc index 93445b70ba45ecc4148503d80ded6fb25f391464..3b8f78487ad1171393814ebbee75fcd57e17907c 100644 --- a/src/TestFacility.cc +++ b/src/TestFacility.cc @@ -86,7 +86,7 @@ namespace ChimeraTK { for(auto& pv : pvManager->getAllProcessVariables()) { if(!pv->isReadable()) continue; callForTypeNoVoid(pv->getValueType(), [&](auto t) { - typedef decltype(t) UserType; + using UserType = decltype(t); this->getArray<UserType>(pv->getName()).readNonBlocking(); }); } diff --git a/src/TestableMode.cc b/src/TestableMode.cc index 8fb9fbf4c1d198d23ff6fa041fbc931dde23a247..9f51b8f133af6c76edbb07c4a1443f29b16c3770 100644 --- a/src/TestableMode.cc +++ b/src/TestableMode.cc @@ -27,13 +27,30 @@ namespace ChimeraTK::detail { } /*********************************************************************************************************************/ - bool TestableMode::testLock() { + bool TestableMode::testLock() const { if(not enabled) return false; return getLockObject().owns_lock(); } /*********************************************************************************************************************/ + namespace { + /// This is a trick to make sure the exception is never caught, not even by the BOOST test framework. + void terminateTestStalled() { + struct TestStalled : std::exception { + [[nodiscard]] const char* what() const noexcept override { return "Test stalled."; } + }; + try { + throw TestStalled(); + } + catch(...) { + std::terminate(); + } + } + } // namespace + + /*********************************************************************************************************************/ + void TestableMode::lock(const std::string& name) { // don't do anything if testable mode is not enabled if(not enabled) return; @@ -66,7 +83,7 @@ namespace ChimeraTK::detail { << std::endl; // LCOV_EXCL_LINE // throw a specialised exception to make sure whoever catches it really knows what he does... - throw TestsStalled(); // LCOV_EXCL_LINE + terminateTestStalled(); // LCOV_EXCL_LINE } // LCOV_EXCL_LINE // check if the last owner of the mutex was this thread, which may be a hint @@ -118,7 +135,7 @@ namespace ChimeraTK::detail { // Check for modules waiting for initial values (prints nothing if there are no such modules) Application::getInstance().circularDependencyDetector.printWaiters(); // throw a specialised exception to make sure whoever catches it really knows what he does... - throw TestsStalled(); + terminateTestStalled(); } } else {