Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
05902d58cced61a7e6dbfc901f520befeefc04fe
[simgrid.git] / src / mc / Server.cpp
1 /* Copyright (c) 2015. 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 <memory>
8 #include <system_error>
9
10 #include <poll.h>
11 #include <sys/types.h>
12 #include <sys/wait.h>
13 #include <sys/socket.h>
14 #include <sys/signalfd.h>
15 #include <sys/ptrace.h>
16
17 #include <xbt/log.h>
18 #include <xbt/automaton.h>
19 #include <xbt/automaton.hpp>
20
21 #include "ModelChecker.hpp"
22 #include "mc_protocol.h"
23 #include "src/mc/Server.hpp"
24 #include "mc_private.h"
25 #include "mc_ignore.h"
26 #include "mcer_ignore.h"
27 #include "mc_exit.h"
28 #include "src/mc/mc_liveness.h"
29
30 using simgrid::mc::remote;
31
32 extern "C" {
33
34 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_Server, mc, "MC server logic");
35
36 }
37
38 // HArdcoded index for now:
39 #define SOCKET_FD_INDEX 0
40 #define SIGNAL_FD_INDEX 1
41
42 namespace simgrid {
43 namespace mc {
44
45 Server* server = nullptr;
46
47 Server::Server(pid_t pid_, int socket_)
48   : pid(pid_), socket(socket_) {}
49
50 void Server::start()
51 {
52   // Block SIGCHLD (this will be handled with accept/signalfd):
53   sigset_t set;
54   sigemptyset(&set);
55   sigaddset(&set, SIGCHLD);
56   if (sigprocmask(SIG_BLOCK, &set, NULL) == -1)
57     throw std::system_error(errno, std::system_category());
58
59   sigset_t full_set;
60   sigfillset(&full_set);
61
62   // Prepare data for poll:
63
64   struct pollfd* socket_pollfd = &fds[SOCKET_FD_INDEX];
65   socket_pollfd->fd = socket;
66   socket_pollfd->events = POLLIN;
67   socket_pollfd->revents = 0;
68
69   int signal_fd = signalfd(-1, &set, 0);
70   if (signal_fd == -1)
71     throw std::system_error(errno, std::system_category());
72
73   struct pollfd* signalfd_pollfd = &fds[SIGNAL_FD_INDEX];
74   signalfd_pollfd->fd = signal_fd;
75   signalfd_pollfd->events = POLLIN;
76   signalfd_pollfd->revents = 0;
77
78   XBT_DEBUG("Waiting for the model-checked process");
79   int status;
80
81   // The model-checked process SIGSTOP itself to signal it's ready:
82   pid_t res = waitpid(pid, &status, __WALL);
83   if (res < 0 || !WIFSTOPPED(status) || WSTOPSIG(status) != SIGSTOP)
84     xbt_die("Could not wait model-checked process");
85
86   // The model-checked process is ready, we can read its memory layout:
87   MC_init_model_checker(pid, socket);
88
89   ptrace(PTRACE_SETOPTIONS, pid, nullptr, PTRACE_O_TRACEEXIT);
90   ptrace(PTRACE_CONT, pid, 0, 0);
91 }
92
93 void Server::shutdown()
94 {
95   XBT_DEBUG("Shuting down model-checker");
96
97   simgrid::mc::Process* process = &mc_model_checker->process();
98   int status = process->status();
99   if (process->running()) {
100     XBT_DEBUG("Killing process");
101     kill(process->pid(), SIGTERM);
102     if (waitpid(process->pid(), &status, 0) == -1)
103       throw std::system_error(errno, std::system_category());
104     // TODO, handle the case when the process does not want to die with a timeout
105     process->terminate(status);
106   }
107 }
108
109 void Server::resume(simgrid::mc::Process& process)
110 {
111   int res = process.send_message(MC_MESSAGE_CONTINUE);
112   if (res)
113     throw std::system_error(res, std::system_category());
114   process.cache_flags = (mc_process_cache_flags_t) 0;
115 }
116
117 static
118 void throw_socket_error(int fd)
119 {
120   int error = 0;
121   socklen_t errlen = sizeof(error);
122   if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&error, &errlen) == -1)
123     error = errno;
124   throw std::system_error(error, std::system_category());
125 }
126
127 bool Server::handle_message(char* buffer, ssize_t size)
128 {
129   s_mc_message_t base_message;
130   if (size < (ssize_t) sizeof(base_message))
131     xbt_die("Broken message");
132   memcpy(&base_message, buffer, sizeof(base_message));
133
134   switch(base_message.type) {
135
136   case MC_MESSAGE_IGNORE_HEAP:
137     {
138       s_mc_ignore_heap_message_t message;
139       if (size != sizeof(message))
140         xbt_die("Broken messsage");
141       memcpy(&message, buffer, sizeof(message));
142       mc_heap_ignore_region_t region = xbt_new(s_mc_heap_ignore_region_t, 1);
143       *region = message.region;
144       MC_heap_region_ignore_insert(region);
145       break;
146     }
147
148   case MC_MESSAGE_UNIGNORE_HEAP:
149     {
150       s_mc_ignore_memory_message_t message;
151       if (size != sizeof(message))
152         xbt_die("Broken messsage");
153       memcpy(&message, buffer, sizeof(message));
154       MC_heap_region_ignore_remove(
155         (void *)(std::uintptr_t) message.addr, message.size);
156       break;
157     }
158
159   case MC_MESSAGE_IGNORE_MEMORY:
160     {
161       s_mc_ignore_memory_message_t message;
162       if (size != sizeof(message))
163         xbt_die("Broken messsage");
164       memcpy(&message, buffer, sizeof(message));
165       mc_model_checker->process().ignore_region(
166         message.addr, message.size);
167       break;
168     }
169
170   case MC_MESSAGE_STACK_REGION:
171     {
172       s_mc_stack_region_message_t message;
173       if (size != sizeof(message))
174         xbt_die("Broken messsage");
175       memcpy(&message, buffer, sizeof(message));
176       stack_region_t stack_region = xbt_new(s_stack_region_t, 1);
177       *stack_region = message.stack_region;
178       MC_stack_area_add(stack_region);
179     }
180     break;
181
182   case MC_MESSAGE_REGISTER_SYMBOL:
183     {
184       s_mc_register_symbol_message_t message;
185       if (size != sizeof(message))
186         xbt_die("Broken message");
187       memcpy(&message, buffer, sizeof(message));
188       if (message.callback)
189         xbt_die("Support for client-side function proposition is not implemented.");
190       XBT_DEBUG("Received symbol: %s", message.name);
191
192       if (_mc_property_automaton == NULL)
193         _mc_property_automaton = xbt_automaton_new();
194
195       simgrid::mc::Process* process = &mc_model_checker->process();
196       simgrid::mc::remote_ptr<int> address
197         = simgrid::mc::remote((int*) message.data);
198       simgrid::xbt::add_proposition(_mc_property_automaton,
199         message.name,
200         [process, address]() { return process->read(address); }
201         );
202
203       break;
204     }
205
206   case MC_MESSAGE_WAITING:
207     return false;
208
209   case MC_MESSAGE_ASSERTION_FAILED:
210     MC_report_assertion_error();
211     ::exit(SIMGRID_MC_EXIT_SAFETY);
212     break;
213
214   default:
215     xbt_die("Unexpected message from model-checked application");
216
217   }
218   return true;
219 }
220
221 bool Server::handle_events()
222 {
223   char buffer[MC_MESSAGE_LENGTH];
224   struct pollfd* socket_pollfd = &fds[SOCKET_FD_INDEX];
225   struct pollfd* signalfd_pollfd = &fds[SIGNAL_FD_INDEX];
226
227   while(poll(fds, 2, -1) == -1) {
228     switch(errno) {
229     case EINTR:
230       continue;
231     default:
232       throw std::system_error(errno, std::system_category());
233     }
234   }
235
236   if (socket_pollfd->revents) {
237     if (socket_pollfd->revents & POLLIN) {
238       ssize_t size = MC_receive_message(socket_pollfd->fd, buffer, sizeof(buffer), MSG_DONTWAIT);
239       if (size == -1 && errno != EAGAIN)
240         throw std::system_error(errno, std::system_category());
241       return handle_message(buffer, size);
242     }
243     if (socket_pollfd->revents & POLLERR) {
244       throw_socket_error(socket_pollfd->fd);
245     }
246     if (socket_pollfd->revents & POLLHUP)
247       xbt_die("Socket hang up?");
248   }
249
250   if (signalfd_pollfd->revents) {
251     if (signalfd_pollfd->revents & POLLIN) {
252       this->handle_signals();
253       return true;
254     }
255     if (signalfd_pollfd->revents & POLLERR) {
256       throw_socket_error(signalfd_pollfd->fd);
257     }
258     if (signalfd_pollfd->revents & POLLHUP)
259       xbt_die("Signalfd hang up?");
260   }
261
262   return true;
263 }
264
265 void Server::loop()
266 {
267   while (mc_model_checker->process().running())
268     this->handle_events();
269 }
270
271 void Server::handle_signals()
272 {
273   struct signalfd_siginfo info;
274   struct pollfd* signalfd_pollfd = &fds[SIGNAL_FD_INDEX];
275   while (1) {
276     ssize_t size = read(signalfd_pollfd->fd, &info, sizeof(info));
277     if (size == -1) {
278       if (errno == EINTR)
279         continue;
280       else
281         throw std::system_error(errno, std::system_category());
282     } else if (size != sizeof(info))
283         return throw std::runtime_error(
284           "Bad communication with model-checked application");
285     else
286       break;
287   }
288   this->on_signal(&info);
289 }
290
291 void Server::handle_waitpid()
292 {
293   XBT_DEBUG("Check for wait event");
294   int status;
295   pid_t pid;
296   while ((pid = waitpid(-1, &status, WNOHANG)) != 0) {
297     if (pid == -1) {
298       if (errno == ECHILD) {
299         // No more children:
300         if (mc_model_checker->process().running())
301           xbt_die("Inconsistent state");
302         else
303           break;
304       } else {
305         XBT_ERROR("Could not wait for pid");
306         throw std::system_error(errno, std::system_category());
307       }
308     }
309
310     if (pid == mc_model_checker->process().pid()) {
311
312       // From PTRACE_O_TRACEEXIT:
313       if (status>>8 == (SIGTRAP | (PTRACE_EVENT_EXIT<<8))) {
314         if (ptrace(PTRACE_GETEVENTMSG, pid, 0, &status) == -1)
315           xbt_die("Could not get exit status");
316         if (WIFSIGNALED(status)) {
317           MC_report_crash(status);
318           ::exit(SIMGRID_MC_EXIT_PROGRAM_CRASH);
319         }
320       }
321
322       // We don't care about signals, just reinject them:
323       if (WIFSTOPPED(status)) {
324         XBT_DEBUG("Stopped with signal %i", (int) WSTOPSIG(status));
325         if (ptrace(PTRACE_CONT, pid, 0, WSTOPSIG(status)) == -1)
326           xbt_die("Could not PTRACE_CONT");
327       }
328
329       else if (WIFEXITED(status) || WIFSIGNALED(status)) {
330         XBT_DEBUG("Child process is over");
331         mc_model_checker->process().terminate(status);
332       }
333     }
334   }
335 }
336
337 void Server::on_signal(const struct signalfd_siginfo* info)
338 {
339   switch(info->ssi_signo) {
340   case SIGCHLD:
341     this->handle_waitpid();
342     break;
343   default:
344     break;
345   }
346 }
347
348 void Server::wait_client(simgrid::mc::Process& process)
349 {
350   this->resume(process);
351   while (mc_model_checker->process().running()) {
352     if (!simgrid::mc::server->handle_events())
353       return;
354   }
355 }
356
357 void Server::simcall_handle(simgrid::mc::Process& process, unsigned long pid, int value)
358 {
359   s_mc_simcall_handle_message m;
360   memset(&m, 0, sizeof(m));
361   m.type  = MC_MESSAGE_SIMCALL_HANDLE;
362   m.pid   = pid;
363   m.value = value;
364   process.send_message(m);
365   process.cache_flags = (mc_process_cache_flags_t) 0;
366   while (process.running()) {
367     if (!simgrid::mc::server->handle_events())
368       return;
369   }
370 }
371
372 }
373 }