1 // Copyright 2010 The Kyua Authors.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of Google Inc. nor the names of its contributors
14 // may be used to endorse or promote products derived from this software
15 // without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 #include "utils/signals/timer.hpp"
30
31 extern "C" {
32 #include <sys/time.h>
33
34 #include <signal.h>
35 }
36
37 #include <cerrno>
38 #include <map>
39 #include <set>
40 #include <vector>
41
42 #include "utils/datetime.hpp"
43 #include "utils/format/macros.hpp"
44 #include "utils/logging/macros.hpp"
45 #include "utils/noncopyable.hpp"
46 #include "utils/optional.ipp"
47 #include "utils/sanity.hpp"
48 #include "utils/signals/exceptions.hpp"
49 #include "utils/signals/interrupts.hpp"
50 #include "utils/signals/programmer.hpp"
51
52 namespace datetime = utils::datetime;
53 namespace signals = utils::signals;
54
55 using utils::none;
56 using utils::optional;
57
58 namespace {
59
60
61 static void sigalrm_handler(const int);
62
63
64 /// Calls setitimer(2) with exception-based error reporting.
65 ///
66 /// This does not currently support intervals.
67 ///
68 /// \param delta The time to the first activation of the programmed timer.
69 /// \param old_timeval If not NULL, pointer to a timeval into which to store the
70 /// existing system timer.
71 ///
72 /// \throw system_error If the call to setitimer(2) fails.
73 static void
safe_setitimer(const datetime::delta & delta,itimerval * old_timeval)74 safe_setitimer(const datetime::delta& delta, itimerval* old_timeval)
75 {
76 ::itimerval timeval;
77 timerclear(&timeval.it_interval);
78 timeval.it_value.tv_sec = delta.seconds;
79 timeval.it_value.tv_usec = delta.useconds;
80
81 if (::setitimer(ITIMER_REAL, &timeval, old_timeval) == -1) {
82 const int original_errno = errno;
83 throw signals::system_error("Failed to program system's interval timer",
84 original_errno);
85 }
86 }
87
88
89 /// Deadline scheduler for all user timers on top of the unique system timer.
90 class global_state : utils::noncopyable {
91 /// Collection of active timers.
92 ///
93 /// Because this is a collection of pointers, all timers are guaranteed to
94 /// be unique, and we want all of these pointers to be valid.
95 typedef std::set< signals::timer* > timers_set;
96
97 /// Sequence of ordered timers.
98 typedef std::vector< signals::timer* > timers_vector;
99
100 /// Collection of active timestamps by their activation timestamp.
101 ///
102 /// This collection is ordered intentionally so that it can be scanned
103 /// sequentially to find either expired or expiring-now timers.
104 typedef std::map< datetime::timestamp, timers_set > timers_by_timestamp_map;
105
106 /// The original timer before any timer was programmed.
107 ::itimerval _old_timeval;
108
109 /// Programmer for the SIGALRM handler.
110 std::unique_ptr< signals::programmer > _sigalrm_programmer;
111
112 /// Time of the current activation of the timer.
113 datetime::timestamp _timer_activation;
114
115 /// Mapping of all active timers using their timestamp as the key.
116 timers_by_timestamp_map _all_timers;
117
118 /// Adds a timer to the _all_timers map.
119 ///
120 /// \param timer The timer to add.
121 void
add_to_all_timers(signals::timer * timer)122 add_to_all_timers(signals::timer* timer)
123 {
124 timers_set& timers = _all_timers[timer->when()];
125 INV(timers.find(timer) == timers.end());
126 timers.insert(timer);
127 }
128
129 /// Removes a timer from the _all_timers map.
130 ///
131 /// This ensures that empty vectors are removed from _all_timers if the
132 /// removal of the timer causes its bucket to be emptied.
133 ///
134 /// \param timer The timer to remove.
135 void
remove_from_all_timers(signals::timer * timer)136 remove_from_all_timers(signals::timer* timer)
137 {
138 // We may not find the timer in _all_timers if the timer has fired,
139 // because fire() took it out from the map.
140 timers_by_timestamp_map::iterator iter = _all_timers.find(
141 timer->when());
142 if (iter != _all_timers.end()) {
143 timers_set& timers = (*iter).second;
144 INV(timers.find(timer) != timers.end());
145 timers.erase(timer);
146 if (timers.empty()) {
147 _all_timers.erase(iter);
148 }
149 }
150 }
151
152 /// Calculates all timers to execute at this timestamp.
153 ///
154 /// \param now The current timestamp.
155 ///
156 /// \post _all_timers is updated to contain only the timers that are
157 /// strictly in the future.
158 ///
159 /// \return A sequence of valid timers that need to be invoked in the order
160 /// of activation. These are all previously registered timers with
161 /// activations in the past.
162 timers_vector
compute_timers_to_run_and_prune_old(const datetime::timestamp & now,const signals::interrupts_inhibiter &)163 compute_timers_to_run_and_prune_old(
164 const datetime::timestamp& now,
165 const signals::interrupts_inhibiter& /* inhibiter */)
166 {
167 timers_vector to_run;
168
169 timers_by_timestamp_map::iterator iter = _all_timers.begin();
170 while (iter != _all_timers.end() && (*iter).first <= now) {
171 const timers_set& timers = (*iter).second;
172 to_run.insert(to_run.end(), timers.begin(), timers.end());
173
174 // Remove expired entries here so that we can always assume that
175 // the first entry in all_timers corresponds to the next
176 // activation.
177 const timers_by_timestamp_map::iterator previous_iter = iter;
178 ++iter;
179 _all_timers.erase(previous_iter);
180 }
181
182 return to_run;
183 }
184
185 /// Adjusts the global system timer to point to the next activation.
186 ///
187 /// \param now The current timestamp.
188 ///
189 /// \throw system_error If the programming fails.
190 void
reprogram_system_timer(const datetime::timestamp & now,const signals::interrupts_inhibiter &)191 reprogram_system_timer(
192 const datetime::timestamp& now,
193 const signals::interrupts_inhibiter& /* inhibiter */)
194 {
195 if (_all_timers.empty()) {
196 // Nothing to do. We can reach this case if all the existing timers
197 // are in the past and they all fired. Just ignore the request and
198 // leave the global timer as is.
199 return;
200 }
201
202 // While fire() prunes old entries from the list of timers, it is
203 // possible for this routine to run with "expired" timers (i.e. timers
204 // whose deadline lies in the past but that have not yet fired for
205 // whatever reason that is out of our control) in the list. We have to
206 // iterate until we find the next activation instead of assuming that
207 // the first entry represents the desired value.
208 timers_by_timestamp_map::const_iterator iter = _all_timers.begin();
209 PRE(!(*iter).second.empty());
210 datetime::timestamp next = (*iter).first;
211 while (next < now) {
212 ++iter;
213 if (iter == _all_timers.end()) {
214 // Nothing to do. We can reach this case if all the existing
215 // timers are in the past but they have not yet fired.
216 return;
217 }
218 PRE(!(*iter).second.empty());
219 next = (*iter).first;
220 }
221
222 if (next < _timer_activation || now > _timer_activation) {
223 INV(next >= now);
224 const datetime::delta delta = next - now;
225 LD(F("Reprogramming timer; firing on %s; now is %s") % next % now);
226 safe_setitimer(delta, NULL);
227 _timer_activation = next;
228 }
229 }
230
231 public:
232 /// Programs the first timer.
233 ///
234 /// The programming of the first timer involves setting up the SIGALRM
235 /// handler and installing a timer handler for the first time, which in turn
236 /// involves keeping track of the old handlers so that we can restore them.
237 ///
238 /// \param timer The timer being programmed.
239 /// \param now The current timestamp.
240 ///
241 /// \throw system_error If the programming fails.
global_state(signals::timer * timer,const datetime::timestamp & now)242 global_state(signals::timer* timer, const datetime::timestamp& now) :
243 _timer_activation(timer->when())
244 {
245 PRE(now < timer->when());
246
247 signals::interrupts_inhibiter inhibiter;
248
249 const datetime::delta delta = timer->when() - now;
250 LD(F("Installing first timer; firing on %s; now is %s") %
251 timer->when() % now);
252
253 _sigalrm_programmer.reset(
254 new signals::programmer(SIGALRM, sigalrm_handler));
255 try {
256 safe_setitimer(delta, &_old_timeval);
257 _timer_activation = timer->when();
258 add_to_all_timers(timer);
259 } catch (...) {
260 _sigalrm_programmer.reset(NULL);
261 throw;
262 }
263 }
264
265 /// Unprograms all timers.
266 ///
267 /// This clears the global system timer and unsets the SIGALRM handler.
~global_state(void)268 ~global_state(void)
269 {
270 signals::interrupts_inhibiter inhibiter;
271
272 LD("Unprogramming all timers");
273
274 if (::setitimer(ITIMER_REAL, &_old_timeval, NULL) == -1) {
275 UNREACHABLE_MSG("Failed to restore original timer");
276 }
277
278 _sigalrm_programmer->unprogram();
279 _sigalrm_programmer.reset(NULL);
280 }
281
282 /// Programs a new timer, possibly adjusting the global system timer.
283 ///
284 /// Programming any timer other than the first one only involves reloading
285 /// the existing timer, not backing up the previous handler nor installing a
286 /// handler for SIGALRM.
287 ///
288 /// \param timer The timer being programmed.
289 /// \param now The current timestamp.
290 ///
291 /// \throw system_error If the programming fails.
292 void
program_new(signals::timer * timer,const datetime::timestamp & now)293 program_new(signals::timer* timer, const datetime::timestamp& now)
294 {
295 signals::interrupts_inhibiter inhibiter;
296
297 add_to_all_timers(timer);
298 reprogram_system_timer(now, inhibiter);
299 }
300
301 /// Unprograms a timer.
302 ///
303 /// This removes the timer from the global state and reprograms the global
304 /// system timer if necessary.
305 ///
306 /// \param timer The timer to unprogram.
307 ///
308 /// \return True if the system interval timer has been reprogrammed to
309 /// another future timer; false if there are no more active timers.
310 bool
unprogram(signals::timer * timer)311 unprogram(signals::timer* timer)
312 {
313 signals::interrupts_inhibiter inhibiter;
314
315 LD(F("Unprogramming timer; previously firing on %s") % timer->when());
316
317 remove_from_all_timers(timer);
318 if (_all_timers.empty()) {
319 return false;
320 } else {
321 reprogram_system_timer(datetime::timestamp::now(), inhibiter);
322 return true;
323 }
324 }
325
326 /// Executes active timers.
327 ///
328 /// Active timers are all those that fire on or before 'now'.
329 ///
330 /// \param now The current time.
331 void
fire(const datetime::timestamp & now)332 fire(const datetime::timestamp& now)
333 {
334 timers_vector to_run;
335 {
336 signals::interrupts_inhibiter inhibiter;
337 to_run = compute_timers_to_run_and_prune_old(now, inhibiter);
338 reprogram_system_timer(now, inhibiter);
339 }
340
341 for (timers_vector::iterator iter = to_run.begin();
342 iter != to_run.end(); ++iter) {
343 signals::detail::invoke_do_fired(*iter);
344 }
345 }
346 };
347
348
349 /// Unique instance of the global state.
350 static std::unique_ptr< global_state > globals;
351
352
353 /// SIGALRM handler for the timer implementation.
354 ///
355 /// \param signo The signal received; must be SIGALRM.
356 static void
sigalrm_handler(const int signo)357 sigalrm_handler(const int signo)
358 {
359 PRE(signo == SIGALRM);
360 globals->fire(datetime::timestamp::now());
361 }
362
363
364 } // anonymous namespace
365
366
367 /// Indirection to invoke the private do_fired() method of a timer.
368 ///
369 /// \param timer The timer on which to run do_fired().
370 void
invoke_do_fired(timer * timer)371 utils::signals::detail::invoke_do_fired(timer* timer)
372 {
373 timer->do_fired();
374 }
375
376
377 /// Internal implementation for the timer.
378 ///
379 /// We assume that there is a 1-1 mapping between timer objects and impl
380 /// objects. If this assumption breaks, then the rest of the code in this
381 /// module breaks as well because we use pointers to the parent timer as the
382 /// identifier of the timer.
383 struct utils::signals::timer::impl : utils::noncopyable {
384 /// Timestamp when this timer is expected to fire.
385 ///
386 /// Note that the timer might be processed after this timestamp, so users of
387 /// this field need to check for timers that fire on or before the
388 /// activation time.
389 datetime::timestamp when;
390
391 /// True until unprogram() is called.
392 bool programmed;
393
394 /// Whether this timer has fired already or not.
395 ///
396 /// This is updated from an interrupt context, hence why it is marked
397 /// volatile.
398 volatile bool fired;
399
400 /// Constructor.
401 ///
402 /// \param when_ Timestamp when this timer is expected to fire.
implutils::signals::timer::impl403 impl(const datetime::timestamp& when_) :
404 when(when_), programmed(true), fired(false)
405 {
406 }
407
408 /// Destructor.
~implutils::signals::timer::impl409 ~impl(void) {
410 }
411 };
412
413
414 /// Constructor; programs a run-once timer.
415 ///
416 /// This programs the global timer and signal handler if this is the first timer
417 /// being installed. Otherwise, reprograms the global timer if this timer
418 /// expires earlier than all other active timers.
419 ///
420 /// \param delta The time until the timer fires.
timer(const datetime::delta & delta)421 signals::timer::timer(const datetime::delta& delta)
422 {
423 signals::interrupts_inhibiter inhibiter;
424
425 const datetime::timestamp now = datetime::timestamp::now();
426 _pimpl.reset(new impl(now + delta));
427 if (globals.get() == NULL) {
428 globals.reset(new global_state(this, now));
429 } else {
430 globals->program_new(this, now);
431 }
432 }
433
434
435 /// Destructor; unprograms the timer if still programmed.
436 ///
437 /// Given that this is a destructor and it can't report errors back to the
438 /// caller, the caller must attempt to call unprogram() on its own. This is
439 /// extremely important because, otherwise, expired timers will never run!
~timer(void)440 signals::timer::~timer(void)
441 {
442 signals::interrupts_inhibiter inhibiter;
443
444 if (_pimpl->programmed) {
445 LW("Auto-destroying still-programmed signals::timer object");
446 try {
447 unprogram();
448 } catch (const system_error& e) {
449 UNREACHABLE;
450 }
451 }
452
453 if (!_pimpl->fired) {
454 const datetime::timestamp now = datetime::timestamp::now();
455 if (now > _pimpl->when) {
456 LW("Expired timer never fired; the code never called unprogram()!");
457 }
458 }
459 }
460
461
462 /// Returns the time of the timer activation.
463 ///
464 /// \return A timestamp that has no relation to the current time (i.e. can be in
465 /// the future or in the past) nor the timer's activation status.
466 const datetime::timestamp&
when(void) const467 signals::timer::when(void) const
468 {
469 return _pimpl->when;
470 }
471
472
473 /// Callback for the SIGALRM handler when this timer expires.
474 ///
475 /// \warning This is executed from a signal handler context without signals
476 /// inhibited. See signal(7) for acceptable system calls.
477 void
do_fired(void)478 signals::timer::do_fired(void)
479 {
480 PRE(!_pimpl->fired);
481 _pimpl->fired = true;
482 callback();
483 }
484
485
486 /// User-provided callback to run when the timer expires.
487 ///
488 /// The default callback does nothing. We record the activation of the timer
489 /// separately, which may be appropriate in the majority of the cases.
490 ///
491 /// \warning This is executed from a signal handler context without signals
492 /// inhibited. See signal(7) for acceptable system calls.
493 void
callback(void)494 signals::timer::callback(void)
495 {
496 // Intentionally left blank.
497 }
498
499
500 /// Checks whether the timer has fired already or not.
501 ///
502 /// \return Returns true if the timer has fired.
503 bool
fired(void) const504 signals::timer::fired(void) const
505 {
506 return _pimpl->fired;
507 }
508
509
510 /// Unprograms the timer.
511 ///
512 /// \pre The timer is programmed (i.e. this can only be called once).
513 ///
514 /// \post If the timer never fired asynchronously because the signal delivery
515 /// did not arrive on time, make sure we invoke the timer's callback here.
516 ///
517 /// \throw system_error If unprogramming the timer failed.
518 void
unprogram(void)519 signals::timer::unprogram(void)
520 {
521 signals::interrupts_inhibiter inhibiter;
522
523 if (!_pimpl->programmed) {
524 // We cannot assert that the timer is not programmed because it might
525 // have been unprogrammed asynchronously between the time we called
526 // unprogram() and the time we reach this. Simply return in this case.
527 LD("Called unprogram on already-unprogrammed timer; possibly just "
528 "a race");
529 return;
530 }
531
532 if (!globals->unprogram(this)) {
533 globals.reset(NULL);
534 }
535 _pimpl->programmed = false;
536
537 // Handle the case where the timer has expired before we ever got its
538 // corresponding signal. Do so by invoking its callback now.
539 if (!_pimpl->fired) {
540 const datetime::timestamp now = datetime::timestamp::now();
541 if (now > _pimpl->when) {
542 LW(F("Firing expired timer on destruction (was to fire on %s)") %
543 _pimpl->when);
544 do_fired();
545 }
546 }
547 }
548