#include <cstdio>
#include <cstring>
-#include <signal.h>
-#include <poll.h>
+#include <utility>
#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/wait.h>
-
-#ifdef __linux__
-#include <sys/prctl.h>
-#endif
-
#include <xbt/log.h>
#include "simgrid/sg_config.h"
#include "src/xbt_modinter.h"
-#include "mc_base.h"
-#include "mc_private.h"
-#include "mc_protocol.h"
-#include "mc_server.h"
-#include "mc_safety.h"
-#include "mc_comm_pattern.h"
-#include "mc_liveness.h"
+#include "src/mc/mc_base.h"
+#include "src/mc/mc_private.h"
+#include "src/mc/mc_protocol.h"
+#include "src/mc/mc_safety.h"
+#include "src/mc/mc_comm_pattern.h"
+#include "src/mc/LivenessChecker.hpp"
+#include "src/mc/mc_exit.h"
+#include "src/mc/Session.hpp"
+#include "src/mc/Checker.hpp"
+#include "src/mc/CommunicationDeterminismChecker.hpp"
+#include "src/mc/SafetyChecker.hpp"
XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_main, mc, "Entry point for simgrid-mc");
-static int do_child(int socket, char** argv)
+static inline
+char** argvdup(int argc, char** argv)
{
- XBT_DEBUG("Inside the child process PID=%i", (int) getpid());
-
-#ifdef __linux__
- // Make sure we do not outlive our parent:
- if (prctl(PR_SET_PDEATHSIG, SIGHUP) != 0) {
- std::perror("simgrid-mc");
- return MC_SERVER_ERROR;
- }
-#endif
-
- int res;
-
- // Remove CLOEXEC in order to pass the socket to the exec-ed program:
- int fdflags = fcntl(socket, F_GETFD, 0);
- if (fdflags == -1) {
- std::perror("simgrid-mc");
- return MC_SERVER_ERROR;
- }
- if (fcntl(socket, F_SETFD, fdflags & ~FD_CLOEXEC) == -1) {
- std::perror("simgrid-mc");
- return MC_SERVER_ERROR;
- }
-
- XBT_DEBUG("CLOEXEC removed on socket %i", socket);
-
- // Set environment:
- setenv(MC_ENV_VARIABLE, "1", 1);
-
- // Disable lazy relocation in the model-ched process.
- // We don't want the model-checked process to modify its .got.plt during
- // snapshot.
- setenv("LC_BIND_NOW", "1", 1);
-
- char buffer[64];
- res = std::snprintf(buffer, sizeof(buffer), "%i", socket);
- if ((size_t) res >= sizeof(buffer) || res == -1)
- return MC_SERVER_ERROR;
- setenv(MC_ENV_SOCKET_FD, buffer, 1);
+ char** argv_copy = xbt_new(char*, argc+1);
+ std::memcpy(argv_copy, argv, sizeof(char*) * argc);
+ argv_copy[argc] = nullptr;
+ return argv_copy;
+}
- execvp(argv[1], argv+1);
- std::perror("simgrid-mc");
- return MC_SERVER_ERROR;
+static
+std::unique_ptr<simgrid::mc::Checker> createChecker(simgrid::mc::Session& session)
+{
+ if (_sg_mc_comms_determinism || _sg_mc_send_determinism)
+ return std::unique_ptr<simgrid::mc::Checker>(
+ new simgrid::mc::CommunicationDeterminismChecker(session));
+ else if (!_sg_mc_property_file || _sg_mc_property_file[0] == '\0')
+ return std::unique_ptr<simgrid::mc::Checker>(
+ new simgrid::mc::SafetyChecker(session));
+ else
+ return std::unique_ptr<simgrid::mc::Checker>(
+ new simgrid::mc::LivenessChecker(session));
}
-static int do_parent(int socket, pid_t child)
+int main(int argc, char** argv)
{
- XBT_DEBUG("Inside the parent process");
- if (mc_server)
- xbt_die("MC server already present");
+ using simgrid::mc::Session;
+
try {
+ if (argc < 2)
+ xbt_die("Missing arguments.\n");
+
+ // Currently, we need this before sg_config_init:
+ _sg_do_model_check = 1;
mc_mode = MC_MODE_SERVER;
- mc_server = new s_mc_server(child, socket);
- mc_server->start();
- MC_init_model_checker(child, socket);
- if (_sg_mc_comms_determinism || _sg_mc_send_determinism)
- MC_modelcheck_comm_determinism();
- else if (!_sg_mc_property_file || _sg_mc_property_file[0] == '\0')
- MC_modelcheck_safety();
- else
- MC_modelcheck_liveness();
- mc_server->shutdown();
- mc_server->exit();
+
+ // The initialisation function can touch argv.
+ // We make a copy of argv before modifying it in order to pass the original
+ // value to the model-checked:
+ char** argv_copy = argvdup(argc, argv);
+ xbt_log_init(&argc, argv);
+ sg_config_init(&argc, argv);
+
+ std::unique_ptr<Session> session =
+ std::unique_ptr<Session>(Session::spawnvp(argv_copy[1], argv_copy+1));
+ free(argv_copy);
+
+ simgrid::mc::session = session.get();
+ std::unique_ptr<simgrid::mc::Checker> checker = createChecker(*session);
+ int res = checker->run();
+ session->close();
+ return res;
}
catch(std::exception& e) {
XBT_ERROR("Exception: %s", e.what());
+ return SIMGRID_MC_EXIT_ERROR;
}
- exit(MC_SERVER_ERROR);
-}
-
-static char** argvdup(int argc, char** argv)
-{
- char** argv_copy = xbt_new(char*, argc+1);
- std::memcpy(argv_copy, argv, sizeof(char*) * argc);
- argv_copy[argc] = NULL;
- return argv_copy;
-}
-
-int main(int argc, char** argv)
-{
- _sg_do_model_check = 1;
-
- // We need to keep the original parameters in order to pass them to the
- // model-checked process:
- int argc_copy = argc;
- char** argv_copy = argvdup(argc, argv);
- xbt_log_init(&argc_copy, argv_copy);
- sg_config_init(&argc_copy, argv_copy);
-
- if (argc < 2)
- xbt_die("Missing arguments.\n");
-
- // Create a AF_LOCAL socketpair:
- int res;
-
- int sockets[2];
- res = socketpair(AF_LOCAL, SOCK_DGRAM | SOCK_CLOEXEC, 0, sockets);
- if (res == -1) {
- perror("simgrid-mc");
- return MC_SERVER_ERROR;
- }
-
- XBT_DEBUG("Created socketpair");
-
- pid_t pid = fork();
- if (pid < 0) {
- perror("simgrid-mc");
- return MC_SERVER_ERROR;
- } else if (pid == 0) {
- close(sockets[1]);
- return do_child(sockets[0], argv);
- } else {
- close(sockets[0]);
- return do_parent(sockets[1], pid);
+ catch(...) {
+ XBT_ERROR("Unknown exception");
+ return SIMGRID_MC_EXIT_ERROR;
}
-
- return 0;
}