Logo AND Algorithmique Numérique Distribuée

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