summaryrefslogtreecommitdiff
path: root/src/sim/drain.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/sim/drain.cc')
-rw-r--r--src/sim/drain.cc102
1 files changed, 98 insertions, 4 deletions
diff --git a/src/sim/drain.cc b/src/sim/drain.cc
index 90fb0c18d..384374099 100644
--- a/src/sim/drain.cc
+++ b/src/sim/drain.cc
@@ -38,10 +38,17 @@
*/
#include "sim/drain.hh"
+
+#include "base/misc.hh"
+#include "base/trace.hh"
+#include "debug/Drain.hh"
#include "sim/sim_exit.hh"
+DrainManager DrainManager::_instance;
+
DrainManager::DrainManager()
- : _count(0)
+ : _count(0),
+ _state(DrainState::Running)
{
}
@@ -49,21 +56,108 @@ DrainManager::~DrainManager()
{
}
+bool
+DrainManager::tryDrain()
+{
+ panic_if(_state == DrainState::Drained,
+ "Trying to drain a drained system\n");
+
+ panic_if(_count != 0,
+ "Drain counter must be zero at the start of a drain cycle\n");
+
+ DPRINTF(Drain, "Trying to drain %u objects.\n", drainableCount());
+ _state = DrainState::Draining;
+ for (auto *obj : _allDrainable)
+ _count += obj->drain(&_instance);
+
+ if (_count == 0) {
+ DPRINTF(Drain, "Drain done.\n");
+ _state = DrainState::Drained;
+ return true;
+ } else {
+ DPRINTF(Drain, "Need another drain cycle. %u/%u objects not ready.\n",
+ _count, drainableCount());
+ return false;
+ }
+}
+
+void
+DrainManager::resume()
+{
+ panic_if(_state == DrainState::Running,
+ "Trying to resume a system that is already running\n");
+
+ warn_if(_state == DrainState::Draining,
+ "Resuming a system that isn't fully drained, this is untested and "
+ "likely to break\n");
+
+ panic_if(_count != 0,
+ "Resume called in the middle of a drain cycle. %u objects "
+ "left to drain.\n", _count);
+
+ DPRINTF(Drain, "Resuming %u objects.\n", drainableCount());
+ _state = DrainState::Running;
+ for (auto *obj : _allDrainable)
+ obj->drainResume();
+}
+
+void
+DrainManager::preCheckpointRestore()
+{
+ panic_if(_state != DrainState::Running,
+ "preCheckpointRestore() called on a system that isn't in the "
+ "Running state.\n");
+
+ DPRINTF(Drain, "Applying pre-restore fixes to %u objects.\n",
+ drainableCount());
+ _state = DrainState::Drained;
+ for (auto *obj : _allDrainable)
+ obj->_drainState = DrainState::Drained;
+}
+
+void
+DrainManager::signalDrainDone()
+{
+ if (--_count == 0) {
+ DPRINTF(Drain, "All %u objects drained..\n", drainableCount());
+ exitSimLoop("Finished drain", 0);
+ }
+}
+
+
+void
+DrainManager::registerDrainable(Drainable *obj)
+{
+ std::lock_guard<std::mutex> lock(globalLock);
+ _allDrainable.insert(obj);
+}
+
void
-DrainManager::drainCycleDone()
+DrainManager::unregisterDrainable(Drainable *obj)
+{
+ std::lock_guard<std::mutex> lock(globalLock);
+ _allDrainable.erase(obj);
+}
+
+size_t
+DrainManager::drainableCount() const
{
- exitSimLoop("Finished drain", 0);
+ std::lock_guard<std::mutex> lock(globalLock);
+ return _allDrainable.size();
}
Drainable::Drainable()
- : _drainState(DrainState::Running)
+ : _drainManager(DrainManager::instance()),
+ _drainState(DrainState::Running)
{
+ _drainManager.registerDrainable(this);
}
Drainable::~Drainable()
{
+ _drainManager.unregisterDrainable(this);
}
void