Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
[mc] Do not use reduction_mode outside of the safety algorithm
[simgrid.git] / src / mc / Session.cpp
1 /* Copyright (c) 2015-2016. The SimGrid Team.
2  * All rights reserved.                                                     */
3
4 /* This program is free software; you can redistribute it and/or modify it
5  * under the terms of the license (GNU LGPL) which comes with this package. */
6
7 #include <fcntl.h>
8 #include <signal.h>
9
10 #include <functional>
11
12 #include <xbt/system_error.hpp>
13 #include <simgrid/sg_config.h>
14 #include <simgrid/modelchecker.h>
15
16 #include "src/mc/Session.hpp"
17
18 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_Session, mc, "Model-checker session");
19
20 namespace simgrid {
21 namespace mc {
22
23 static void setup_child_environment(int socket)
24 {
25 #ifdef __linux__
26   // Make sure we do not outlive our parent:
27   sigset_t mask;
28   sigemptyset (&mask);
29   if (sigprocmask(SIG_SETMASK, &mask, nullptr) < 0)
30     throw simgrid::xbt::errno_error(errno, "Could not unblock signals");
31   if (prctl(PR_SET_PDEATHSIG, SIGHUP) != 0)
32     throw simgrid::xbt::errno_error(errno, "Could not PR_SET_PDEATHSIG");
33 #endif
34
35   int res;
36
37   // Remove CLOEXEC in order to pass the socket to the exec-ed program:
38   int fdflags = fcntl(socket, F_GETFD, 0);
39   if (fdflags == -1 || fcntl(socket, F_SETFD, fdflags & ~FD_CLOEXEC) == -1)
40     throw simgrid::xbt::errno_error(errno, "Could not remove CLOEXEC for socket");
41
42   // Set environment:
43   setenv(MC_ENV_VARIABLE, "1", 1);
44
45   // Disable lazy relocation in the model-checked process.
46   // We don't want the model-checked process to modify its .got.plt during
47   // snapshot.
48   setenv("LC_BIND_NOW", "1", 1);
49
50   char buffer[64];
51   res = std::snprintf(buffer, sizeof(buffer), "%i", socket);
52   if ((size_t) res >= sizeof(buffer) || res == -1)
53     std::abort();
54   setenv(MC_ENV_SOCKET_FD, buffer, 1);
55 }
56
57 /** Execute some code in a forked process */
58 template<class F>
59 static inline
60 pid_t do_fork(F code)
61 {
62   pid_t pid = fork();
63   if (pid < 0)
64     throw simgrid::xbt::errno_error(errno, "Could not fork model-checked process");
65   if (pid != 0)
66     return pid;
67
68   // Child-process:
69   try {
70     code();
71     _exit(EXIT_SUCCESS);
72   }
73   catch(...) {
74     // The callback should catch exceptions:
75     std::terminate();
76   }
77 }
78
79 Session::Session(pid_t pid, int socket)
80 {
81   std::unique_ptr<simgrid::mc::Process> process(new simgrid::mc::Process(pid, socket));
82   // TODO, automatic detection of the config from the process
83   process->privatized(
84     sg_cfg_get_boolean("smpi/privatize_global_variables"));
85   modelChecker_ = std::unique_ptr<ModelChecker>(
86     new simgrid::mc::ModelChecker(std::move(process)));
87   xbt_assert(mc_model_checker == nullptr);
88   mc_model_checker = modelChecker_.get();
89   mc_model_checker->start();
90 }
91
92 Session::~Session()
93 {
94   this->close();
95 }
96
97 // static
98 Session* Session::fork(std::function<void(void)> code)
99 {
100   // Create a AF_LOCAL socketpair used for exchanging messages
101   // bewteen the model-checker process (ourselves) and the model-checked
102   // process:
103   int res;
104   int sockets[2];
105   res = socketpair(AF_LOCAL, SOCK_DGRAM | SOCK_CLOEXEC, 0, sockets);
106   if (res == -1)
107     throw simgrid::xbt::errno_error(errno, "Could not create socketpair");
108
109   pid_t pid = do_fork([&] {
110     ::close(sockets[1]);
111     setup_child_environment(sockets[0]);
112     code();
113     xbt_die("The model-checked process failed to exec()");
114   });
115
116   // Parent (model-checker):
117   ::close(sockets[0]);
118
119   return new Session(pid, sockets[1]);
120 }
121
122 // static
123 Session* Session::spawnv(const char *path, char *const argv[])
124 {
125   return Session::fork([&] {
126     execv(path, argv);
127   });
128 }
129
130 // static
131 Session* Session::spawnvp(const char *path, char *const argv[])
132 {
133   return Session::fork([&] {
134     execvp(path, argv);
135   });
136 }
137
138 void Session::close()
139 {
140   if (modelChecker_) {
141     modelChecker_->shutdown();
142     modelChecker_ = nullptr;
143     mc_model_checker = nullptr;
144   }
145 }
146
147 }
148 }