Logo AND Algorithmique Numérique Distribuée

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