summaryrefslogtreecommitdiff
path: root/src/sim/drain.hh
diff options
context:
space:
mode:
Diffstat (limited to 'src/sim/drain.hh')
-rw-r--r--src/sim/drain.hh96
1 files changed, 61 insertions, 35 deletions
diff --git a/src/sim/drain.hh b/src/sim/drain.hh
index a045bf169..f60a9978f 100644
--- a/src/sim/drain.hh
+++ b/src/sim/drain.hh
@@ -192,23 +192,26 @@ class DrainManager
* follows (see simulate.py for details):
*
* <ol>
- * <li>Call Drainable::drain() for every object in the
- * system. Draining has completed if all of them return
- * zero. Otherwise, the sum of the return values is loaded into
- * the counter of the DrainManager. A pointer to the drain
- * manager is passed as an argument to the drain() method.
+ * <li>DrainManager::tryDrain() calls Drainable::drain() for every
+ * object in the system. Draining has completed if all of them
+ * return true. Otherwise, the drain manager keeps track of the
+ * objects that requested draining and waits for them to signal
+ * that they are done draining using the signalDrainDone() method.
*
* <li>Continue simulation. When an object has finished draining its
* internal state, it calls DrainManager::signalDrainDone() on the
- * manager. When the counter in the manager reaches zero, the
- * simulation stops.
+ * manager. The drain manager keeps track of the objects that
+ * haven't drained yet, simulation stops when the set of
+ * non-drained objects becomes empty.
*
- * <li>Check if any object still needs draining, if so repeat the
- * process above.
+ * <li>Check if any object still needs draining
+ * (DrainManager::tryDrain()), if so repeat the process above.
*
* <li>Serialize objects, switch CPU model, or change timing model.
*
- * <li>Call Drainable::drainResume() and continue the simulation.
+ * <li>Call DrainManager::resume(), which intern calls
+ * Drainable::drainResume() for all objects, and continue the
+ * simulation.
* </ol>
*
*/
@@ -216,7 +219,7 @@ class Drainable
{
friend class DrainManager;
- public:
+ protected:
Drainable();
virtual ~Drainable();
@@ -224,44 +227,67 @@ class Drainable
* Determine if an object needs draining and register a
* DrainManager.
*
- * When draining the state of an object, the simulator calls drain
- * with a pointer to a drain manager. If the object does not need
- * further simulation to drain internal buffers, it switched to
- * the Drained state and returns 0, otherwise it switches to the
- * Draining state and returns the number of times that it will
- * call Event::process() on the drain event. Most objects are
- * expected to return either 0 or 1.
+ * If the object does not need further simulation to drain
+ * internal buffers, it returns true and automatically switches to
+ * the Drained state, otherwise it switches to the Draining state.
*
* @note An object that has entered the Drained state can be
* disturbed by other objects in the system and consequently be
- * forced to enter the Draining state again. The simulator
- * therefore repeats the draining process until all objects return
- * 0 on the first call to drain().
+ * being drained. These perturbations are not visible in the
+ * drain state. The simulator therefore repeats the draining
+ * process until all objects return DrainState::Drained on the
+ * first call to drain().
*
- * @param drainManager DrainManager to use to inform the simulator
- * when draining has completed.
- *
- * @return 0 if the object is ready for serialization now, >0 if
- * it needs further simulation.
+ * @return DrainState::Drained if the object is ready for
+ * serialization now, DrainState::Draining if it needs further
+ * simulation.
*/
- virtual unsigned int drain(DrainManager *drainManager) = 0;
+ virtual DrainState drain() = 0;
/**
* Resume execution after a successful drain.
- *
- * @note This method is normally only called from the simulation
- * scripts.
*/
- virtual void drainResume();
+ virtual void drainResume() {};
- DrainState getDrainState() const { return _drainState; }
+ /**
+ * Signal that an object is drained
+ *
+ * This method is designed to be called whenever an object enters
+ * into a state where it is ready to be drained. The method is
+ * safe to call multiple times and there is no need to check that
+ * draining has been requested before calling this method.
+ */
+ void signalDrainDone() const {
+ switch (_drainState) {
+ case DrainState::Running:
+ case DrainState::Drained:
+ return;
+ case DrainState::Draining:
+ _drainState = DrainState::Drained;
+ _drainManager.signalDrainDone();
+ return;
+ }
+ }
- protected:
- void setDrainState(DrainState new_state) { _drainState = new_state; }
+ public:
+ /** Return the current drain state of an object. */
+ DrainState drainState() const { return _drainState; }
private:
+ /** DrainManager interface to request a drain operation */
+ DrainState dmDrain();
+ /** DrainManager interface to request a resume operation */
+ void dmDrainResume();
+
+ /** Convenience reference to the drain manager */
DrainManager &_drainManager;
- DrainState _drainState;
+
+ /**
+ * Current drain state of the object. Needs to be mutable since
+ * objects need to be able to signal that they have transitioned
+ * into a Drained state even if the calling method is const.
+ */
+ mutable DrainState _drainState;
};
#endif