Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
[mc] Cross-process MC/safety implementation
[simgrid.git] / src / mc / 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
16 #include <xbt/log.h>
17
18 #include "mc_model_checker.h"
19 #include "mc_protocol.h"
20 #include "mc_server.h"
21 #include "mc_private.h"
22 #include "mc_ignore.h"
23
24 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_server, mc, "MC server logic");
25
26 // HArdcoded index for now:
27 #define SOCKET_FD_INDEX 0
28 #define SIGNAL_FD_INDEX 1
29
30 mc_server_t mc_server;
31
32 struct mc_symbol_pointer_callback
33 {
34   mc_process_t process;
35   void* value;
36 };
37
38 static int mc_symbol_pointer_callback_evaluate(void* p)
39 {
40   struct mc_symbol_pointer_callback* callback = (struct mc_symbol_pointer_callback*) p;
41   int value;
42   MC_process_read(callback->process, MC_ADDRESS_SPACE_READ_FLAGS_NONE,
43     &value, callback->value, sizeof(value), MC_PROCESS_INDEX_ANY);
44   return value;
45 }
46
47 s_mc_server::s_mc_server(pid_t pid, int socket)
48 {
49   this->pid = pid;
50   this->socket = socket;
51 }
52
53 void s_mc_server::start()
54 {
55   /* Wait for the target process to initialize and exchange a HELLO messages
56    * before trying to look at its memory map.
57    */
58   int res = MC_protocol_hello(socket);
59   if (res != 0)
60     throw std::system_error(res, std::system_category());
61
62   // Block SIGCHLD (this will be handled with accept/signalfd):
63   sigset_t set;
64   sigemptyset(&set);
65   sigaddset(&set, SIGCHLD);
66   if (sigprocmask(SIG_BLOCK, &set, NULL) == -1)
67     throw std::system_error(errno, std::system_category());
68
69   sigset_t full_set;
70   sigfillset(&full_set);
71
72   // Prepare data for poll:
73
74   struct pollfd* socket_pollfd = &fds[SOCKET_FD_INDEX];
75   socket_pollfd->fd = socket;
76   socket_pollfd->events = POLLIN;
77   socket_pollfd->revents = 0;
78
79   int signal_fd = signalfd(-1, &set, 0);
80   if (signal_fd == -1)
81     throw std::system_error(errno, std::system_category());
82
83   struct pollfd* signalfd_pollfd = &fds[SIGNAL_FD_INDEX];
84   signalfd_pollfd->fd = signal_fd;
85   signalfd_pollfd->events = POLLIN;
86   signalfd_pollfd->revents = 0;
87 }
88
89 void s_mc_server::shutdown()
90 {
91   XBT_DEBUG("Shuting down model-checker");
92
93   mc_process_t process = &mc_model_checker->process;
94   int status = process->status;
95   if (process->running) {
96     XBT_DEBUG("Killing process");
97     kill(process->pid, SIGTERM);
98     if (waitpid(process->pid, &status, 0) == -1)
99       throw std::system_error(errno, std::system_category());
100     // TODO, handle the case when the process does not want to die with a timeout
101     process->status = status;
102   }
103 }
104
105 void s_mc_server::exit()
106 {
107   // Finished:
108   int status = mc_model_checker->process.status;
109   if (WIFEXITED(status))
110     ::exit(WEXITSTATUS(status));
111   else if (WIFSIGNALED(status)) {
112     // Try to uplicate the signal of the model-checked process.
113     // This is a temporary hack so we don't try too hard.
114     kill(mc_model_checker->process.pid, WTERMSIG(status));
115     abort();
116   } else {
117     xbt_die("Unexpected status from model-checked process");
118   }
119 }
120
121 void s_mc_server::resume(mc_process_t process)
122 {
123   int socket = process->socket;
124   int res = MC_protocol_send_simple_message(socket, MC_MESSAGE_CONTINUE);
125   if (res)
126     throw std::system_error(res, std::system_category());
127   process->cache_flags = (e_mc_process_cache_flags_t) 0;
128 }
129
130 static
131 void throw_socket_error(int fd)
132 {
133   int error = 0;
134   socklen_t errlen = sizeof(error);
135   if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&error, &errlen) == -1)
136     error = errno;
137   throw std::system_error(error, std::system_category());
138 }
139
140 bool s_mc_server::handle_events()
141 {
142   char buffer[MC_MESSAGE_LENGTH];
143   struct pollfd* socket_pollfd = &fds[SOCKET_FD_INDEX];
144   struct pollfd* signalfd_pollfd = &fds[SIGNAL_FD_INDEX];
145
146   while(poll(fds, 2, -1) == -1) {
147     switch(errno) {
148     case EINTR:
149       continue;
150     default:
151       throw std::system_error(errno, std::system_category());
152     }
153   }
154
155   if (socket_pollfd->revents) {
156     if (socket_pollfd->revents & POLLIN) {
157
158       ssize_t size = MC_receive_message(socket_pollfd->fd, buffer, sizeof(buffer), MSG_DONTWAIT);
159       if (size == -1 && errno != EAGAIN)
160         throw std::system_error(errno, std::system_category());
161
162       s_mc_message_t base_message;
163       if (size < (ssize_t) sizeof(base_message))
164         xbt_die("Broken message");
165       memcpy(&base_message, buffer, sizeof(base_message));
166
167       switch(base_message.type) {
168
169       case MC_MESSAGE_IGNORE_HEAP:
170         {
171           s_mc_ignore_heap_message_t message;
172           if (size != sizeof(message))
173             xbt_die("Broken messsage");
174           memcpy(&message, buffer, sizeof(message));
175           mc_heap_ignore_region_t region = xbt_new(s_mc_heap_ignore_region_t, 1);
176           *region = message.region;
177           MC_heap_region_ignore_insert(region);
178           break;
179         }
180
181       case MC_MESSAGE_UNIGNORE_HEAP:
182         {
183           s_mc_ignore_memory_message_t message;
184           if (size != sizeof(message))
185             xbt_die("Broken messsage");
186           memcpy(&message, buffer, sizeof(message));
187           MC_remove_ignore_heap(message.addr, message.size);
188           break;
189         }
190
191       case MC_MESSAGE_IGNORE_MEMORY:
192         {
193           s_mc_ignore_memory_message_t message;
194           if (size != sizeof(message))
195             xbt_die("Broken messsage");
196           memcpy(&message, buffer, sizeof(message));
197           MC_process_ignore_memory(&mc_model_checker->process,
198             message.addr, message.size);
199           break;
200         }
201
202       case MC_MESSAGE_STACK_REGION:
203         {
204           s_mc_stack_region_message_t message;
205           if (size != sizeof(message))
206             xbt_die("Broken messsage");
207           memcpy(&message, buffer, sizeof(message));
208           stack_region_t stack_region = xbt_new(s_stack_region_t, 1);
209           *stack_region = message.stack_region;
210           MC_stack_area_add(stack_region);
211         }
212         break;
213
214       case MC_MESSAGE_REGISTER_SYMBOL:
215         {
216           s_mc_register_symbol_message_t message;
217           if (size != sizeof(message))
218             xbt_die("Broken message");
219           memcpy(&message, buffer, sizeof(message));
220           if (message.callback)
221             xbt_die("Support for callbacks/functions symbols not implemented in client/server mode.");
222           XBT_DEBUG("Received symbol: %s", message.name);
223
224           struct mc_symbol_pointer_callback* callback = xbt_new(struct mc_symbol_pointer_callback, 1);
225           callback->process = &mc_model_checker->process;
226           callback->value   = message.data;
227
228           MC_automaton_new_propositional_symbol_callback(message.name,
229             mc_symbol_pointer_callback_evaluate, callback, free);
230           break;
231         }
232
233       case MC_MESSAGE_WAITING:
234         return false;
235
236       case MC_MESSAGE_ASSERTION_FAILED:
237         MC_report_assertion_error();
238         xbt_abort();
239         break;
240
241       default:
242         xbt_die("Unexpected message from model-checked application");
243
244       }
245       return true;
246     }
247     if (socket_pollfd->revents & POLLERR) {
248       throw_socket_error(socket_pollfd->fd);
249     }
250     if (socket_pollfd->revents & POLLHUP)
251       xbt_die("Socket hang up?");
252   }
253
254   if (signalfd_pollfd->revents) {
255     if (signalfd_pollfd->revents & POLLIN) {
256       this->handle_signals();
257       return true;
258     }
259     if (signalfd_pollfd->revents & POLLERR) {
260       throw_socket_error(signalfd_pollfd->fd);
261     }
262     if (signalfd_pollfd->revents & POLLHUP)
263       xbt_die("Signalfd hang up?");
264   }
265
266   return true;
267 }
268
269 void s_mc_server::loop()
270 {
271   while (mc_model_checker->process.running)
272     this->handle_events();
273 }
274
275 void s_mc_server::handle_signals()
276 {
277   struct signalfd_siginfo info;
278   struct pollfd* signalfd_pollfd = &fds[SIGNAL_FD_INDEX];
279   while (1) {
280     ssize_t size = read(signalfd_pollfd->fd, &info, sizeof(info));
281     if (size == -1) {
282       if (errno == EINTR)
283         continue;
284       else
285         throw std::system_error(errno, std::system_category());
286     } else if (size != sizeof(info))
287         return throw std::runtime_error(
288           "Bad communication with model-checked application");
289     else
290       break;
291   }
292   this->on_signal(&info);
293 }
294
295 void s_mc_server::handle_waitpid()
296 {
297   XBT_DEBUG("Check for wait event");
298   int status;
299   pid_t pid;
300   while ((pid = waitpid(-1, &status, WNOHANG)) != 0) {
301     if (pid == -1) {
302       if (errno == ECHILD) {
303         // No more children:
304         if (mc_model_checker->process.running)
305           xbt_die("Inconsistent state");
306         else
307           break;
308       } else {
309         XBT_ERROR("Could not wait for pid");
310         throw std::system_error(errno, std::system_category());
311       }
312     }
313
314     if (pid == mc_model_checker->process.pid) {
315       if (WIFEXITED(status) || WIFSIGNALED(status)) {
316         XBT_DEBUG("Child process is over");
317         mc_model_checker->process.status = status;
318         mc_model_checker->process.running = false;
319       }
320     }
321   }
322 }
323
324 void s_mc_server::on_signal(const struct signalfd_siginfo* info)
325 {
326   switch(info->ssi_signo) {
327   case SIGCHLD:
328     this->handle_waitpid();
329     break;
330   default:
331     break;
332   }
333 }
334
335 void MC_server_wait_client(mc_process_t process)
336 {
337   mc_server->resume(process);
338   while (mc_model_checker->process.running) {
339     if (!mc_server->handle_events())
340       return;
341   }
342 }
343
344 void MC_server_simcall_handle(mc_process_t process, unsigned long pid, int value)
345 {
346   s_mc_simcall_handle_message m;
347   memset(&m, 0, sizeof(m));
348   m.type  = MC_MESSAGE_SIMCALL_HANDLE;
349   m.pid   = pid;
350   m.value = value;
351   MC_protocol_send(mc_model_checker->process.socket, &m, sizeof(m));
352   process->cache_flags = (e_mc_process_cache_flags_t) 0;
353   while (mc_model_checker->process.running) {
354     if (!mc_server->handle_events())
355       return;
356   }
357 }