diff options
Diffstat (limited to 'src/sim/drain.cc')
-rw-r--r-- | src/sim/drain.cc | 102 |
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 |