1 /* Copyright (c) 2015. The SimGrid Team.
2 * All rights reserved. */
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. */
8 #include <system_error>
11 #include <sys/types.h>
13 #include <sys/socket.h>
14 #include <sys/signalfd.h>
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"
24 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_server, mc, "MC server logic");
26 // HArdcoded index for now:
27 #define SOCKET_FD_INDEX 0
28 #define SIGNAL_FD_INDEX 1
30 mc_server_t mc_server;
32 s_mc_server::s_mc_server(pid_t pid, int socket)
35 this->socket = socket;
38 void s_mc_server::start()
40 /* Wait for the target process to initialize and exchange a HELLO messages
41 * before trying to look at its memory map.
43 XBT_DEBUG("Greeting the MC client");
44 int res = MC_protocol_hello(socket);
46 throw std::system_error(res, std::system_category());
47 XBT_DEBUG("Greeted the MC client");
49 // Block SIGCHLD (this will be handled with accept/signalfd):
52 sigaddset(&set, SIGCHLD);
53 if (sigprocmask(SIG_BLOCK, &set, NULL) == -1)
54 throw std::system_error(errno, std::system_category());
57 sigfillset(&full_set);
59 // Prepare data for poll:
61 struct pollfd* socket_pollfd = &fds[SOCKET_FD_INDEX];
62 socket_pollfd->fd = socket;
63 socket_pollfd->events = POLLIN;
64 socket_pollfd->revents = 0;
66 int signal_fd = signalfd(-1, &set, 0);
68 throw std::system_error(errno, std::system_category());
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;
76 void s_mc_server::shutdown()
78 XBT_DEBUG("Shuting down model-checker");
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;
92 void s_mc_server::exit()
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));
104 xbt_die("Unexpected status from model-checked process");
108 void s_mc_server::resume(mc_process_t process)
110 int socket = process->socket;
111 int res = MC_protocol_send_simple_message(socket, MC_MESSAGE_CONTINUE);
113 throw std::system_error(res, std::system_category());
117 void throw_socket_error(int fd)
120 socklen_t errlen = sizeof(error);
121 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&error, &errlen) == -1)
123 throw std::system_error(error, std::system_category());
126 void s_mc_server::handle_events()
128 char buffer[MC_MESSAGE_LENGTH];
129 struct pollfd* socket_pollfd = &fds[SOCKET_FD_INDEX];
130 struct pollfd* signalfd_pollfd = &fds[SIGNAL_FD_INDEX];
132 while(poll(fds, 2, -1) == -1) {
137 throw std::system_error(errno, std::system_category());
141 if (socket_pollfd->revents) {
142 if (socket_pollfd->revents & POLLIN) {
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());
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));
153 switch(base_message.type) {
155 case MC_MESSAGE_IGNORE_HEAP:
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);
169 case MC_MESSAGE_UNIGNORE_HEAP:
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);
180 case MC_MESSAGE_IGNORE_MEMORY:
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);
192 case MC_MESSAGE_STACK_REGION:
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);
206 xbt_die("Unexpected message from model-checked application");
211 if (socket_pollfd->revents & POLLERR) {
212 throw_socket_error(socket_pollfd->fd);
214 if (socket_pollfd->revents & POLLHUP)
215 xbt_die("Socket hang up?");
218 if (signalfd_pollfd->revents) {
219 if (signalfd_pollfd->revents & POLLIN) {
220 this->handle_signals();
223 if (signalfd_pollfd->revents & POLLERR) {
224 throw_socket_error(signalfd_pollfd->fd);
226 if (signalfd_pollfd->revents & POLLHUP)
227 xbt_die("Signalfd hang up?");
231 void s_mc_server::loop()
233 while (mc_model_checker->process.running)
234 this->handle_events();
237 void s_mc_server::handle_signals()
239 struct signalfd_siginfo info;
240 struct pollfd* signalfd_pollfd = &fds[SIGNAL_FD_INDEX];
242 ssize_t size = read(signalfd_pollfd->fd, &info, sizeof(info));
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");
254 this->on_signal(&info);
257 void s_mc_server::handle_waitpid()
259 XBT_DEBUG("Check for wait event");
262 while ((pid = waitpid(-1, &status, WNOHANG)) != 0) {
264 if (errno == ECHILD) {
266 if (mc_model_checker->process.running)
267 xbt_die("Inconsistent state");
271 XBT_ERROR("Could not wait for pid: %s", strerror(errno));
272 throw std::system_error(errno, std::system_category());
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;
286 void s_mc_server::on_signal(const struct signalfd_siginfo* info)
288 switch(info->ssi_signo) {
290 this->handle_waitpid();