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 struct mc_symbol_pointer_callback
38 static int mc_symbol_pointer_callback_evaluate(void* p)
40 struct mc_symbol_pointer_callback* callback = (struct mc_symbol_pointer_callback*) p;
42 MC_process_read(callback->process, MC_ADDRESS_SPACE_READ_FLAGS_NONE,
43 &value, callback->value, sizeof(value), MC_PROCESS_INDEX_ANY);
47 s_mc_server::s_mc_server(pid_t pid, int socket)
50 this->socket = socket;
53 void s_mc_server::start()
55 /* Wait for the target process to initialize and exchange a HELLO messages
56 * before trying to look at its memory map.
58 XBT_DEBUG("Greeting the MC client");
59 int res = MC_protocol_hello(socket);
61 throw std::system_error(res, std::system_category());
62 XBT_DEBUG("Greeted the MC client");
64 // Block SIGCHLD (this will be handled with accept/signalfd):
67 sigaddset(&set, SIGCHLD);
68 if (sigprocmask(SIG_BLOCK, &set, NULL) == -1)
69 throw std::system_error(errno, std::system_category());
72 sigfillset(&full_set);
74 // Prepare data for poll:
76 struct pollfd* socket_pollfd = &fds[SOCKET_FD_INDEX];
77 socket_pollfd->fd = socket;
78 socket_pollfd->events = POLLIN;
79 socket_pollfd->revents = 0;
81 int signal_fd = signalfd(-1, &set, 0);
83 throw std::system_error(errno, std::system_category());
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;
91 void s_mc_server::shutdown()
93 XBT_DEBUG("Shuting down model-checker");
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;
107 void s_mc_server::exit()
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));
119 xbt_die("Unexpected status from model-checked process");
123 void s_mc_server::resume(mc_process_t process)
125 int socket = process->socket;
126 int res = MC_protocol_send_simple_message(socket, MC_MESSAGE_CONTINUE);
128 throw std::system_error(res, std::system_category());
132 void throw_socket_error(int fd)
135 socklen_t errlen = sizeof(error);
136 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&error, &errlen) == -1)
138 throw std::system_error(error, std::system_category());
141 void s_mc_server::handle_events()
143 char buffer[MC_MESSAGE_LENGTH];
144 struct pollfd* socket_pollfd = &fds[SOCKET_FD_INDEX];
145 struct pollfd* signalfd_pollfd = &fds[SIGNAL_FD_INDEX];
147 while(poll(fds, 2, -1) == -1) {
152 throw std::system_error(errno, std::system_category());
156 if (socket_pollfd->revents) {
157 if (socket_pollfd->revents & POLLIN) {
159 ssize_t size = recv(socket_pollfd->fd, buffer, sizeof(buffer), MSG_DONTWAIT);
160 if (size == -1 && errno != EAGAIN)
161 throw std::system_error(errno, std::system_category());
163 s_mc_message_t base_message;
164 if (size < (ssize_t) sizeof(base_message))
165 xbt_die("Broken message");
166 memcpy(&base_message, buffer, sizeof(base_message));
168 switch(base_message.type) {
170 case MC_MESSAGE_IGNORE_HEAP:
172 XBT_DEBUG("Received ignored region");
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);
184 case MC_MESSAGE_UNIGNORE_HEAP:
186 XBT_DEBUG("Received unignored region");
187 s_mc_ignore_memory_message_t message;
188 if (size != sizeof(message))
189 xbt_die("Broken messsage");
190 memcpy(&message, buffer, sizeof(message));
191 MC_remove_ignore_heap(message.addr, message.size);
195 case MC_MESSAGE_IGNORE_MEMORY:
197 XBT_DEBUG("Received ignored memory");
198 s_mc_ignore_memory_message_t message;
199 if (size != sizeof(message))
200 xbt_die("Broken messsage");
201 memcpy(&message, buffer, sizeof(message));
202 MC_process_ignore_memory(&mc_model_checker->process,
203 message.addr, message.size);
207 case MC_MESSAGE_STACK_REGION:
209 XBT_DEBUG("Received stack area");
210 s_mc_stack_region_message_t message;
211 if (size != sizeof(message))
212 xbt_die("Broken messsage");
213 memcpy(&message, buffer, sizeof(message));
214 stack_region_t stack_region = xbt_new(s_stack_region_t, 1);
215 *stack_region = message.stack_region;
216 MC_stack_area_add(stack_region);
220 case MC_MESSAGE_REGISTER_SYMBOL:
222 s_mc_register_symbol_message_t message;
223 if (size != sizeof(message))
224 xbt_die("Broken message");
225 memcpy(&message, buffer, sizeof(message));
226 if (message.callback)
227 xbt_die("Support for callbacks/functions symbols not implemented in client/server mode.");
228 XBT_DEBUG("Received symbol: %s", message.name);
230 struct mc_symbol_pointer_callback* callback = xbt_new(struct mc_symbol_pointer_callback, 1);
231 callback->process = &mc_model_checker->process;
232 callback->value = message.data;
234 MC_automaton_new_propositional_symbol_callback(message.name,
235 mc_symbol_pointer_callback_evaluate, callback, free);
240 xbt_die("Unexpected message from model-checked application");
245 if (socket_pollfd->revents & POLLERR) {
246 throw_socket_error(socket_pollfd->fd);
248 if (socket_pollfd->revents & POLLHUP)
249 xbt_die("Socket hang up?");
252 if (signalfd_pollfd->revents) {
253 if (signalfd_pollfd->revents & POLLIN) {
254 this->handle_signals();
257 if (signalfd_pollfd->revents & POLLERR) {
258 throw_socket_error(signalfd_pollfd->fd);
260 if (signalfd_pollfd->revents & POLLHUP)
261 xbt_die("Signalfd hang up?");
265 void s_mc_server::loop()
267 while (mc_model_checker->process.running)
268 this->handle_events();
271 void s_mc_server::handle_signals()
273 struct signalfd_siginfo info;
274 struct pollfd* signalfd_pollfd = &fds[SIGNAL_FD_INDEX];
276 ssize_t size = read(signalfd_pollfd->fd, &info, sizeof(info));
281 throw std::system_error(errno, std::system_category());
282 } else if (size != sizeof(info))
283 return throw std::runtime_error(
284 "Bad communication with model-checked application");
288 this->on_signal(&info);
291 void s_mc_server::handle_waitpid()
293 XBT_DEBUG("Check for wait event");
296 while ((pid = waitpid(-1, &status, WNOHANG)) != 0) {
298 if (errno == ECHILD) {
300 if (mc_model_checker->process.running)
301 xbt_die("Inconsistent state");
305 XBT_ERROR("Could not wait for pid");
306 throw std::system_error(errno, std::system_category());
310 if (pid == mc_model_checker->process.pid) {
311 if (WIFEXITED(status) || WIFSIGNALED(status)) {
312 XBT_DEBUG("Child process is over");
313 mc_model_checker->process.status = status;
314 mc_model_checker->process.running = false;
320 void s_mc_server::on_signal(const struct signalfd_siginfo* info)
322 switch(info->ssi_signo) {
324 this->handle_waitpid();