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 "ModelChecker.hpp"
19 #include "mc_protocol.h"
20 #include "mc_server.h"
21 #include "mc_private.h"
22 #include "mc_ignore.h"
26 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_server, mc, "MC server logic");
28 // HArdcoded index for now:
29 #define SOCKET_FD_INDEX 0
30 #define SIGNAL_FD_INDEX 1
32 mc_server_t mc_server;
34 struct mc_symbol_pointer_callback
40 static int mc_symbol_pointer_callback_evaluate(void* p)
42 struct mc_symbol_pointer_callback* callback = (struct mc_symbol_pointer_callback*) p;
44 MC_process_read(callback->process, MC_ADDRESS_SPACE_READ_FLAGS_NONE,
45 &value, callback->value, sizeof(value), MC_PROCESS_INDEX_ANY);
49 s_mc_server::s_mc_server(pid_t pid, int socket)
52 this->socket = socket;
55 void s_mc_server::start()
57 /* Wait for the target process to initialize and exchange a HELLO messages
58 * before trying to look at its memory map.
60 int res = MC_protocol_hello(socket);
62 throw std::system_error(res, std::system_category());
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());
129 process->cache_flags = (mc_process_cache_flags_t) 0;
133 void throw_socket_error(int fd)
136 socklen_t errlen = sizeof(error);
137 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&error, &errlen) == -1)
139 throw std::system_error(error, std::system_category());
142 bool s_mc_server::handle_events()
144 char buffer[MC_MESSAGE_LENGTH];
145 struct pollfd* socket_pollfd = &fds[SOCKET_FD_INDEX];
146 struct pollfd* signalfd_pollfd = &fds[SIGNAL_FD_INDEX];
148 while(poll(fds, 2, -1) == -1) {
153 throw std::system_error(errno, std::system_category());
157 if (socket_pollfd->revents) {
158 if (socket_pollfd->revents & POLLIN) {
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());
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));
169 switch(base_message.type) {
171 case MC_MESSAGE_IGNORE_HEAP:
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);
183 case MC_MESSAGE_UNIGNORE_HEAP:
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);
193 case MC_MESSAGE_IGNORE_MEMORY:
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);
204 case MC_MESSAGE_STACK_REGION:
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);
216 case MC_MESSAGE_REGISTER_SYMBOL:
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);
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;
230 MC_automaton_new_propositional_symbol_callback(message.name,
231 mc_symbol_pointer_callback_evaluate, callback, free);
235 case MC_MESSAGE_WAITING:
238 case MC_MESSAGE_ASSERTION_FAILED:
239 MC_report_assertion_error();
244 xbt_die("Unexpected message from model-checked application");
249 if (socket_pollfd->revents & POLLERR) {
250 throw_socket_error(socket_pollfd->fd);
252 if (socket_pollfd->revents & POLLHUP)
253 xbt_die("Socket hang up?");
256 if (signalfd_pollfd->revents) {
257 if (signalfd_pollfd->revents & POLLIN) {
258 this->handle_signals();
261 if (signalfd_pollfd->revents & POLLERR) {
262 throw_socket_error(signalfd_pollfd->fd);
264 if (signalfd_pollfd->revents & POLLHUP)
265 xbt_die("Signalfd hang up?");
271 void s_mc_server::loop()
273 while (mc_model_checker->process().running)
274 this->handle_events();
277 void s_mc_server::handle_signals()
279 struct signalfd_siginfo info;
280 struct pollfd* signalfd_pollfd = &fds[SIGNAL_FD_INDEX];
282 ssize_t size = read(signalfd_pollfd->fd, &info, sizeof(info));
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");
294 this->on_signal(&info);
297 void s_mc_server::handle_waitpid()
299 XBT_DEBUG("Check for wait event");
302 while ((pid = waitpid(-1, &status, WNOHANG)) != 0) {
304 if (errno == ECHILD) {
306 if (mc_model_checker->process().running)
307 xbt_die("Inconsistent state");
311 XBT_ERROR("Could not wait for pid");
312 throw std::system_error(errno, std::system_category());
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;
326 void s_mc_server::on_signal(const struct signalfd_siginfo* info)
328 switch(info->ssi_signo) {
330 this->handle_waitpid();
337 void MC_server_wait_client(mc_process_t process)
339 mc_server->resume(process);
340 while (mc_model_checker->process().running) {
341 if (!mc_server->handle_events())
346 void MC_server_simcall_handle(mc_process_t process, unsigned long pid, int value)
348 s_mc_simcall_handle_message m;
349 memset(&m, 0, sizeof(m));
350 m.type = MC_MESSAGE_SIMCALL_HANDLE;
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())
361 void MC_server_loop(mc_server_t server)