Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
3cacf132b7ed58fad7ccb95becfc8244039b021c
[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
23 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_server, mc, "MC server logic");
24
25 // HArdcoded index for now:
26 #define SOCKET_FD_INDEX 0
27 #define SIGNAL_FD_INDEX 1
28
29 mc_server_t mc_server;
30
31 s_mc_server::s_mc_server(pid_t pid, int socket)
32 {
33   this->pid = pid;
34   this->socket = socket;
35 }
36
37 void s_mc_server::start()
38 {
39   /* Wait for the target process to initialize and exchange a HELLO messages
40    * before trying to look at its memory map.
41    */
42   XBT_DEBUG("Greeting the MC client");
43   int res = MC_protocol_hello(socket);
44   if (res != 0)
45     throw std::system_error(res, std::system_category());
46   XBT_DEBUG("Greeted the MC client");
47
48   MC_init_pid(pid, socket);
49
50   // Block SIGCHLD (this will be handled with accept/signalfd):
51   sigset_t set;
52   sigemptyset(&set);
53   sigaddset(&set, SIGCHLD);
54   if (sigprocmask(SIG_BLOCK, &set, NULL) == -1)
55     throw std::system_error(errno, std::system_category());
56
57   sigset_t full_set;
58   sigfillset(&full_set);
59
60   // Prepare data for poll:
61
62   struct pollfd* socket_pollfd = &fds[SOCKET_FD_INDEX];
63   socket_pollfd->fd = socket;
64   socket_pollfd->events = POLLIN;
65   socket_pollfd->revents = 0;
66
67   int signal_fd = signalfd(-1, &set, 0);
68   if (signal_fd == -1)
69     throw std::system_error(errno, std::system_category());
70
71   struct pollfd* signalfd_pollfd = &fds[SIGNAL_FD_INDEX];
72   signalfd_pollfd->fd = signal_fd;
73   signalfd_pollfd->events = POLLIN;
74   signalfd_pollfd->revents = 0;
75 }
76
77 void s_mc_server::shutdown()
78 {
79   XBT_DEBUG("Shuting down model-checker");
80
81   mc_process_t process = &mc_model_checker->process;
82   int status = process->status;
83   if (process->running) {
84     XBT_DEBUG("Killing process");
85     kill(process->pid, SIGTERM);
86     if (waitpid(process->pid, &status, 0) == -1)
87       throw std::system_error(errno, std::system_category());
88     // TODO, handle the case when the process does not want to die with a timeout
89     process->status = status;
90   }
91 }
92
93 void s_mc_server::exit()
94 {
95   // Finished:
96   int status = mc_model_checker->process.status;
97   if (WIFEXITED(status))
98     ::exit(WEXITSTATUS(status));
99   else if (WIFSIGNALED(status)) {
100     // Try to uplicate the signal of the model-checked process.
101     // This is a temporary hack so we don't try too hard.
102     kill(mc_model_checker->process.pid, WTERMSIG(status));
103     abort();
104   } else {
105     xbt_die("Unexpected status from model-checked process");
106   }
107 }
108
109 void s_mc_server::resume(mc_process_t process)
110 {
111   int socket = process->socket;
112   int res = MC_protocol_send_simple_message(socket, MC_MESSAGE_CONTINUE);
113   if (res)
114     throw std::system_error(res, std::system_category());
115 }
116
117 static
118 void throw_socket_error(int fd)
119 {
120   int error = 0;
121   socklen_t errlen = sizeof(error);
122   if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&error, &errlen) == -1)
123     error = errno;
124   throw std::system_error(error, std::system_category());
125 }
126
127 void s_mc_server::handle_events()
128 {
129   s_mc_message_t message;
130   struct pollfd* socket_pollfd = &fds[SOCKET_FD_INDEX];
131   struct pollfd* signalfd_pollfd = &fds[SIGNAL_FD_INDEX];
132
133   while(poll(fds, 2, -1) == -1) {
134     switch(errno) {
135     case EINTR:
136       continue;
137     default:
138       throw std::system_error(errno, std::system_category());
139     }
140   }
141
142   if (socket_pollfd->revents) {
143     if (socket_pollfd->revents & POLLIN) {
144       ssize_t size = recv(socket_pollfd->fd, &message, sizeof(message), MSG_DONTWAIT);
145       if (size == -1 && errno != EAGAIN)
146         throw std::system_error(errno, std::system_category());
147       else switch(message.type) {
148       default:
149         xbt_die("Unexpected message from model-checked application");
150       }
151       return;
152     }
153     if (socket_pollfd->revents & POLLERR) {
154       throw_socket_error(socket_pollfd->fd);
155     }
156     if (socket_pollfd->revents & POLLHUP)
157       xbt_die("Socket hang up?");
158   }
159
160   if (signalfd_pollfd->revents) {
161     if (signalfd_pollfd->revents & POLLIN) {
162       this->handle_signals();
163       return;
164     }
165     if (signalfd_pollfd->revents & POLLERR) {
166       throw_socket_error(signalfd_pollfd->fd);
167     }
168     if (signalfd_pollfd->revents & POLLHUP)
169       xbt_die("Signalfd hang up?");
170   }
171 }
172
173 void s_mc_server::loop()
174 {
175   while (mc_model_checker->process.running)
176     this->handle_events();
177 }
178
179 void s_mc_server::handle_signals()
180 {
181   struct signalfd_siginfo info;
182   struct pollfd* signalfd_pollfd = &fds[SIGNAL_FD_INDEX];
183   while (1) {
184     ssize_t size = read(signalfd_pollfd->fd, &info, sizeof(info));
185     if (size == -1) {
186       if (errno == EINTR)
187         continue;
188       else
189         throw std::system_error(errno, std::system_category());
190     } else if (size != sizeof(info))
191         return throw std::runtime_error(
192           "Bad communication with model-checked application");
193     else
194       break;
195   }
196   this->on_signal(&info);
197 }
198
199 void s_mc_server::handle_waitpid()
200 {
201   XBT_DEBUG("Check for wait event");
202   int status;
203   pid_t pid;
204   while ((pid = waitpid(-1, &status, WNOHANG)) != 0) {
205     if (pid == -1) {
206       if (errno == ECHILD) {
207         // No more children:
208         if (mc_model_checker->process.running)
209           xbt_die("Inconsistent state");
210         else
211           break;
212       } else {
213         XBT_ERROR("Could not wait for pid: %s", strerror(errno));
214         throw std::system_error(errno, std::system_category());
215       }
216     }
217
218     if (pid == mc_model_checker->process.pid) {
219       if (WIFEXITED(status) || WIFSIGNALED(status)) {
220         XBT_DEBUG("Child process is over");
221         mc_model_checker->process.status = status;
222         mc_model_checker->process.running = false;
223       }
224     }
225   }
226 }
227
228 void s_mc_server::on_signal(const struct signalfd_siginfo* info)
229 {
230   switch(info->ssi_signo) {
231   case SIGCHLD:
232     this->handle_waitpid();
233     break;
234   default:
235     break;
236   }
237 }