diff --git a/src/core/efw/CoroutineManager.cc b/src/core/efw/CoroutineManager.cc index 4dd35e4c..1b8be303 100644 --- a/src/core/efw/CoroutineManager.cc +++ b/src/core/efw/CoroutineManager.cc @@ -8,9 +8,9 @@ namespace fail { void CoroutineManager::m_invoke(void* pData) { - //std::cerr << "CORO m_invoke " << co_current() << std::endl; - // TODO: Log-Level? - reinterpret_cast(pData)->coroutine_entry(); + ExperimentFlow *flow = reinterpret_cast(pData); + flow->coroutine_entry(); + simulator.removeFlow(flow); //m_togglerstack.pop(); // FIXME: need to pop our caller co_exit(); // deletes the associated coroutine memory as well @@ -20,7 +20,12 @@ void CoroutineManager::m_invoke(void* pData) while (1); // freeze. } -CoroutineManager::~CoroutineManager() { } +CoroutineManager::~CoroutineManager() +{ + // Note that we do not destroy the associated coroutines; this causes + // problems when shutting down. + m_Flows.clear(); +} void CoroutineManager::toggle(ExperimentFlow* flow) { @@ -53,7 +58,9 @@ void CoroutineManager::remove(ExperimentFlow* flow) // find coroutine handle for this flow flowmap_t::iterator it = m_Flows.find(flow); if (it == m_Flows.end()) { - assert(false && "FATAL ERROR: Cannot remove flow"); + // Not finding the flow to remove is not an error; especially when + // shutting down this is the common case, as ~CoroutineManager probably + // clears the flow list before the ExperimentFlow destructors run. return; } corohandle_t coro = it->second; @@ -67,7 +74,9 @@ void CoroutineManager::remove(ExperimentFlow* flow) // delete coroutine (and handle the special case we're removing // ourselves) if (coro == co_current()) { - co_exit(); + if (!m_Terminated) { + co_exit(); + } } else { co_delete(coro); } diff --git a/src/core/efw/CoroutineManager.hpp b/src/core/efw/CoroutineManager.hpp index 13d9ce58..ec550f8e 100644 --- a/src/core/efw/CoroutineManager.hpp +++ b/src/core/efw/CoroutineManager.hpp @@ -29,10 +29,12 @@ private: std::stack m_togglerstack; //! manages the run-calls for each ExperimentFlow-object static void m_invoke(void* pData); + //! \c true if terminated explicitly using simulator.terminate() + bool m_Terminated; public: static const ExperimentFlow* SIM_FLOW; //!< the simulator coroutine flow - CoroutineManager() : m_simCoro(co_current()) { } + CoroutineManager() : m_simCoro(co_current()), m_Terminated(false) { } ~CoroutineManager(); /** * Creates a new coroutine for the specified experiment flow. @@ -63,6 +65,12 @@ public: * @return the current experiment flow. */ ExperimentFlow* getCurrent(); + /** + * Sets the termination flag. This should be called when Fail + * exists due to a call to \c ::exit() (used, e.g., in + * \c SimulatorController::terminate()). This cannot be undone. + */ + void setTerminated() { m_Terminated = true; } }; } // end-of-namespace: fail diff --git a/src/core/efw/ExperimentFlow.hpp b/src/core/efw/ExperimentFlow.hpp index 6279491f..0166a2fe 100644 --- a/src/core/efw/ExperimentFlow.hpp +++ b/src/core/efw/ExperimentFlow.hpp @@ -13,6 +13,11 @@ namespace fail { class ExperimentFlow { public: ExperimentFlow() { } + virtual ~ExperimentFlow() + { + simulator.clearListeners(this); // remove residual events + simulator.removeFlow(this); + } /** * Defines the experiment flow. * @return \c true if the experiment was successful, \c false otherwise diff --git a/src/core/sal/SimulatorController.cc b/src/core/sal/SimulatorController.cc index 26ea73dd..be5d9864 100644 --- a/src/core/sal/SimulatorController.cc +++ b/src/core/sal/SimulatorController.cc @@ -217,6 +217,8 @@ void SimulatorController::terminate(int exCode) // Attention: This could cause problems, e.g., because of non-closed sockets std::cout << "[FAIL] Exit called by experiment with exit code: " << exCode << std::endl; // TODO: (Non-)Verbose-Mode? Log-Level? + + m_Flows.setTerminated(); // we are about to terminate exit(exCode); } diff --git a/src/experiments/ecos_kernel_test/instantiateExperiment.cc b/src/experiments/ecos_kernel_test/instantiateExperiment.cc index 520be8a3..414a7172 100644 --- a/src/experiments/ecos_kernel_test/instantiateExperiment.cc +++ b/src/experiments/ecos_kernel_test/instantiateExperiment.cc @@ -1,8 +1,7 @@ #include "experiment.hpp" #include "sal/SALInst.hpp" -static EcosKernelTestExperiment experiment; void instantiateEcosKernelTestExperiment() { - fail::simulator.addFlow(&experiment); + fail::simulator.addFlow(new EcosKernelTestExperiment); } diff --git a/src/experiments/instantiate-experiment-indirect.ah.in b/src/experiments/instantiate-experiment-indirect.ah.in index d309617b..b3a72752 100644 --- a/src/experiments/instantiate-experiment-indirect.ah.in +++ b/src/experiments/instantiate-experiment-indirect.ah.in @@ -12,6 +12,10 @@ // You need to provide the implementation of this function in your experiment // directory: void instantiate@EXPERIMENT_TYPE@(); +// The experiment needs to be instantiated dynamically (on the stack, or the +// heap), as the ExperimentFlow destructor deregisters from the +// CoroutineManager which may not exist anymore if the global +// construction/destruction order is inappropriate. aspect @EXPERIMENT_TYPE@ExperimentHook { advice execution ("void fail::SimulatorController::initExperiments()") : after () { diff --git a/src/experiments/instantiate-experiment.ah.in b/src/experiments/instantiate-experiment.ah.in index 765d7214..5bf1ed32 100644 --- a/src/experiments/instantiate-experiment.ah.in +++ b/src/experiments/instantiate-experiment.ah.in @@ -9,10 +9,14 @@ #include "../experiments/@EXPERIMENT_NAME@/experiment.hpp" #include "sal/SALInst.hpp" +// The experiment needs to be instantiated dynamically (on the stack, or the +// heap), as the ExperimentFlow destructor deregisters from the +// CoroutineManager which may not exist anymore if the global +// construction/destruction order is inappropriate. + aspect @EXPERIMENT_TYPE@ExperimentHook { - @EXPERIMENT_TYPE@ experiment; advice execution ("void fail::SimulatorController::initExperiments()") : after () { - fail::simulator.addFlow(&experiment); + fail::simulator.addFlow(new @EXPERIMENT_TYPE@); } }; diff --git a/src/experiments/nanojpeg/instantiateExperiment.cc b/src/experiments/nanojpeg/instantiateExperiment.cc index 98493577..84e8a80d 100644 --- a/src/experiments/nanojpeg/instantiateExperiment.cc +++ b/src/experiments/nanojpeg/instantiateExperiment.cc @@ -1,8 +1,7 @@ #include "experiment.hpp" #include "sal/SALInst.hpp" -static NanoJPEGExperiment experiment; void instantiateNanoJPEGExperiment() { - fail::simulator.addFlow(&experiment); + fail::simulator.addFlow(new NanoJPEGExperiment); } diff --git a/src/experiments/rampage/instantiateExperiment.cc b/src/experiments/rampage/instantiateExperiment.cc index ed51e4b8..b1efb310 100644 --- a/src/experiments/rampage/instantiateExperiment.cc +++ b/src/experiments/rampage/instantiateExperiment.cc @@ -1,8 +1,7 @@ #include "experiment.hpp" #include "sal/SALInst.hpp" -static RAMpageExperiment experiment; void instantiateRAMpageExperiment() { - fail::simulator.addFlow(&experiment); + fail::simulator.addFlow(new RAMpageExperiment); }