PPL  1.2
Watchdog.cc
Go to the documentation of this file.
1 /* Watchdog and associated classes' implementation (non-inline functions).
2  Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it>
3  Copyright (C) 2010-2016 BUGSENG srl (http://bugseng.com)
4 
5 This file is part of the Parma Polyhedra Library (PPL).
6 
7 The PPL is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 The PPL is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software Foundation,
19 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA.
20 
21 For the most up-to-date information see the Parma Polyhedra Library
22 site: http://bugseng.com/products/ppl/ . */
23 
24 #include "ppl-config.h"
25 #include "Watchdog_defs.hh"
26 
27 #if PPL_HAVE_DECL_SETITIMER && PPL_HAVE_DECL_SIGACTION
28 
29 #include <csignal>
30 #include <iostream>
31 #include <stdexcept>
32 #include <cerrno>
33 #include <string>
34 #include <string.h>
35 
36 #ifdef PPL_TIME_WITH_SYS_TIME
37 # include <sys/time.h>
38 # include <ctime>
39 #else
40 # ifdef PPL_HAVE_SYS_TIME_H
41 # include <sys/time.h>
42 # else
43 # include <ctime>
44 # endif
45 #endif
46 
47 // Cygwin only supports ITIMER_REAL.
48 // Apparently GNU Hurd also only supports ITIMER_REAL
49 // (see http://www.cs.unipr.it/pipermail/ppl-devel/2010-March/016072.html).
50 // Profiling does not work on programs that use the ITIMER_PROF timer.
51 #if defined(__CYGWIN__) || defined(__gnu_hurd__) || defined(PPL_PROFILING)
52 #define THE_TIMER ITIMER_REAL
53 #define THE_SIGNAL SIGALRM
54 #else
55 #define THE_TIMER ITIMER_PROF
56 #define THE_SIGNAL SIGPROF
57 #endif
58 
59 using std::cerr;
60 using std::endl;
61 
62 namespace PPL = Parma_Polyhedra_Library;
63 
64 // Pass this to getitimer().
65 itimerval PPL::Watchdog::current_timer_status;
66 
67 // Pass this to setitimer().
68 itimerval PPL::Watchdog::signal_once;
69 
70 // Last time value we set the timer to.
71 PPL::Implementation::Watchdog::Time PPL::Watchdog::last_time_requested;
72 
73 // Records the time elapsed since last fresh start.
74 PPL::Implementation::Watchdog::Time PPL::Watchdog::time_so_far;
75 
76 // The ordered queue of pending watchdog events.
77 PPL::Watchdog::WD_Pending_List PPL::Watchdog::pending;
78 
79 // Whether the alarm clock is running.
80 volatile bool PPL::Watchdog::alarm_clock_running = false;
81 
82 // Whether we are changing data which are also changed by the signal handler.
83 volatile bool PPL::Watchdog::in_critical_section = false;
84 
85 namespace {
86 
87 void
88 throw_syscall_error(const char* syscall_name) {
89  throw std::runtime_error(std::string(syscall_name) + ": " + strerror(errno));
90 }
91 
92 void
93 my_getitimer(int which, struct itimerval* value) {
94  if (getitimer(which, value) != 0) {
95  throw_syscall_error("getitimer");
96  }
97 }
98 
99 void
100 my_setitimer(int which,
101  const struct itimerval* value, struct itimerval* old_value) {
102  if (setitimer(which, value, old_value) != 0) {
103  throw_syscall_error("setitimer");
104  }
105 }
106 
107 void
108 my_sigaction(int signum,
109  const struct sigaction* act, struct sigaction* old_action) {
110  if (sigaction(signum, act, old_action) != 0) {
111  throw_syscall_error("sigaction");
112  }
113 }
114 
115 } // namespace
116 
117 void
118 PPL::Watchdog::get_timer(Implementation::Watchdog::Time& time) {
119  using namespace Implementation::Watchdog;
120  my_getitimer(THE_TIMER, &current_timer_status);
121  time = Time(current_timer_status.it_value.tv_sec,
122  current_timer_status.it_value.tv_usec);
123 }
124 
125 void
126 PPL::Watchdog::set_timer(const Implementation::Watchdog::Time& time) {
127  if (time.seconds() == 0 && time.microseconds() == 0) {
128  throw std::runtime_error("PPL internal error");
129  }
130  last_time_requested = time;
131  signal_once.it_value.tv_sec = time.seconds();
132  signal_once.it_value.tv_usec = time.microseconds();
133  my_setitimer(THE_TIMER, &signal_once, 0);
134 }
135 
136 void
137 PPL::Watchdog::stop_timer() {
138  signal_once.it_value.tv_sec = 0;
139  signal_once.it_value.tv_usec = 0;
140  my_setitimer(THE_TIMER, &signal_once, 0);
141 }
142 
143 void
144 PPL::Watchdog::handle_timeout(int) {
145  if (in_critical_section) {
146  reschedule();
147  }
148  else {
149  time_so_far += last_time_requested;
150  if (!pending.empty()) {
151  WD_Pending_List::iterator i = pending.begin();
152  do {
153  i->handler().act();
154  i->expired_flag() = true;
155  i = pending.erase(i);
156  } while (i != pending.end() && i->deadline() <= time_so_far);
157  if (pending.empty()) {
158  alarm_clock_running = false;
159  }
160  else {
161  set_timer((*pending.begin()).deadline() - time_so_far);
162  }
163  }
164  else {
165  alarm_clock_running = false;
166  }
167  }
168 }
169 
170 void
171 PPL::PPL_handle_timeout(int signum) {
172  PPL::Watchdog::handle_timeout(signum);
173 }
174 
175 PPL::Watchdog::WD_Pending_List::iterator
176 PPL::Watchdog::new_watchdog_event(long csecs,
177  const WD_Handler& handler,
178  bool& expired_flag) {
179  using namespace Implementation::Watchdog;
180  assert(csecs > 0);
181  WD_Pending_List::iterator position;
182  const Time deadline(csecs);
183  if (!alarm_clock_running) {
184  position = pending.insert(deadline, handler, expired_flag);
185  time_so_far = Time(0);
186  set_timer(deadline);
187  alarm_clock_running = true;
188  }
189  else {
190  Time time_to_shoot;
191  get_timer(time_to_shoot);
192  Time elapsed_time(last_time_requested);
193  elapsed_time -= time_to_shoot;
194  Time current_time(time_so_far);
195  current_time += elapsed_time;
196  Time real_deadline(deadline);
197  real_deadline += current_time;
198  position = pending.insert(real_deadline, handler, expired_flag);
199  if (deadline < time_to_shoot) {
200  time_so_far = current_time;
201  set_timer(deadline);
202  }
203  }
204  return position;
205 }
206 
207 void
208 PPL::Watchdog::remove_watchdog_event(WD_Pending_List::iterator position) {
209  using namespace Implementation::Watchdog;
210  assert(!pending.empty());
211  if (position == pending.begin()) {
212  WD_Pending_List::iterator next = position;
213  ++next;
214  if (next != pending.end()) {
215  const Time first_deadline(position->deadline());
216  Time next_deadline(next->deadline());
217  if (first_deadline != next_deadline) {
218  Time time_to_shoot;
219  get_timer(time_to_shoot);
220  Time elapsed_time(last_time_requested);
221  elapsed_time -= time_to_shoot;
222  time_so_far += elapsed_time;
223  next_deadline -= first_deadline;
224  time_to_shoot += next_deadline;
225  set_timer(time_to_shoot);
226  }
227  }
228  else {
229  stop_timer();
230  alarm_clock_running = false;
231  }
232  }
233  pending.erase(position);
234 }
235 
236 PPL::Implementation::Watchdog::Time PPL::Watchdog::reschedule_time(1);
237 
238 void
240  signal_once.it_interval.tv_sec = 0;
241  signal_once.it_interval.tv_usec = 0;
242 
243  sigset_t mask;
244  sigemptyset(&mask);
245 
246  struct sigaction s;
247  s.sa_handler = &PPL_handle_timeout;
248  s.sa_mask = mask;
249  s.sa_flags = 0; // Was SA_ONESHOT: why?
250 
251  my_sigaction(THE_SIGNAL, &s, 0);
252 }
253 
254 void
256 }
257 
258 #endif // PPL_HAVE_DECL_SETITIMER && PPL_HAVE_DECL_SIGACTION
void finalize()
Finalizes the library.
Definition: initializer.hh:60
Coefficient value
Definition: PIP_Tree.cc:618
void initialize()
Initializes the library.
Definition: initializer.hh:52
The entire library is confined to this namespace.
Definition: version.hh:61
void PPL_handle_timeout(int signum)