xref: /freebsd/contrib/kyua/utils/signals/timer.cpp (revision 8881d206f4e68b564c2c5f50fc717086fc3e827a)
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
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::auto_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
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
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
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
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.
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.
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
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
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
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::auto_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
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
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.
403     impl(const datetime::timestamp& when_) :
404         when(when_), programmed(true), fired(false)
405     {
406     }
407 
408     /// Destructor.
409     ~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.
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!
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&
467 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
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
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
504 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
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