Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
d49031308299132c6c69240c9d43daf03bf4f03a
[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   if (process->running()) {
99     XBT_DEBUG("Killing process");
100     kill(process->pid(), SIGTERM);
101     process->terminate();
102   }
103 }
104
105 void Server::resume(simgrid::mc::Process& process)
106 {
107   int res = process.send_message(MC_MESSAGE_CONTINUE);
108   if (res)
109     throw std::system_error(res, std::system_category());
110   process.cache_flags = (mc_process_cache_flags_t) 0;
111 }
112
113 static
114 void throw_socket_error(int fd)
115 {
116   int error = 0;
117   socklen_t errlen = sizeof(error);
118   if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&error, &errlen) == -1)
119     error = errno;
120   throw std::system_error(error, std::system_category());
121 }
122
123 bool Server::handle_message(char* buffer, ssize_t size)
124 {
125   s_mc_message_t base_message;
126   if (size < (ssize_t) sizeof(base_message))
127     xbt_die("Broken message");
128   memcpy(&base_message, buffer, sizeof(base_message));
129
130   switch(base_message.type) {
131
132   case MC_MESSAGE_IGNORE_HEAP:
133     {
134       s_mc_ignore_heap_message_t message;
135       if (size != sizeof(message))
136         xbt_die("Broken messsage");
137       memcpy(&message, buffer, sizeof(message));
138       mc_heap_ignore_region_t region = xbt_new(s_mc_heap_ignore_region_t, 1);
139       *region = message.region;
140       MC_heap_region_ignore_insert(region);
141       break;
142     }
143
144   case MC_MESSAGE_UNIGNORE_HEAP:
145     {
146       s_mc_ignore_memory_message_t message;
147       if (size != sizeof(message))
148         xbt_die("Broken messsage");
149       memcpy(&message, buffer, sizeof(message));
150       MC_heap_region_ignore_remove(
151         (void *)(std::uintptr_t) message.addr, message.size);
152       break;
153     }
154
155   case MC_MESSAGE_IGNORE_MEMORY:
156     {
157       s_mc_ignore_memory_message_t message;
158       if (size != sizeof(message))
159         xbt_die("Broken messsage");
160       memcpy(&message, buffer, sizeof(message));
161       mc_model_checker->process().ignore_region(
162         message.addr, message.size);
163       break;
164     }
165
166   case MC_MESSAGE_STACK_REGION:
167     {
168       s_mc_stack_region_message_t message;
169       if (size != sizeof(message))
170         xbt_die("Broken messsage");
171       memcpy(&message, buffer, sizeof(message));
172       stack_region_t stack_region = xbt_new(s_stack_region_t, 1);
173       *stack_region = message.stack_region;
174       MC_stack_area_add(stack_region);
175     }
176     break;
177
178   case MC_MESSAGE_REGISTER_SYMBOL:
179     {
180       s_mc_register_symbol_message_t message;
181       if (size != sizeof(message))
182         xbt_die("Broken message");
183       memcpy(&message, buffer, sizeof(message));
184       if (message.callback)
185         xbt_die("Support for client-side function proposition is not implemented.");
186       XBT_DEBUG("Received symbol: %s", message.name);
187
188       if (_mc_property_automaton == NULL)
189         _mc_property_automaton = xbt_automaton_new();
190
191       simgrid::mc::Process* process = &mc_model_checker->process();
192       simgrid::mc::remote_ptr<int> address
193         = simgrid::mc::remote((int*) message.data);
194       simgrid::xbt::add_proposition(_mc_property_automaton,
195         message.name,
196         [process, address]() { return process->read(address); }
197         );
198
199       break;
200     }
201
202   case MC_MESSAGE_WAITING:
203     return false;
204
205   case MC_MESSAGE_ASSERTION_FAILED:
206     MC_report_assertion_error();
207     ::exit(SIMGRID_MC_EXIT_SAFETY);
208     break;
209
210   default:
211     xbt_die("Unexpected message from model-checked application");
212
213   }
214   return true;
215 }
216
217 bool Server::handle_events()
218 {
219   char buffer[MC_MESSAGE_LENGTH];
220   struct pollfd* socket_pollfd = &fds[SOCKET_FD_INDEX];
221   struct pollfd* signalfd_pollfd = &fds[SIGNAL_FD_INDEX];
222
223   while(poll(fds, 2, -1) == -1) {
224     switch(errno) {
225     case EINTR:
226       continue;
227     default:
228       throw std::system_error(errno, std::system_category());
229     }
230   }
231
232   if (socket_pollfd->revents) {
233     if (socket_pollfd->revents & POLLIN) {
234       ssize_t size = MC_receive_message(socket_pollfd->fd, buffer, sizeof(buffer), MSG_DONTWAIT);
235       if (size == -1 && errno != EAGAIN)
236         throw std::system_error(errno, std::system_category());
237       return handle_message(buffer, size);
238     }
239     if (socket_pollfd->revents & POLLERR) {
240       throw_socket_error(socket_pollfd->fd);
241     }
242     if (socket_pollfd->revents & POLLHUP)
243       xbt_die("Socket hang up?");
244   }
245
246   if (signalfd_pollfd->revents) {
247     if (signalfd_pollfd->revents & POLLIN) {
248       this->handle_signals();
249       return true;
250     }
251     if (signalfd_pollfd->revents & POLLERR) {
252       throw_socket_error(signalfd_pollfd->fd);
253     }
254     if (signalfd_pollfd->revents & POLLHUP)
255       xbt_die("Signalfd hang up?");
256   }
257
258   return true;
259 }
260
261 void Server::loop()
262 {
263   while (mc_model_checker->process().running())
264     this->handle_events();
265 }
266
267 void Server::handle_signals()
268 {
269   struct signalfd_siginfo info;
270   struct pollfd* signalfd_pollfd = &fds[SIGNAL_FD_INDEX];
271   while (1) {
272     ssize_t size = read(signalfd_pollfd->fd, &info, sizeof(info));
273     if (size == -1) {
274       if (errno == EINTR)
275         continue;
276       else
277         throw std::system_error(errno, std::system_category());
278     } else if (size != sizeof(info))
279         return throw std::runtime_error(
280           "Bad communication with model-checked application");
281     else
282       break;
283   }
284   this->on_signal(&info);
285 }
286
287 void Server::handle_waitpid()
288 {
289   XBT_DEBUG("Check for wait event");
290   int status;
291   pid_t pid;
292   while ((pid = waitpid(-1, &status, WNOHANG)) != 0) {
293     if (pid == -1) {
294       if (errno == ECHILD) {
295         // No more children:
296         if (mc_model_checker->process().running())
297           xbt_die("Inconsistent state");
298         else
299           break;
300       } else {
301         XBT_ERROR("Could not wait for pid");
302         throw std::system_error(errno, std::system_category());
303       }
304     }
305
306     if (pid == mc_model_checker->process().pid()) {
307
308       // From PTRACE_O_TRACEEXIT:
309       if (status>>8 == (SIGTRAP | (PTRACE_EVENT_EXIT<<8))) {
310         if (ptrace(PTRACE_GETEVENTMSG, pid, 0, &status) == -1)
311           xbt_die("Could not get exit status");
312         if (WIFSIGNALED(status)) {
313           MC_report_crash(status);
314           ::exit(SIMGRID_MC_EXIT_PROGRAM_CRASH);
315         }
316       }
317
318       // We don't care about signals, just reinject them:
319       if (WIFSTOPPED(status)) {
320         XBT_DEBUG("Stopped with signal %i", (int) WSTOPSIG(status));
321         if (ptrace(PTRACE_CONT, pid, 0, WSTOPSIG(status)) == -1)
322           xbt_die("Could not PTRACE_CONT");
323       }
324
325       else if (WIFEXITED(status) || WIFSIGNALED(status)) {
326         XBT_DEBUG("Child process is over");
327         mc_model_checker->process().terminate();
328       }
329     }
330   }
331 }
332
333 void Server::on_signal(const struct signalfd_siginfo* info)
334 {
335   switch(info->ssi_signo) {
336   case SIGCHLD:
337     this->handle_waitpid();
338     break;
339   default:
340     break;
341   }
342 }
343
344 void Server::wait_client(simgrid::mc::Process& process)
345 {
346   this->resume(process);
347   while (mc_model_checker->process().running()) {
348     if (!simgrid::mc::server->handle_events())
349       return;
350   }
351 }
352
353 void Server::simcall_handle(simgrid::mc::Process& process, unsigned long pid, int value)
354 {
355   s_mc_simcall_handle_message m;
356   memset(&m, 0, sizeof(m));
357   m.type  = MC_MESSAGE_SIMCALL_HANDLE;
358   m.pid   = pid;
359   m.value = value;
360   process.send_message(m);
361   process.cache_flags = (mc_process_cache_flags_t) 0;
362   while (process.running()) {
363     if (!simgrid::mc::server->handle_events())
364       return;
365   }
366 }
367
368 }
369 }