1 // -*- c-basic-offset: 4; related-file-name: "../include/click/timer.hh" -*-
2 /*
3  * timer.{cc,hh} -- portable timers
4  * Eddie Kohler
5  *
6  * Copyright (c) 1999-2000 Massachusetts Institute of Technology
7  * Copyright (c) 2008 Regents of the University of California
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a
10  * copy of this software and associated documentation files (the "Software"),
11  * to deal in the Software without restriction, subject to the conditions
12  * listed in the Click LICENSE file. These conditions include: you must
13  * preserve this copyright notice, and you cannot mention the copyright
14  * holders in advertising related to the Software without their permission.
15  * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
16  * notice is a summary of the Click LICENSE file; the license in that file is
17  * legally binding.
18  */
19 
20 #include <click/config.h>
21 #include <click/timer.hh>
22 #include <click/element.hh>
23 #include <click/router.hh>
24 #include <click/master.hh>
25 #include <click/routerthread.hh>
26 #include <click/task.hh>
27 #include <click/heap.hh>
28 CLICK_DECLS
29 
30 /** @file timer.hh
31  * @brief Support for Timer, which triggers execution at a given time.
32  */
33 
34 /** @class Timer
35  @brief Triggers execution at a given time.
36 
37  Click Timer objects trigger the execution of code after a specific time.
38  Click's version of "ping" (the ICMPPingSource element) uses Timer objects to
39  create ping packets at specific times.  Many other elements, such as
40  IPRewriter, garbage-collect their internal state based on timers.  An element
41  that needs to run occasional timed tasks includes and initializes a Timer
42  instance variable.  When scheduled, most timers call their associated
43  element's @link Element::run_timer() run_timer()@endlink method.
44 
45  Each scheduled Timer has a single expiration Timestamp.  To implement a
46  periodic timer, reschedule the timer as appropriate.
47 
48  <h3>Examples</h3>
49 
50  This example element code, based on TimedSource, will print a message every
51  5 seconds:
52 
53  @code
54  #include <click/element.hh>
55  #include <click/timer.hh>
56 
57  class PeriodicPrinter : public Element { public:
58      PeriodicPrinter();
59      const char *class_name() const { return "PeriodicPrinter"; }
60      int initialize(ErrorHandler *errh);
61      void run_timer(Timer *timer);
62    private:
63      Timer _timer;
64  };
65 
66  PeriodicPrinter::PeriodicPrinter()
67      : _timer(this)    // Sets _timer to call this->run_timer(&_timer)
68  {                     // when it fires.
69  }
70 
71  int PeriodicPrinter::initialize(ErrorHandler *) {
72      _timer.initialize(this);   // Initialize timer object (mandatory).
73      _timer.schedule_now();     // Set the timer to fire as soon as the
74                                 // router runs.
75      return 0;
76  }
77 
78  void PeriodicPrinter::run_timer(Timer *timer) {
79      // This function is called when the timer fires.
80      assert(timer == &_timer);
81      Timestamp now = Timestamp::now_steady();
82      click_chatter("%s: %p{timestamp}: timer fired with expiry %p{timestamp}!\n",
83                    declaration().c_str(), &now, &_timer.expiry_steady());
84 		   // _timer.expiry_steady() is the steady-clock Timestamp
85 		   // at which the timer was set to fire.
86      _timer.reschedule_after_sec(5);  // Fire again 5 seconds later.
87  }
88  @endcode
89 
90  Running this element might produce output like this:
91 
92  <pre>
93  pp: 1204658365.127870: timer fired with expiry 1204658365.127847!
94  pp: 1204658370.127911: timer fired with expiry 1204658370.127847!
95  pp: 1204658375.127877: timer fired with expiry 1204658375.127847!
96  pp: 1204658380.127874: timer fired with expiry 1204658380.127847!
97  pp: 1204658385.127876: timer fired with expiry 1204658385.127847!
98  pp: 1204658390.127926: timer fired with expiry 1204658390.127847!
99  pp: 1204658395.128044: timer fired with expiry 1204658395.127847!
100  </pre>
101 
102  The expiry time measures when the timer was supposed to fire, while
103  Timestamp::now_steady() reports the current steady-clock time.  Note that the
104  timer's expiry time goes up by exactly 5 seconds each time, and that
105  steady-clock time is always later than the expiry time.
106 
107  Click aims to fire the timer as soon as possible after the expiry time, but
108  cannot hit the expiry time exactly.  The reschedule_after_sec() function and
109  its variants (reschedule_after(), reschedule_after_msec()) schedule the next
110  firing based on the previous expiry time.  This makes the timer's action more
111  robust to runtime fluctuations.  Compare:
112 
113  @code
114  void PeriodicPrinter::run_timer(Timer *timer) {
115      Timestamp now = Timestamp::now_steady();
116      click_chatter("%s: %p{timestamp}: timer fired with expiry %p{timestamp}!\n",
117                    name().c_str(), &now, &_timer.expiry_steady());
118      _timer.schedule_after_sec(5);  // Fire again 5 seconds later.
119          // This is the same as:
120 	 // _timer.schedule_at_steady(Timestamp::now_steady() + Timestamp::make_sec(5));
121  }
122  @endcode
123 
124  The schedule_after_sec() function sets the timer to fire an interval after
125  the <em>current steady-clock time</em>, not the previous expiry.  As a
126  result, the timer drifts:
127 
128  <pre>
129  pp: 1204658494.374277: timer fired with expiry 1204658494.374256!
130  pp: 1204658499.374575: timer fired with expiry 1204658499.374478!
131  pp: 1204658504.375261: timer fired with expiry 1204658504.375218!
132  pp: 1204658509.375428: timer fired with expiry 1204658509.375381!
133  ...
134  pp: 1204658884.998112: timer fired with expiry 1204658884.998074!
135  pp: 1204658890.001909: timer fired with expiry 1204658889.998209!
136  pp: 1204658895.002399: timer fired with expiry 1204658895.002175!
137  pp: 1204658900.003626: timer fired with expiry 1204658900.003589!
138  </pre>
139 
140  Timers that are set to fire more than 1 second in the past are silently
141  updated to the current steady-clock time.  Thus, the reschedule_after()
142  methods will never fall more than a second or two behind steady-clock time.
143 
144  <h3>Notes</h3>
145 
146  Elements desiring extremely frequent access to the CPU, up to tens of
147  thousands of times a second, should use a Task object rather than a Timer.
148  However, Tasks essentially busy-wait, taking up all available CPU.  There is
149  a tradeoff, and some elements combine a Task and a Timer to get the benefits
150  of both; for example, LinkUnqueue uses a Task at high rates and a Timer at
151  low rates.  The Timer::adjustment() value is useful in this context.
152 
153  Particularly at user level, there can be a significant delay between a
154  Timer's nominal expiration time and the actual time it runs.  Elements that
155  desire extremely precise timings should combine a Timer with a Task.  The
156  Timer is set to go off a bit before the true expiration time (see
157  Timer::adjustment()), after which the Task polls the CPU until the actual
158  expiration time arrives.
159 
160  Since Click is cooperatively scheduled, any timer callback should run for
161  just a short period of time.  Very long callbacks can inappropriately delay
162  other timers and periodic events.
163 
164  The Click core stores timers in a heap, so most timer operations (including
165  scheduling and unscheduling) take @e O(log @e n) time and Click can handle
166  very large numbers of timers.
167 
168  Timers generally run in increasing order by expiration time.  That is, if
169  timer @a a's expiry() is less than timer @a b's expiry(), then @a a will
170  generally fire before @a b.  However, Click must sometimes run timers out of
171  order to ensure fairness.  The only strict guarantee is that a Timer will run
172  after its nominal expiration time.
173 */
174 
175 void
do_nothing_hook(Timer *,void *)176 Timer::do_nothing_hook(Timer *, void *)
177 {
178 }
179 
180 void
element_hook(Timer * timer,void * thunk)181 Timer::element_hook(Timer *timer, void *thunk)
182 {
183     Element* e = static_cast<Element *>(thunk);
184     e->run_timer(timer);
185 }
186 
187 void
task_hook(Timer *,void * thunk)188 Timer::task_hook(Timer *, void *thunk)
189 {
190     Task* task = static_cast<Task *>(thunk);
191     task->reschedule();
192 }
193 
194 
Timer()195 Timer::Timer()
196     : _schedpos1(0), _thunk(0), _owner(0), _thread(0)
197 {
198     static_assert(sizeof(TimerSet::heap_element) == 16, "size_element should be 16 bytes long.");
199     _hook.callback = do_nothing_hook;
200 }
201 
Timer(const do_nothing_t &)202 Timer::Timer(const do_nothing_t &)
203     : _schedpos1(0), _thunk((void *) 1), _owner(0), _thread(0)
204 {
205     _hook.callback = do_nothing_hook;
206 }
207 
Timer(TimerCallback f,void * user_data)208 Timer::Timer(TimerCallback f, void *user_data)
209     : _schedpos1(0), _thunk(user_data), _owner(0), _thread(0)
210 {
211     _hook.callback = f;
212 }
213 
Timer(Element * element)214 Timer::Timer(Element* element)
215     : _schedpos1(0), _thunk(element), _owner(0), _thread(0)
216 {
217     _hook.callback = element_hook;
218 }
219 
Timer(Task * task)220 Timer::Timer(Task* task)
221     : _schedpos1(0), _thunk(task), _owner(0), _thread(0)
222 {
223     _hook.callback = task_hook;
224 }
225 
Timer(const Timer & x)226 Timer::Timer(const Timer &x)
227     : _schedpos1(0), _hook(x._hook), _thunk(x._thunk), _owner(0), _thread(0)
228 {
229 }
230 
231 void
initialize(Router * router)232 Timer::initialize(Router *router)
233 {
234     initialize(router->root_element());
235 }
236 
237 void
initialize(Element * owner,bool quiet)238 Timer::initialize(Element *owner, bool quiet)
239 {
240     assert(!initialized() || _owner->router() == owner->router());
241     _owner = owner;
242     if (unlikely(_hook.callback == do_nothing_hook && !_thunk) && !quiet)
243 	click_chatter("initializing Timer %p{element} [%p], which does nothing", _owner, this);
244 
245     int tid = owner->router()->home_thread_id(owner);
246     _thread = owner->master()->thread(tid);
247 }
248 
249 int
home_thread_id() const250 Timer::home_thread_id() const
251 {
252     if (_thread)
253 	return _thread->thread_id();
254     else
255 	return ThreadSched::THREAD_UNKNOWN;
256 }
257 
258 void
schedule_at_steady(const Timestamp & when)259 Timer::schedule_at_steady(const Timestamp &when)
260 {
261     // acquire lock, unschedule
262     assert(_owner && initialized());
263     TimerSet &ts = _thread->timer_set();
264     ts.lock_timers();
265 
266     // set expiration timer (ensure nonzero)
267     _expiry_s = when ? when : Timestamp::epsilon();
268     ts.check_timer_expiry(this);
269 
270     // manipulate list; this is essentially a "decrease-key" operation
271     // any reschedule removes a timer from the runchunk (XXX -- even backwards
272     // reschedulings)
273     int old_schedpos1 = _schedpos1;
274     if (_schedpos1 <= 0) {
275 	if (_schedpos1 < 0)
276 	    ts._timer_runchunk[-_schedpos1 - 1] = 0;
277 	_schedpos1 = ts._timer_heap.size() + 1;
278 	ts._timer_heap.push_back(TimerSet::heap_element(this));
279     } else
280 	ts._timer_heap.unchecked_at(_schedpos1 - 1).expiry_s = _expiry_s;
281     change_heap<4>(ts._timer_heap.begin(), ts._timer_heap.end(),
282 		   ts._timer_heap.begin() + _schedpos1 - 1,
283 		   TimerSet::heap_less(), TimerSet::heap_place());
284     if (old_schedpos1 == 1 || _schedpos1 == 1)
285 	ts.set_timer_expiry();
286 
287     // if we changed the timeout, wake up the thread
288     if (_schedpos1 == 1)
289 	_thread->wake();
290 
291     // done
292     ts.unlock_timers();
293 }
294 
295 void
schedule_after(const Timestamp & delta)296 Timer::schedule_after(const Timestamp &delta)
297 {
298     schedule_at_steady(Timestamp::now_steady() + delta);
299 }
300 
301 void
unschedule()302 Timer::unschedule()
303 {
304     if (!scheduled())
305 	return;
306     TimerSet &ts = _thread->timer_set();
307     ts.lock_timers();
308     int old_schedpos1 = _schedpos1;
309     if (_schedpos1 > 0) {
310 	remove_heap<4>(ts._timer_heap.begin(), ts._timer_heap.end(),
311 		       ts._timer_heap.begin() + _schedpos1 - 1,
312 		       TimerSet::heap_less(), TimerSet::heap_place());
313 	ts._timer_heap.pop_back();
314 	if (old_schedpos1 == 1)
315 	    ts.set_timer_expiry();
316     } else if (_schedpos1 < 0)
317 	ts._timer_runchunk[-_schedpos1 - 1] = 0;
318     _schedpos1 = 0;
319     ts.unlock_timers();
320 }
321 
322 // list-related functions in master.cc
323 
324 CLICK_ENDDECLS
325