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