/**
* @brief The transitions that the actor is allowed to execute from this
- * state.
+ * state, viz. those that are enabled for this actor
+ *
+ * Most actors can take only a single action from any given state.
+ * However, when an actor executes a transition with multiple
+ * possible variations (e.g. an MC_Random() [see class: RandomTransition]
+ * for more details]), multiple enabled actions are defined
+ *
+ * @invariant The transitions are arranged such that an actor
+ * with multiple possible paths of execution will contain all
+ * such transitions such that `pending_transitions_[i]` represents
+ * the variation of the transition with `times_considered = i`.
+ *
+ * TODO: If only a subset of transitions of an actor that can
+ * take multiple transitions in some state are truly enabled,
+ * we would instead need to map `times_considered` to a transition,
+ * as the map is currently implicit in the ordering of the transitions
+ * in the vector
*
* TODO: If a single transition is taken at a time in a concurrent system,
* then nearly all of the transitions from in a state `s'` after taking
}
void set_done() { this->state_ = InterleavingType::done; }
- Transition* get_transition(unsigned times_considered)
+ inline Transition* get_transition(unsigned times_considered)
{
- xbt_assert(times_considered <= this->pending_transitions_.size(),
+ xbt_assert(times_considered < this->pending_transitions_.size(),
"Actor %lu does not have a state available transition with `times_considered = %d`,\n"
"yet one was asked for",
aid_, times_considered);
return this->pending_transitions_[times_considered].get();
}
+
+ inline void set_transition(std::unique_ptr<Transition> t, unsigned times_considered)
+ {
+ xbt_assert(times_considered < this->pending_transitions_.size(),
+ "Actor %lu does not have a state available transition with `times_considered = %d`, "
+ "yet one was attempted to be set",
+ aid_, times_considered);
+ this->pending_transitions_[times_considered] = std::move(t);
+ }
};
} // namespace simgrid::mc
}
return -1;
}
+
void State::execute_next(aid_t next)
{
- /* This actor is ready to be executed. Prepare its execution when simcall_handle will be called on it */
- const unsigned times_considered = actors_to_run_.at(next).do_consider();
- auto* expected_executed_transition = actors_to_run_.at(next).get_transition(times_considered);
+ // This actor is ready to be executed. Execution involves three phases:
+
+ // 1. Identify the appropriate ActorState to prepare for execution
+ // when simcall_handle will be called on it
+ auto& actor_state = actors_to_run_.at(next);
+ const unsigned times_considered = actor_state.do_consider();
+ const auto* expected_executed_transition = actor_state.get_transition(times_considered);
xbt_assert(expected_executed_transition != nullptr,
"Expected a transition with %d times considered to be noted in actor %lu", times_considered, next);
XBT_DEBUG("Let's run actor %ld (times_considered = %u)", next, times_considered);
+ // 2. Execute the actor according to the preparation above
Transition::executed_transitions_++;
-
- const auto* executed_transition = mc_model_checker->handle_simcall(next, times_considered, true);
- xbt_assert(executed_transition->type_ == expected_executed_transition->type_,
+ auto* just_executed = mc_model_checker->handle_simcall(next, times_considered, true);
+ xbt_assert(just_executed->type_ == expected_executed_transition->type_,
"The transition that was just executed by actor %lu, viz:\n"
"%s\n"
"is not what was purportedly scheduled to execute, which was:\n"
"%s\n",
- next, executed_transition->to_string().c_str(), expected_executed_transition->to_string().c_str());
- transition_ = expected_executed_transition;
+ next, just_executed->to_string().c_str(), expected_executed_transition->to_string().c_str());
+
+ // 3. Update the state with the newest information. This means recording
+ // both
+ // 1. what action was last taken from this state (viz. `executed_transition`)
+ // 2. what action actor `next` was able to take given `times_considered`
+ // The latter update is important as *more* information is potentially available
+ // about a transition AFTER it has executed.
+ transition_ = just_executed;
+
+ auto executed_transition = std::unique_ptr<Transition>(just_executed);
+ actor_state.set_transition(std::move(executed_transition), times_considered);
+
mc_model_checker->wait_for_requests();
}
} // namespace simgrid::mc
static long expended_states_; /* Count total amount of states, for stats */
/**
- * Outgoing transition: what was the last transition that we took to leave this state?
- * The owner of the transition is the ActorState instance which exists in the State
- * object from which this state is derived, or nullptr if the state represents the root
+ * @brief The outgoing transition: what was the last transition that
+ * we took to leave this state?
+ *
+ * The owner of the transition is the `ActorState` instance which exists in this state,
+ * or nullptr if the state represents the root
*/
Transition* transition_ = nullptr;