Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
c9dc25f939f54dc38977a491dd8b240ad541e47b
[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 s_mc_server::s_mc_server(pid_t pid, int socket)
33 {
34   this->pid = pid;
35   this->socket = socket;
36 }
37
38 void s_mc_server::start()
39 {
40   /* Wait for the target process to initialize and exchange a HELLO messages
41    * before trying to look at its memory map.
42    */
43   XBT_DEBUG("Greeting the MC client");
44   int res = MC_protocol_hello(socket);
45   if (res != 0)
46     throw std::system_error(res, std::system_category());
47   XBT_DEBUG("Greeted the MC client");
48
49   // Block SIGCHLD (this will be handled with accept/signalfd):
50   sigset_t set;
51   sigemptyset(&set);
52   sigaddset(&set, SIGCHLD);
53   if (sigprocmask(SIG_BLOCK, &set, NULL) == -1)
54     throw std::system_error(errno, std::system_category());
55
56   sigset_t full_set;
57   sigfillset(&full_set);
58
59   // Prepare data for poll:
60
61   struct pollfd* socket_pollfd = &fds[SOCKET_FD_INDEX];
62   socket_pollfd->fd = socket;
63   socket_pollfd->events = POLLIN;
64   socket_pollfd->revents = 0;
65
66   int signal_fd = signalfd(-1, &set, 0);
67   if (signal_fd == -1)
68     throw std::system_error(errno, std::system_category());
69
70   struct pollfd* signalfd_pollfd = &fds[SIGNAL_FD_INDEX];
71   signalfd_pollfd->fd = signal_fd;
72   signalfd_pollfd->events = POLLIN;
73   signalfd_pollfd->revents = 0;
74 }
75
76 void s_mc_server::shutdown()
77 {
78   XBT_DEBUG("Shuting down model-checker");
79
80   mc_process_t process = &mc_model_checker->process;
81   int status = process->status;
82   if (process->running) {
83     XBT_DEBUG("Killing process");
84     kill(process->pid, SIGTERM);
85     if (waitpid(process->pid, &status, 0) == -1)
86       throw std::system_error(errno, std::system_category());
87     // TODO, handle the case when the process does not want to die with a timeout
88     process->status = status;
89   }
90 }
91
92 void s_mc_server::exit()
93 {
94   // Finished:
95   int status = mc_model_checker->process.status;
96   if (WIFEXITED(status))
97     ::exit(WEXITSTATUS(status));
98   else if (WIFSIGNALED(status)) {
99     // Try to uplicate the signal of the model-checked process.
100     // This is a temporary hack so we don't try too hard.
101     kill(mc_model_checker->process.pid, WTERMSIG(status));
102     abort();
103   } else {
104     xbt_die("Unexpected status from model-checked process");
105   }
106 }
107
108 void s_mc_server::resume(mc_process_t process)
109 {
110   int socket = process->socket;
111   int res = MC_protocol_send_simple_message(socket, MC_MESSAGE_CONTINUE);
112   if (res)
113     throw std::system_error(res, std::system_category());
114 }
115
116 static
117 void throw_socket_error(int fd)
118 {
119   int error = 0;
120   socklen_t errlen = sizeof(error);
121   if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&error, &errlen) == -1)
122     error = errno;
123   throw std::system_error(error, std::system_category());
124 }
125
126 void s_mc_server::handle_events()
127 {
128   char buffer[MC_MESSAGE_LENGTH];
129   struct pollfd* socket_pollfd = &fds[SOCKET_FD_INDEX];
130   struct pollfd* signalfd_pollfd = &fds[SIGNAL_FD_INDEX];
131
132   while(poll(fds, 2, -1) == -1) {
133     switch(errno) {
134     case EINTR:
135       continue;
136     default:
137       throw std::system_error(errno, std::system_category());
138     }
139   }
140
141   if (socket_pollfd->revents) {
142     if (socket_pollfd->revents & POLLIN) {
143
144       ssize_t size = recv(socket_pollfd->fd, buffer, sizeof(buffer), MSG_DONTWAIT);
145       if (size == -1 && errno != EAGAIN)
146         throw std::system_error(errno, std::system_category());
147
148       s_mc_message_t base_message;
149       if (size < (ssize_t) sizeof(base_message))
150         xbt_die("Broken message");
151       memcpy(&base_message, buffer, sizeof(base_message));
152
153       switch(base_message.type) {
154
155       case MC_MESSAGE_IGNORE_HEAP:
156         {
157           XBT_DEBUG("Received ignored region");
158           s_mc_ignore_heap_message_t message;
159           if (size != sizeof(message))
160             xbt_die("Broken messsage");
161           memcpy(&message, buffer, sizeof(message));
162           mc_heap_ignore_region_t region = xbt_new(s_mc_heap_ignore_region_t, 1);
163           *region = message.region;
164           MC_heap_region_ignore_insert(region);
165           break;
166         }
167
168
169       case MC_MESSAGE_UNIGNORE_HEAP:
170         {
171           XBT_DEBUG("Received unignored region");
172           s_mc_ignore_memory_message_t message;
173           if (size != sizeof(message))
174             xbt_die("Broken messsage");
175           memcpy(&message, buffer, sizeof(message));
176           MC_remove_ignore_heap(message.addr, message.size);
177           break;
178         }
179
180       case MC_MESSAGE_IGNORE_MEMORY:
181         {
182           XBT_DEBUG("Received ignored memory");
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_process_ignore_memory(&mc_model_checker->process,
188             message.addr, message.size);
189           break;
190         }
191
192       case MC_MESSAGE_STACK_REGION:
193         {
194           XBT_DEBUG("Received stack area");
195           s_mc_stack_region_message_t message;
196           if (size != sizeof(message))
197             xbt_die("Broken messsage");
198           memcpy(&message, buffer, sizeof(message));
199           stack_region_t stack_region = xbt_new(s_stack_region_t, 1);
200           *stack_region = message.stack_region;
201           MC_stack_area_add(stack_region);
202         }
203         break;
204
205       default:
206         xbt_die("Unexpected message from model-checked application");
207
208       }
209       return;
210     }
211     if (socket_pollfd->revents & POLLERR) {
212       throw_socket_error(socket_pollfd->fd);
213     }
214     if (socket_pollfd->revents & POLLHUP)
215       xbt_die("Socket hang up?");
216   }
217
218   if (signalfd_pollfd->revents) {
219     if (signalfd_pollfd->revents & POLLIN) {
220       this->handle_signals();
221       return;
222     }
223     if (signalfd_pollfd->revents & POLLERR) {
224       throw_socket_error(signalfd_pollfd->fd);
225     }
226     if (signalfd_pollfd->revents & POLLHUP)
227       xbt_die("Signalfd hang up?");
228   }
229 }
230
231 void s_mc_server::loop()
232 {
233   while (mc_model_checker->process.running)
234     this->handle_events();
235 }
236
237 void s_mc_server::handle_signals()
238 {
239   struct signalfd_siginfo info;
240   struct pollfd* signalfd_pollfd = &fds[SIGNAL_FD_INDEX];
241   while (1) {
242     ssize_t size = read(signalfd_pollfd->fd, &info, sizeof(info));
243     if (size == -1) {
244       if (errno == EINTR)
245         continue;
246       else
247         throw std::system_error(errno, std::system_category());
248     } else if (size != sizeof(info))
249         return throw std::runtime_error(
250           "Bad communication with model-checked application");
251     else
252       break;
253   }
254   this->on_signal(&info);
255 }
256
257 void s_mc_server::handle_waitpid()
258 {
259   XBT_DEBUG("Check for wait event");
260   int status;
261   pid_t pid;
262   while ((pid = waitpid(-1, &status, WNOHANG)) != 0) {
263     if (pid == -1) {
264       if (errno == ECHILD) {
265         // No more children:
266         if (mc_model_checker->process.running)
267           xbt_die("Inconsistent state");
268         else
269           break;
270       } else {
271         XBT_ERROR("Could not wait for pid: %s", strerror(errno));
272         throw std::system_error(errno, std::system_category());
273       }
274     }
275
276     if (pid == mc_model_checker->process.pid) {
277       if (WIFEXITED(status) || WIFSIGNALED(status)) {
278         XBT_DEBUG("Child process is over");
279         mc_model_checker->process.status = status;
280         mc_model_checker->process.running = false;
281       }
282     }
283   }
284 }
285
286 void s_mc_server::on_signal(const struct signalfd_siginfo* info)
287 {
288   switch(info->ssi_signo) {
289   case SIGCHLD:
290     this->handle_waitpid();
291     break;
292   default:
293     break;
294   }
295 }