base: Tag API methods in amo.hh
[gem5.git] / src / sim / drain.cc
index bb8abd735151a0fadf8a0ef70e0b98e584cf88eb..30067682e03de5e2e37b7be1dc002d87c96bda88 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2015 ARM Limited
+ * Copyright (c) 2012, 2015, 2017 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Andreas Sandberg
  */
 
 #include "sim/drain.hh"
 
 #include <algorithm>
 
-#include "base/misc.hh"
+#include "base/logging.hh"
 #include "base/trace.hh"
 #include "debug/Drain.hh"
 #include "sim/sim_exit.hh"
@@ -101,14 +99,33 @@ DrainManager::resume()
             "Resuming a system that isn't fully drained, this is untested and "
             "likely to break\n");
 
+    panic_if(_state == DrainState::Resuming,
+             "Resuming a system that is already trying to resume. This should "
+             "never happen.\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());
+    // At this point in time the DrainManager and all objects will be
+    // in the the Drained state. New objects (i.e., objects created
+    // while resuming) will inherit the Resuming state from the
+    // DrainManager, which means we have to resume objects until all
+    // objects are in the Running state.
+    _state = DrainState::Resuming;
+
+    do {
+        DPRINTF(Drain, "Resuming %u objects.\n", drainableCount());
+        for (auto *obj : _allDrainable) {
+            if (obj->drainState() != DrainState::Running) {
+                assert(obj->drainState() == DrainState::Drained ||
+                       obj->drainState() == DrainState::Resuming);
+                obj->dmDrainResume();
+            }
+        }
+    } while (!allInState(DrainState::Running));
+
     _state = DrainState::Running;
-    for (auto *obj : _allDrainable)
-        obj->dmDrainResume();
 }
 
 void
@@ -154,6 +171,17 @@ DrainManager::unregisterDrainable(Drainable *obj)
     _allDrainable.erase(o);
 }
 
+bool
+DrainManager::allInState(DrainState state) const
+{
+    for (const auto *obj : _allDrainable) {
+        if (obj->drainState() != state)
+            return false;
+    }
+
+    return true;
+}
+
 size_t
 DrainManager::drainableCount() const
 {
@@ -189,7 +217,8 @@ Drainable::dmDrain()
 void
 Drainable::dmDrainResume()
 {
-    panic_if(_drainState != DrainState::Drained,
+    panic_if(_drainState != DrainState::Drained &&
+             _drainState != DrainState::Resuming,
              "Trying to resume an object that hasn't been drained\n");
 
     _drainState = DrainState::Running;