Logo AND Algorithmique Numérique Distribuée

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