From c78a4ef3d3e6bd58eb69fba9c5ebf97283fa8a5c Mon Sep 17 00:00:00 2001 From: Benjamin Morgan Date: Tue, 14 Mar 2023 09:15:06 +0100 Subject: [PATCH] runtime: Add ModelStop exception to signal simulation stop In the runtime, a simulator that is not operational after a process will also throw the ModelStop exception. --- engine/src/simulation.cpp | 13 ++++++++++++- runtime/include/cloe/model.hpp | 27 +++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/engine/src/simulation.cpp b/engine/src/simulation.cpp index 0ed56cad2..7eeda86ae 100644 --- a/engine/src/simulation.cpp +++ b/engine/src/simulation.cpp @@ -202,6 +202,9 @@ class SimulationMachine } catch (cloe::ModelReset& e) { logger()->error("Unhandled reset request in {} state: {}", id, e.what()); this->push_interrupt(RESET); + } catch (cloe::ModelStop& e) { + logger()->error("Unhandled stop request in {} state: {}", id, e.what()); + this->push_interrupt(STOP); } catch (cloe::ModelAbort& e) { logger()->error("Unhandled abort request in {} state: {}", id, e.what()); this->push_interrupt(ABORT); @@ -832,12 +835,16 @@ StateId SimulationMachine::StepSimulators::impl(SimulationContext& ctx) { ctx.foreach_simulator([&ctx](cloe::Simulator& simulator) { try { cloe::Duration sim_time = simulator.process(ctx.sync); + if (!simulator.is_operational()) { + throw cloe::ModelStop("simulator {} no longer operational", simulator.name()); + } if (sim_time != ctx.sync.time()) { - throw cloe::ModelError("simulator {} did not progress to required time: got {}ms, expected {}ms", simulator.name(), sim_time.count()/1'000'000, ctx.sync.time().count()/1'000'000); } } catch (cloe::ModelReset& e) { throw; + } catch (cloe::ModelStop& e) { + throw; } catch (cloe::ModelAbort& e) { throw; } catch (cloe::ModelError& e) { @@ -915,6 +922,10 @@ StateId SimulationMachine::StepControllers::impl(SimulationContext& ctx) { this->logger()->error("Controller {} reset: {}", ctrl.name(), e.what()); this->state_machine()->reset(); return false; + } catch (cloe::ModelStop& e) { + this->logger()->error("Controller {} stop: {}", ctrl.name(), e.what()); + this->state_machine()->stop(); + return false; } catch (cloe::ModelAbort& e) { this->logger()->error("Controller {} abort: {}", ctrl.name(), e.what()); this->state_machine()->abort(); diff --git a/runtime/include/cloe/model.hpp b/runtime/include/cloe/model.hpp index 72aedb30a..6371f908c 100644 --- a/runtime/include/cloe/model.hpp +++ b/runtime/include/cloe/model.hpp @@ -40,6 +40,10 @@ * ModelReset * Error used when a model needs to *signal* that it desires a simulation * reset. + * + * ModelStop + * Error used when a model needs to *signal* that it desires a simulation + * stop. */ #pragma once @@ -125,6 +129,29 @@ class ModelReset : public ModelError { } }; +/** + * ModelStop indicates that the model has encountered a request that causes + * it to believe that the simulation should be stopped. + */ +class ModelStop : public ModelError { + public: + using ModelError::ModelError; + virtual ~ModelStop() noexcept = default; + + const std::string& explanation() const { return Error::explanation(); } + + ModelError explanation(const std::string& explanation) && { + this->set_explanation(explanation); + return std::move(*this); + } + + template + ModelError explanation(const char* format, const Args&... args) && { + this->set_explanation(fmt::format(format, args...)); + return std::move(*this); + } +}; + /** * The Model class serves as an interface which Controller and Simulator can * inherit from.