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