WIP, done in the easy parts for now.
Not finished in MC_state_get_request_for_process() yet. That's too bad
because this function is the core of the use of simcalls by the MC,
where the next simcall is picked.
Not done in the independence computing part either.
#include <string>
#include <unordered_map>
-XBT_PUBLIC void simcall_run_kernel(std::function<void()> const& code);
-XBT_PUBLIC void simcall_run_blocking(std::function<void()> const& code);
+namespace simgrid {
+namespace kernel {
+namespace actor {
+
+class Transition {
+public:
+ virtual bool fireable()
+ {
+ return true;
+ } // whether this transition can currently be taken (if not, it could block the process)
+ virtual bool visible() { return true; } // whether the model-checker should pay any attention to this simcall
+ virtual std::string to_string() = 0;
+ virtual std::string dot_label() = 0;
+};
+} // namespace actor
+} // namespace kernel
+} // namespace simgrid
+
+XBT_PUBLIC void simcall_run_kernel(std::function<void()> const& code, simgrid::kernel::actor::Transition* t);
+XBT_PUBLIC void simcall_run_blocking(std::function<void()> const& code, simgrid::kernel::actor::Transition* t);
namespace simgrid {
namespace kernel {
* you may need to wait for that mutex to be unlocked by its current owner.
* Potentially blocking simcall must be issued using simcall_blocking(), right below in this file.
*/
-template <class F> typename std::result_of<F()>::type simcall(F&& code)
+template <class F> typename std::result_of<F()>::type simcall(F&& code, Transition* t = nullptr)
{
// If we are in the maestro, we take the fast path and execute the
// code directly without simcall mashalling/unmarshalling/dispatch:
// conveniently handles the success/failure value for us.
typedef typename std::result_of<F()>::type R;
simgrid::xbt::Result<R> result;
- simcall_run_kernel([&result, &code] { simgrid::xbt::fulfill_promise(result, std::forward<F>(code)); });
+ simcall_run_kernel([&result, &code] { simgrid::xbt::fulfill_promise(result, std::forward<F>(code)); }, t);
return result.get();
}
*
* If your code never calls actor->simcall_answer() itself, the actor will never return from its simcall.
*/
-template <class F> typename std::result_of<F()>::type simcall_blocking(F&& code)
+template <class F> typename std::result_of<F()>::type simcall_blocking(F&& code, Transition* t = nullptr)
{
// If we are in the maestro, we take the fast path and execute the
// code directly without simcall mashalling/unmarshalling/dispatch:
// conveniently handles the success/failure value for us.
typedef typename std::result_of<F()>::type R;
simgrid::xbt::Result<R> result;
- simcall_run_blocking([&result, &code] { simgrid::xbt::fulfill_promise(result, std::forward<F>(code)); });
+ simcall_run_blocking([&result, &code] { simgrid::xbt::fulfill_promise(result, std::forward<F>(code)); }, t);
return result.get();
}
} // namespace actor
#include <simgrid/simix.h>
#include <simgrid/simix.hpp>
-XBT_PUBLIC void simcall_run_blocking(std::function<void()> const& code);
-
namespace simgrid {
namespace simix {
smx_actor_t self = SIMIX_process_self();
simgrid::xbt::Result<T> result;
- simcall_run_blocking([&result, self, &code]{
- try {
- auto future = code();
- future.then_([&result, self](std::shared_ptr<simgrid::kernel::FutureState<T>>&& value) {
- simgrid::xbt::set_promise(result, simgrid::kernel::Future<T>(value));
- simgrid::simix::unblock(self);
- });
- }
- catch (...) {
- result.set_exception(std::current_exception());
- simgrid::simix::unblock(self);
- }
- });
+ simcall_run_blocking(
+ [&result, self, &code] {
+ try {
+ auto future = code();
+ future.then_([&result, self](std::shared_ptr<simgrid::kernel::FutureState<T>>&& value) {
+ simgrid::xbt::set_promise(result, simgrid::kernel::Future<T>(value));
+ simgrid::simix::unblock(self);
+ });
+ } catch (...) {
+ result.set_exception(std::current_exception());
+ simgrid::simix::unblock(self);
+ }
+ },
+ nullptr);
return result.get();
}
throw std::future_error(std::future_errc::no_state);
smx_actor_t self = SIMIX_process_self();
simgrid::xbt::Result<T> result;
- simcall_run_blocking([this, &result, self]{
- try {
- // When the kernel future is ready...
- this->future_.then_([&result, self](std::shared_ptr<simgrid::kernel::FutureState<T>>&& value) {
- // ... wake up the process with the result of the kernel future.
- simgrid::xbt::set_promise(result, simgrid::kernel::Future<T>(value));
- simgrid::simix::unblock(self);
- });
- }
- catch (...) {
- result.set_exception(std::current_exception());
- simgrid::simix::unblock(self);
- }
- });
+ simcall_run_blocking(
+ [this, &result, self] {
+ try {
+ // When the kernel future is ready...
+ this->future_.then_([&result, self](std::shared_ptr<simgrid::kernel::FutureState<T>>&& value) {
+ // ... wake up the process with the result of the kernel future.
+ simgrid::xbt::set_promise(result, simgrid::kernel::Future<T>(value));
+ simgrid::simix::unblock(self);
+ });
+ } catch (...) {
+ result.set_exception(std::current_exception());
+ simgrid::simix::unblock(self);
+ }
+ },
+ nullptr);
return result.get();
}
bool is_ready() const
// The future is not ready. We have to delegate to the SimGrid kernel:
std::exception_ptr exception;
smx_actor_t self = SIMIX_process_self();
- simcall_run_blocking([this, &exception, self]{
- try {
- // When the kernel future is ready...
- this->future_.then_([this, self](std::shared_ptr<simgrid::kernel::FutureState<T>>&& value) {
- // ...store it the simix kernel and wake up.
- this->future_ = std::move(simgrid::kernel::Future<T>(value));
- simgrid::simix::unblock(self);
- });
- }
- catch (...) {
- exception = std::current_exception();
- simgrid::simix::unblock(self);
- }
- });
+ simcall_run_blocking(
+ [this, &exception, self] {
+ try {
+ // When the kernel future is ready...
+ this->future_.then_([this, self](std::shared_ptr<simgrid::kernel::FutureState<T>>&& value) {
+ // ...store it the simix kernel and wake up.
+ this->future_ = std::move(simgrid::kernel::Future<T>(value));
+ simgrid::simix::unblock(self);
+ });
+ } catch (...) {
+ exception = std::current_exception();
+ simgrid::simix::unblock(self);
+ }
+ },
+ nullptr);
}
private:
// We wrap an event-based kernel future:
// Now, we are in the client app, no need for remote memory reading.
smx_simcall_t req = &actor->simcall;
+ if (req->transition != nullptr)
+ return req->transition->fireable();
+
switch (req->call) {
case SIMCALL_NONE:
return false;
xbt_assert(mc_model_checker == nullptr, "This should be called from the client side");
#endif
- return req->call == SIMCALL_COMM_ISEND || req->call == SIMCALL_COMM_IRECV || req->call == SIMCALL_COMM_WAIT ||
- req->call == SIMCALL_COMM_WAITANY || req->call == SIMCALL_COMM_TEST || req->call == SIMCALL_COMM_TESTANY ||
- req->call == SIMCALL_MC_RANDOM || req->call == SIMCALL_MUTEX_LOCK || req->call == SIMCALL_MUTEX_TRYLOCK ||
- req->call == SIMCALL_MUTEX_UNLOCK;
+ return (req->transition != nullptr && req->transition->visible()) || req->call == SIMCALL_COMM_ISEND ||
+ req->call == SIMCALL_COMM_IRECV || req->call == SIMCALL_COMM_WAIT || req->call == SIMCALL_COMM_WAITANY ||
+ req->call == SIMCALL_COMM_TEST || req->call == SIMCALL_COMM_TESTANY || req->call == SIMCALL_MC_RANDOM ||
+ req->call == SIMCALL_MUTEX_LOCK || req->call == SIMCALL_MUTEX_TRYLOCK || req->call == SIMCALL_MUTEX_UNLOCK;
}
}
{
xbt_assert(mc_model_checker != nullptr, "Must be called from MCer");
+ if (req->transition != nullptr)
+ return req->transition->to_string();
+
bool use_remote_comm = true;
switch(request_type) {
case simgrid::mc::RequestType::simix:
std::string request_get_dot_output(smx_simcall_t req, int value)
{
+ const smx_actor_t issuer = MC_smx_simcall_get_issuer(req);
+ const char* color = get_color(issuer->get_pid() - 1);
+
+ if (req->transition != nullptr)
+ return simgrid::xbt::string_printf("label = \"%s\", color = %s, fontcolor = %s",
+ req->transition->dot_label().c_str(), color, color);
+
std::string label;
- const smx_actor_t issuer = MC_smx_simcall_get_issuer(req);
switch (req->call) {
case SIMCALL_COMM_ISEND:
THROW_UNIMPLEMENTED;
}
- const char* color = get_color(issuer->get_pid() - 1);
return simgrid::xbt::string_printf(
"label = \"%s\", color = %s, fontcolor = %s", label.c_str(),
color, color);
return (e_smx_state_t)simcall_BODY_io_wait(static_cast<simgrid::kernel::activity::IoImpl*>(io.get()));
}
-void simcall_run_kernel(std::function<void()> const& code)
+void simcall_run_kernel(std::function<void()> const& code, simgrid::kernel::actor::Transition* t)
{
+ SIMIX_process_self()->simcall.transition = t;
simcall_BODY_run_kernel(&code);
}
-void simcall_run_blocking(std::function<void()> const& code)
+void simcall_run_blocking(std::function<void()> const& code, simgrid::kernel::actor::Transition* t = nullptr)
{
+ SIMIX_process_self()->simcall.transition = t;
simcall_BODY_run_blocking(&code);
}
e_smx_simcall_t call;
smx_actor_t issuer;
smx_timer_t timeout_cb; // Callback to timeouts
+ simgrid::kernel::actor::Transition* transition = nullptr;
int mc_value;
u_smx_scalar args[11];
u_smx_scalar result;