#include <algorithm>
#include <array>
+#include <limits.h>
#include <memory>
#include <numeric>
#include <string>
-
#include <sys/ptrace.h>
+#include <sys/un.h>
#include <sys/wait.h>
XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_Session, mc, "Model-checker session");
namespace simgrid::mc {
-RemoteApp::RemoteApp(const std::vector<char*>& args, bool need_memory_introspection) : app_args_(args)
+static char master_socket_name[65] = {};
+static void cleanup_master_socket()
{
- checker_side_ = std::make_unique<simgrid::mc::CheckerSide>(app_args_, need_memory_introspection);
+ if (master_socket_name[0] != '\0')
+ unlink(master_socket_name);
+ master_socket_name[0] = '\0';
+}
- if (need_memory_introspection)
+RemoteApp::RemoteApp(const std::vector<char*>& args, bool need_memory_introspection) : app_args_(args)
+{
+ if (need_memory_introspection) {
+ checker_side_ = std::make_unique<simgrid::mc::CheckerSide>(app_args_, need_memory_introspection);
initial_snapshot_ = std::make_shared<simgrid::mc::Snapshot>(0, page_store_, *checker_side_->get_remote_memory());
+ } else {
+ master_socket_ = socket(AF_LOCAL, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
+ xbt_assert(master_socket_ != -1, "Cannot create the master socket: %s", strerror(errno));
+
+ struct sockaddr_un serv_addr = {};
+ serv_addr.sun_family = AF_LOCAL;
+ snprintf(serv_addr.sun_path, 64, "/tmp/simgrid-mc-%d", getpid());
+ strcpy(master_socket_name, serv_addr.sun_path);
+ auto addr_size = offsetof(struct sockaddr_un, sun_path) + strlen(serv_addr.sun_path);
+
+ xbt_assert(bind(master_socket_, (struct sockaddr*)&serv_addr, addr_size) >= 0,
+ "Cannot bind the master socket to %s: %s.", serv_addr.sun_path, strerror(errno));
+ atexit(cleanup_master_socket);
+
+ xbt_assert(listen(master_socket_, SOMAXCONN) >= 0, "Cannot listen to the master socket: %s.", strerror(errno));
+
+ application_factory_ = std::make_unique<simgrid::mc::CheckerSide>(app_args_, need_memory_introspection);
+ checker_side_ = application_factory_->clone(master_socket_);
+ }
}
RemoteApp::~RemoteApp()
void RemoteApp::restore_initial_state()
{
if (initial_snapshot_ == nullptr) { // No memory introspection
- // We need to destroy the existing CheckerSide before creating the new one, or libevent gets crazy
- checker_side_.reset(nullptr);
- checker_side_.reset(new simgrid::mc::CheckerSide(app_args_, false));
+ checker_side_ = application_factory_->clone(master_socket_);
} else
initial_snapshot_->restore(*checker_side_->get_remote_memory());
}
//
// CheckerSide AppSide
// send ACTORS_STATUS ---->
- // <----- send ACTORS_STATUS_REPLY
- // <----- send `N` `s_mc_message_actors_status_one_t` structs
- // <----- send `M` `s_mc_message_simcall_probe_one_t` structs
+ // <----- send ACTORS_STATUS_REPLY_COUNT
+ // <----- send `N` ACTORS_STATUS_REPLY_TRANSITION (s_mc_message_actors_status_one_t)
+ // <----- send `M` ACTORS_STATUS_REPLY_SIMCALL (s_mc_message_simcall_probe_one_t)
checker_side_->get_channel().send(MessageType::ACTORS_STATUS);
s_mc_message_actors_status_answer_t answer;
ssize_t answer_size = checker_side_->get_channel().receive(answer);
xbt_assert(answer_size != -1, "Could not receive message");
xbt_assert(answer_size == sizeof answer, "Broken message (size=%zd; expected %zu)", answer_size, sizeof answer);
- xbt_assert(answer.type == MessageType::ACTORS_STATUS_REPLY,
- "Received unexpected message %s (%i); expected MessageType::ACTORS_STATUS_REPLY (%i)",
- to_c_str(answer.type), (int)answer.type, (int)MessageType::ACTORS_STATUS_REPLY);
+ xbt_assert(answer.type == MessageType::ACTORS_STATUS_REPLY_COUNT,
+ "Received unexpected message %s (%i); expected MessageType::ACTORS_STATUS_REPLY_COUNT (%i)",
+ to_c_str(answer.type), (int)answer.type, (int)MessageType::ACTORS_STATUS_REPLY_COUNT);
// Message sanity checks
- xbt_assert(answer.count >= 0, "Received an ACTOR_STATUS_REPLY message with an actor count of '%d' < 0", answer.count);
+ xbt_assert(answer.count >= 0, "Received an ACTORS_STATUS_REPLY_COUNT message with an actor count of '%d' < 0",
+ answer.count);
std::vector<s_mc_message_actors_status_one_t> status(answer.count);
if (answer.count > 0) {
s_mc_message_simcall_execute_answer_t answer;
ssize_t s = checker_side_->get_channel().receive(answer);
xbt_assert(s != -1, "Could not receive message");
+ xbt_assert(s > 0 && answer.type == MessageType::SIMCALL_EXECUTE_REPLY,
+ "%d Received unexpected message %s (%i); expected MessageType::SIMCALL_EXECUTE_REPLY (%i)", getpid(),
+ to_c_str(answer.type), (int)answer.type, (int)MessageType::SIMCALL_EXECUTE_REPLY);
xbt_assert(s == sizeof answer, "Broken message (size=%zd; expected %zu)", s, sizeof answer);
- xbt_assert(answer.type == MessageType::SIMCALL_EXECUTE_ANSWER,
- "Received unexpected message %s (%i); expected MessageType::SIMCALL_EXECUTE_ANSWER (%i)",
- to_c_str(answer.type), (int)answer.type, (int)MessageType::SIMCALL_EXECUTE_ANSWER);
if (new_transition) {
std::stringstream stream(answer.buffer.data());
std::unique_ptr<CheckerSide> checker_side_;
PageStore page_store_{500};
std::shared_ptr<simgrid::mc::Snapshot> initial_snapshot_;
+ std::unique_ptr<CheckerSide> application_factory_; // when no meminfo, create checker_side_ by cloning this one
+ int master_socket_ = -1;
const std::vector<char*> app_args_;
#include <sys/ptrace.h>
#include <sys/socket.h>
#include <sys/types.h>
+#include <sys/un.h>
+#include <sys/wait.h>
XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_client, mc, "MC client logic");
XBT_LOG_EXTERNAL_CATEGORY(mc_global);
// Finish the RPC from the server: return a serialized observer, to build a Transition on Checker side
s_mc_message_simcall_execute_answer_t answer = {};
- answer.type = MessageType::SIMCALL_EXECUTE_ANSWER;
+ answer.type = MessageType::SIMCALL_EXECUTE_REPLY;
std::stringstream stream;
if (actor->simcall_.observer_ != nullptr) {
actor->simcall_.observer_->serialize(stream);
if (terminate_asap)
::_Exit(0);
}
+void AppSide::handle_fork(const s_mc_message_int_t* msg)
+{
+ int pid = fork();
+ xbt_assert(pid >= 0, "Could not fork application sub-process: %s.", strerror(errno));
+
+ if (pid == 0) { // Child
+ int sock = socket(AF_LOCAL, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
+
+ struct sockaddr_un addr = {};
+ addr.sun_family = AF_LOCAL;
+ snprintf(addr.sun_path, 64, "/tmp/simgrid-mc-%lu", msg->value);
+ auto addr_size = offsetof(struct sockaddr_un, sun_path) + strlen(addr.sun_path);
+
+ xbt_assert(connect(sock, (struct sockaddr*)&addr, addr_size) >= 0,
+ "Cannot connect to Checker on /tmp/simgrid-mc-%lu: %s.", msg->value, strerror(errno));
+
+ channel_.reset_socket(sock);
+
+ s_mc_message_int_t answer = {};
+ answer.type = MessageType::FORK_REPLY;
+ answer.value = getpid();
+ xbt_assert(channel_.send(answer) == 0, "Could not send response to WAIT_CHILD_REPLY: %s", strerror(errno));
+ }
+}
+void AppSide::handle_wait_child(const s_mc_message_int_t* msg)
+{
+ int status;
+ errno = 0;
+ waitpid(msg->value, &status, 0);
+ xbt_assert(errno == 0, "Cannot wait on behalf of the checker: %s.", strerror(errno));
+
+ s_mc_message_int_t answer = {};
+ answer.type = MessageType::WAIT_CHILD_REPLY;
+ answer.value = status;
+ xbt_assert(channel_.send(answer) == 0, "Could not send response to WAIT_CHILD: %s", strerror(errno));
+}
void AppSide::handle_need_meminfo()
{
this->need_memory_info_ = true;
std::vector<s_mc_message_actors_status_one_t> status;
for (auto const& [aid, actor] : actor_list) {
s_mc_message_actors_status_one_t one = {};
+ one.type = MessageType::ACTORS_STATUS_REPLY_TRANSITION;
one.aid = aid;
one.enabled = mc::actor_is_enabled(actor);
one.max_considered = actor->simcall_.observer_->get_max_consider();
}
struct s_mc_message_actors_status_answer_t answer = {};
- answer.type = MessageType::ACTORS_STATUS_REPLY;
+ answer.type = MessageType::ACTORS_STATUS_REPLY_COUNT;
answer.count = static_cast<int>(status.size());
xbt_assert(channel_.send(answer) == 0, "Could not send ACTORS_STATUS_REPLY msg");
for (int times_considered = 0; times_considered < max_considered; times_considered++) {
std::stringstream stream;
s_mc_message_simcall_probe_one_t probe;
+ probe.type = MessageType::ACTORS_STATUS_REPLY_SIMCALL;
if (actor->simcall_.observer_ != nullptr) {
actor->simcall_.observer_->prepare(times_considered);
void AppSide::handle_messages()
{
while (true) { // Until we get a CONTINUE message
- XBT_DEBUG("Waiting messages from model-checker");
+ XBT_DEBUG("Waiting messages from the model-checker");
std::array<char, MC_MESSAGE_LENGTH> message_buffer;
ssize_t received_size = channel_.receive(message_buffer.data(), message_buffer.size());
const s_mc_message_t* message = (s_mc_message_t*)message_buffer.data();
switch (message->type) {
+ case MessageType::CONTINUE:
+ assert_msg_size("MESSAGE_CONTINUE", s_mc_message_t);
+ return;
+
case MessageType::DEADLOCK_CHECK:
assert_msg_size("DEADLOCK_CHECK", s_mc_message_t);
handle_deadlock_check(message);
break;
- case MessageType::CONTINUE:
- assert_msg_size("MESSAGE_CONTINUE", s_mc_message_t);
- return;
-
case MessageType::SIMCALL_EXECUTE:
assert_msg_size("SIMCALL_EXECUTE", s_mc_message_simcall_execute_t);
handle_simcall_execute((s_mc_message_simcall_execute_t*)message_buffer.data());
handle_finalize((s_mc_message_int_t*)message_buffer.data());
break;
+ case MessageType::FORK:
+ assert_msg_size("FORK", s_mc_message_int_t);
+ handle_fork((s_mc_message_int_t*)message_buffer.data());
+ break;
+
+ case MessageType::WAIT_CHILD:
+ assert_msg_size("WAIT_CHILD", s_mc_message_int_t);
+ handle_wait_child((s_mc_message_int_t*)message_buffer.data());
+ break;
+
case MessageType::NEED_MEMINFO:
assert_msg_size("NEED_MEMINFO", s_mc_message_t);
handle_need_meminfo();
void handle_deadlock_check(const s_mc_message_t* msg) const;
void handle_simcall_execute(const s_mc_message_simcall_execute_t* message) const;
void handle_finalize(const s_mc_message_int_t* msg) const;
+ void handle_fork(const s_mc_message_int_t* msg);
+ void handle_wait_child(const s_mc_message_int_t* msg);
void handle_need_meminfo();
void handle_actors_status() const;
void handle_actors_maxpid() const;
ssize_t Channel::receive(void* message, size_t size) const
{
ssize_t res = recv(this->socket_, message, size, 0);
- if (res != -1) {
- if (static_cast<size_t>(res) >= sizeof(int) && is_valid_MessageType(*static_cast<int*>(message))) {
- XBT_DEBUG("Receive %s (requested %zu; received %zd)", to_c_str(*static_cast<MessageType*>(message)), size, res);
- } else {
- XBT_DEBUG("Receive %zd bytes", res);
- }
+ xbt_assert(res != -1, "Channel::receive failure: %s", strerror(errno));
+ if (static_cast<size_t>(res) >= sizeof(int) && is_valid_MessageType(*static_cast<const int*>(message))) {
+ XBT_DEBUG("Receive %s (requested %zu; received %zd at %p)", to_c_str(*static_cast<const MessageType*>(message)),
+ size, res, message);
} else {
- XBT_ERROR("Channel::receive failure: %s", strerror(errno));
+ XBT_DEBUG("Receive %zd bytes", res);
}
return res;
}
return this->receive(&m, sizeof(M));
}
+ // Socket handling
int get_socket() const { return socket_; }
void reset_socket(int socket) { socket_ = socket; }
};
errno);
}
-void CheckerSide::setup_events()
+void CheckerSide::setup_events(bool socket_only)
{
- if (base_ != nullptr)
- event_base_free(base_.get());
auto* base = event_base_new();
base_.reset(base);
this);
event_add(socket_event_, nullptr);
- signal_event_ = event_new(
- base, SIGCHLD, EV_SIGNAL | EV_PERSIST,
- [](evutil_socket_t sig, short events, void* arg) {
- auto checker = static_cast<simgrid::mc::CheckerSide*>(arg);
- if (events == EV_SIGNAL) {
- if (sig == SIGCHLD)
- checker->handle_waitpid();
- else
- xbt_die("Unexpected signal: %d", sig);
- } else {
- xbt_die("Unexpected event");
- }
- },
- this);
- event_add(signal_event_, nullptr);
+ if (socket_only) {
+ signal_event_ = nullptr;
+ } else {
+ signal_event_ = event_new(
+ base, SIGCHLD, EV_SIGNAL | EV_PERSIST,
+ [](evutil_socket_t sig, short events, void* arg) {
+ auto checker = static_cast<simgrid::mc::CheckerSide*>(arg);
+ if (events == EV_SIGNAL) {
+ if (sig == SIGCHLD)
+ checker->handle_waitpid();
+ else
+ xbt_die("Unexpected signal: %d", sig);
+ } else {
+ xbt_die("Unexpected event");
+ }
+ },
+ this);
+ event_add(signal_event_, nullptr);
+ }
}
+/* When this constructor is called, no other checkerside exists */
CheckerSide::CheckerSide(const std::vector<char*>& args, bool need_memory_info) : running_(true)
{
// Create an AF_LOCAL socketpair used for exchanging messages between the model-checker process (ancestor)
// and the application process (child)
int sockets[2];
- xbt_assert(socketpair(AF_LOCAL, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sockets) != -1, "Could not create socketpair");
+ xbt_assert(socketpair(AF_LOCAL, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sockets) != -1, "Could not create socketpair: %s",
+ strerror(errno));
pid_ = fork();
- xbt_assert(pid_ >= 0, "Could not fork model-checked process");
+ xbt_assert(pid_ >= 0, "Could not fork application process");
if (pid_ == 0) { // Child
::close(sockets[1]);
::close(sockets[0]);
channel_.reset_socket(sockets[1]);
- setup_events();
- if (need_memory_info)
+ setup_events(false); /* we need a signal handler too */
+ if (need_memory_info) {
+ // setup ptrace and sync with the app
wait_application_process(pid_);
- // Request the initial memory on need
- if (need_memory_info) {
+ // Request the initial memory on need
channel_.send(MessageType::NEED_MEMINFO);
s_mc_message_need_meminfo_reply_t answer;
ssize_t answer_size = channel_.receive(answer);
{
event_del(socket_event_);
event_free(socket_event_);
- event_del(signal_event_);
- event_free(signal_event_);
+ if (signal_event_ != nullptr) {
+ event_del(signal_event_);
+ event_free(signal_event_);
+ }
+}
+
+/* This constructor is called when cloning a checkerside to get its application to fork away */
+CheckerSide::CheckerSide(int socket, CheckerSide* child_checker)
+ : channel_(socket), running_(true), child_checker_(child_checker)
+{
+ setup_events(true); // We already have a signal handled in that case
+
+ s_mc_message_int_t answer;
+ ssize_t s = get_channel().receive(answer);
+ xbt_assert(s != -1, "Could not receive answer to FORK_REPLY");
+ xbt_assert(s == sizeof answer, "Broken message (size=%zd; expected %zu)", s, sizeof answer);
+ xbt_assert(answer.type == MessageType::FORK_REPLY,
+ "Received unexpected message %s (%i); expected MessageType::FORK_REPLY (%i)", to_c_str(answer.type),
+ (int)answer.type, (int)MessageType::FORK_REPLY);
+ pid_ = answer.value;
+
+ wait_for_requests();
+}
+
+std::unique_ptr<CheckerSide> CheckerSide::clone(int master_socket)
+{
+ s_mc_message_int_t m = {};
+ m.type = MessageType::FORK;
+ m.value = getpid();
+ xbt_assert(get_channel().send(m) == 0, "Could not ask the app to fork on need.");
+
+ int sock = accept(master_socket, nullptr /* I know who's connecting*/, nullptr);
+ xbt_assert(sock > 0, "Cannot accept the incomming connection of the forked app: %s.", strerror(errno));
+
+ return std::make_unique<CheckerSide>(sock, this);
}
void CheckerSide::finalize(bool terminate_asap)
break;
default:
- xbt_die("Unexpected message from model-checked application");
+ xbt_die("Unexpected message from the application");
}
return true;
}
void CheckerSide::wait_for_requests()
{
- /* Resume the application */
+ XBT_DEBUG("Resume the application");
if (get_channel().send(MessageType::CONTINUE) != 0)
throw xbt::errno_error();
clear_memory_cache();
remote_memory_->clear_cache();
}
-void CheckerSide::handle_waitpid()
+void CheckerSide::handle_dead_child(int status)
{
- XBT_DEBUG("Check for wait event");
- int status;
- pid_t pid;
- while ((pid = waitpid(-1, &status, WNOHANG)) != 0) {
- if (pid == -1) {
- if (errno == ECHILD) { // No more children:
- xbt_assert(not this->running(), "Inconsistent state");
- break;
- } else {
- xbt_die("Could not wait for pid: %s", strerror(errno));
- }
- }
-
- if (pid == get_pid()) {
- // From PTRACE_O_TRACEEXIT:
+ // From PTRACE_O_TRACEEXIT:
#ifdef __linux__
- if (status >> 8 == (SIGTRAP | (PTRACE_EVENT_EXIT << 8))) {
- unsigned long eventmsg;
- xbt_assert(ptrace(PTRACE_GETEVENTMSG, pid, 0, &eventmsg) != -1, "Could not get exit status");
- status = static_cast<int>(eventmsg);
- if (WIFSIGNALED(status)) {
- this->terminate();
- Exploration::get_instance()->report_crash(status);
- }
- }
+ if (status >> 8 == (SIGTRAP | (PTRACE_EVENT_EXIT << 8))) {
+ unsigned long eventmsg;
+ xbt_assert(ptrace(PTRACE_GETEVENTMSG, pid_, 0, &eventmsg) != -1, "Could not get exit status");
+ status = static_cast<int>(eventmsg);
+ if (WIFSIGNALED(status)) {
+ this->terminate();
+ Exploration::get_instance()->report_crash(status);
+ }
+ }
#endif
- // We don't care about non-lethal signals, just reinject them:
- if (WIFSTOPPED(status)) {
- XBT_DEBUG("Stopped with signal %i", (int)WSTOPSIG(status));
- errno = 0;
+ // We don't care about non-lethal signals, just reinject them:
+ if (WIFSTOPPED(status)) {
+ XBT_DEBUG("Stopped with signal %i", (int)WSTOPSIG(status));
+ errno = 0;
#ifdef __linux__
- ptrace(PTRACE_CONT, pid, 0, WSTOPSIG(status));
+ ptrace(PTRACE_CONT, pid_, 0, WSTOPSIG(status));
#elif defined BSD
- ptrace(PT_CONTINUE, pid, (caddr_t)1, WSTOPSIG(status));
+ ptrace(PT_CONTINUE, pid_, (caddr_t)1, WSTOPSIG(status));
#endif
- xbt_assert(errno == 0, "Could not PTRACE_CONT");
- }
+ xbt_assert(errno == 0, "Could not PTRACE_CONT: %s", strerror(errno));
+ }
+
+ else if (WIFSIGNALED(status)) {
+ this->terminate();
+ Exploration::get_instance()->report_crash(status);
+ } else if (WIFEXITED(status)) {
+ XBT_DEBUG("Child process is over");
+ this->terminate();
+ }
+}
- else if (WIFSIGNALED(status)) {
- this->terminate();
- Exploration::get_instance()->report_crash(status);
- } else if (WIFEXITED(status)) {
- XBT_DEBUG("Child process is over");
- this->terminate();
+void CheckerSide::handle_waitpid()
+{
+ XBT_DEBUG("Check for wait event");
+
+ if (child_checker_ == nullptr) { // Wait directly
+ int status;
+ pid_t pid;
+ while ((pid = waitpid(-1, &status, WNOHANG)) != 0) {
+ if (pid == -1) {
+ if (errno == ECHILD) { // No more children:
+ xbt_assert(not this->running(), "Inconsistent state");
+ break;
+ } else {
+ xbt_die("Could not wait for pid: %s", strerror(errno));
+ }
}
+
+ if (pid == get_pid())
+ handle_dead_child(status);
}
+
+ } else { // Ask our proxy to wait for us
+
+ s_mc_message_int_t request = {};
+ request.type = MessageType::WAIT_CHILD;
+ request.value = pid_;
+ xbt_assert(child_checker_->get_channel().send(request) == 0,
+ "Could not ask my child to waitpid its child for me: %s", strerror(errno));
+
+ s_mc_message_int_t answer;
+ ssize_t answer_size = child_checker_->get_channel().receive(answer);
+ xbt_assert(answer_size != -1, "Could not receive message");
+ xbt_assert(answer.type == MessageType::WAIT_CHILD_REPLY,
+ "The received message is not the WAIT_CHILD_REPLY I was expecting but of type %s",
+ to_c_str(answer.type));
+ xbt_assert(answer_size == sizeof answer, "Broken message (size=%zd; expected %zu)", answer_size, sizeof answer);
+ handle_dead_child(answer.value);
}
}
-
} // namespace simgrid::mc
Channel channel_;
bool running_ = false;
pid_t pid_;
+ // When forking (no meminfo), the real app is our grandchild. In this case,
+ // child_checker_ is a CheckerSide to our child that can waitpid our grandchild on our behalf
+ CheckerSide* child_checker_ = nullptr;
- void setup_events(); // Part of the initialization
+ void setup_events(bool socket_only); // Part of the initialization
void clear_memory_cache();
- void handle_waitpid();
+ void handle_dead_child(int status); // Launched when the dying child is the PID we follow
+ void handle_waitpid(); // Launched when receiving a sigchild
public:
+ explicit CheckerSide(int socket, CheckerSide* child_checker);
explicit CheckerSide(const std::vector<char*>& args, bool need_memory_introspection);
~CheckerSide();
void break_loop() const;
void wait_for_requests();
+ /* Create a new CheckerSide by forking the currently existing one, and connect it through the master_socket */
+ std::unique_ptr<CheckerSide> clone(int master_socket);
+
/** Ask the application to run post-mortem analysis, and maybe to stop ASAP */
void finalize(bool terminate_asap = false);
// ***** Messages
namespace simgrid::mc {
-XBT_DECLARE_ENUM_CLASS(MessageType, NONE, NEED_MEMINFO, NEED_MEMINFO_REPLY, CONTINUE, IGNORE_HEAP, UNIGNORE_HEAP,
- IGNORE_MEMORY, STACK_REGION, REGISTER_SYMBOL, DEADLOCK_CHECK, DEADLOCK_CHECK_REPLY, WAITING,
- SIMCALL_EXECUTE, SIMCALL_EXECUTE_ANSWER, ASSERTION_FAILED, ACTORS_STATUS, ACTORS_STATUS_REPLY,
- ACTORS_MAXPID, ACTORS_MAXPID_REPLY, FINALIZE, FINALIZE_REPLY);
+XBT_DECLARE_ENUM_CLASS(MessageType, NONE, NEED_MEMINFO, NEED_MEMINFO_REPLY, FORK, FORK_REPLY, WAIT_CHILD,
+ WAIT_CHILD_REPLY, CONTINUE, IGNORE_HEAP, UNIGNORE_HEAP, IGNORE_MEMORY, STACK_REGION,
+ REGISTER_SYMBOL, DEADLOCK_CHECK, DEADLOCK_CHECK_REPLY, WAITING, SIMCALL_EXECUTE,
+ SIMCALL_EXECUTE_REPLY, ASSERTION_FAILED, ACTORS_STATUS, ACTORS_STATUS_REPLY_COUNT,
+ ACTORS_STATUS_REPLY_SIMCALL, ACTORS_STATUS_REPLY_TRANSITION, ACTORS_MAXPID, ACTORS_MAXPID_REPLY,
+ FINALIZE, FINALIZE_REPLY);
} // namespace simgrid::mc
constexpr unsigned MC_MESSAGE_LENGTH = 512;
};
struct s_mc_message_actors_status_one_t { // an array of `s_mc_message_actors_status_one_t[count]` is sent right after
// after a `s_mc_message_actors_status_answer_t`
+ simgrid::mc::MessageType type;
aid_t aid;
bool enabled;
int max_considered;
// Answer from an actor to the question "what are you about to run?"
struct s_mc_message_simcall_probe_one_t { // a series of `s_mc_message_simcall_probe_one_t`
// is sent right after `s_mc_message_actors_status_one_t[]`
+ simgrid::mc::MessageType type;
std::array<char, SIMCALL_SERIALIZATION_BUFFER_SIZE> buffer;
};