1 | /// ----------------------------------------*- mode: C++; -*-- |
---|
2 | /// @file timer.cpp |
---|
3 | /// Software timer interface |
---|
4 | /// ---------------------------------------------------------- |
---|
5 | /// $Id: timer.cpp 2549 2007-04-02 22:17:37Z bless $ |
---|
6 | /// $HeadURL: https://svn.ipv6.tm.uka.de/nsis/protlib/trunk/src/timer.cpp $ |
---|
7 | // =========================================================== |
---|
8 | // |
---|
9 | // Copyright (C) 2005-2007, all rights reserved by |
---|
10 | // - Institute of Telematics, Universitaet Karlsruhe (TH) |
---|
11 | // |
---|
12 | // More information and contact: |
---|
13 | // https://projekte.tm.uka.de/trac/NSIS |
---|
14 | // |
---|
15 | // This program is free software; you can redistribute it and/or modify |
---|
16 | // it under the terms of the GNU General Public License as published by |
---|
17 | // the Free Software Foundation; version 2 of the License |
---|
18 | // |
---|
19 | // This program is distributed in the hope that it will be useful, |
---|
20 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
21 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
22 | // GNU General Public License for more details. |
---|
23 | // |
---|
24 | // You should have received a copy of the GNU General Public License along |
---|
25 | // with this program; if not, write to the Free Software Foundation, Inc., |
---|
26 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
---|
27 | // |
---|
28 | // =========================================================== |
---|
29 | /** @ingroup timer |
---|
30 | * You can create a software timer and attach a callback object to it. |
---|
31 | * Timers are only accessed through their TimerManager and timer ID. |
---|
32 | * timer managers are thread-safe. |
---|
33 | * |
---|
34 | * Timers are stored in an ordered list to ease checking for elapsed timers. |
---|
35 | * Additionally, their IDs are kept in a hash_map, so a pointer to a |
---|
36 | * timer object can be obtained very fast. |
---|
37 | */ |
---|
38 | |
---|
39 | //#define DEBUG_TIMER |
---|
40 | |
---|
41 | #include <errno.h> |
---|
42 | |
---|
43 | #include "cleanuphandler.h" |
---|
44 | #include "timer.h" |
---|
45 | #include "logfile.h" |
---|
46 | |
---|
47 | namespace protlib { |
---|
48 | |
---|
49 | /** @addtogroup timer Timer |
---|
50 | * @{ |
---|
51 | */ |
---|
52 | |
---|
53 | using namespace log; |
---|
54 | |
---|
55 | static inline |
---|
56 | void |
---|
57 | normalize_timespec(struct timespec& ts) |
---|
58 | { |
---|
59 | while (ts.tv_nsec>=1000000000) { |
---|
60 | ts.tv_sec++; |
---|
61 | ts.tv_nsec -= 1000000000; |
---|
62 | } // end while |
---|
63 | if (ts.tv_sec<0) ts.tv_sec = 0; |
---|
64 | if (ts.tv_nsec<0) ts.tv_nsec = 0; |
---|
65 | } // end normalize |
---|
66 | |
---|
67 | /** |
---|
68 | * fills in timespec with sec+msec, msec may be larger than 999! |
---|
69 | */ |
---|
70 | static inline |
---|
71 | void |
---|
72 | fill_timespec(struct timespec& ts, int32 sec, int32 msec) |
---|
73 | { |
---|
74 | if (sec<0) sec = 0; |
---|
75 | if (msec<0) msec = 0; |
---|
76 | ts.tv_sec = sec + (msec/1000); |
---|
77 | ts.tv_nsec = (msec%1000)*1000000; |
---|
78 | normalize_timespec(ts); |
---|
79 | } // end fill_timespec |
---|
80 | |
---|
81 | static inline |
---|
82 | void |
---|
83 | add_timespecs(struct timespec& ts1, struct timespec& ts2, struct timespec& res) { |
---|
84 | res.tv_sec = ts1.tv_sec + ts2.tv_sec; |
---|
85 | res.tv_nsec = ts1.tv_nsec + ts2.tv_nsec; |
---|
86 | normalize_timespec(res); |
---|
87 | } // end add_timespecs |
---|
88 | |
---|
89 | static inline void gettimeofday_timespec(struct timespec& ts) { |
---|
90 | struct timeval now = {0,0}; |
---|
91 | gettimeofday(&now,NULL); |
---|
92 | ts.tv_sec = now.tv_sec; |
---|
93 | ts.tv_nsec = now.tv_usec*1000; |
---|
94 | } // end gettimeofday_timespec |
---|
95 | |
---|
96 | /** Initialize a TimerManager object. */ |
---|
97 | TimerManager::TimerManager() |
---|
98 | { |
---|
99 | pthread_mutexattr_init(&mutex_attr); |
---|
100 | #ifdef _DEBUG |
---|
101 | pthread_mutexattr_settype(&mutex_attr,PTHREAD_MUTEX_ERRORCHECK); |
---|
102 | #else |
---|
103 | pthread_mutexattr_settype(&mutex_attr,PTHREAD_MUTEX_NORMAL); |
---|
104 | #endif |
---|
105 | |
---|
106 | pthread_mutex_init(&mutex,&mutex_attr); |
---|
107 | pthread_cond_init(&cond,NULL); |
---|
108 | |
---|
109 | Log(DEBUG_LOG,LOG_NORMAL, "Timer", "Creating TimerManager"); |
---|
110 | } // end constructor TimerManager |
---|
111 | |
---|
112 | /** Destroy TimerManager. */ |
---|
113 | TimerManager::~TimerManager() { |
---|
114 | #ifndef _NO_LOGGING |
---|
115 | int num = cleanup(); |
---|
116 | #else |
---|
117 | cleanup(); |
---|
118 | #endif |
---|
119 | DLog("Timer", "Destroying TimerManager with " << num << " timers"); |
---|
120 | pthread_cond_destroy(&cond); |
---|
121 | pthread_mutex_destroy(&mutex); |
---|
122 | pthread_mutexattr_destroy(&mutex_attr); |
---|
123 | } // end destructor TimerManager |
---|
124 | |
---|
125 | /** Start a timer relative to current time. |
---|
126 | * @return ID of the new timer. |
---|
127 | */ |
---|
128 | timer_id_t |
---|
129 | TimerManager::start_relative(TimerCallback* tc, int32 sec, int32 msec, timer_callback_param_t tcp) |
---|
130 | { |
---|
131 | struct timespec timeofday = {0,0}; |
---|
132 | struct timespec reltime = {0,0}; |
---|
133 | struct timespec alarm = {0,0}; |
---|
134 | timer *t = NULL; |
---|
135 | timer_id_t result = 0; |
---|
136 | fill_timespec(reltime,sec,msec); |
---|
137 | // calculate absolute alarm time |
---|
138 | gettimeofday_timespec(timeofday); |
---|
139 | add_timespecs(timeofday,reltime,alarm); |
---|
140 | // begin critical section |
---|
141 | pthread_mutex_lock(&mutex); // install_cleanup_mutex_lock(&mutex); |
---|
142 | // start timer |
---|
143 | t = new(nothrow) timer(alarm,tc,tcp); |
---|
144 | if (t) { |
---|
145 | result = t->id; |
---|
146 | // insert into list |
---|
147 | insert_into_list(t); |
---|
148 | // insert into hash |
---|
149 | hashmap[result] = t; |
---|
150 | // wake up threads |
---|
151 | pthread_cond_signal(&cond); |
---|
152 | } else { |
---|
153 | Log(ERROR_LOG,LOG_CRIT, "Timer", "TimerManager::start_relative() is unable to create timer object"); |
---|
154 | } // end if t |
---|
155 | // end critical section |
---|
156 | pthread_mutex_unlock(&mutex); // uninstall_cleanup(1); |
---|
157 | return result; |
---|
158 | } // end start_relative |
---|
159 | |
---|
160 | /** Start an absolute timer. |
---|
161 | * @return ID of the new timer. |
---|
162 | */ |
---|
163 | timer_id_t |
---|
164 | TimerManager::start_absolute(TimerCallback* tc, int32 sec, int32 msec, timer_callback_param_t tcp) { |
---|
165 | struct timespec alarm = {0,0}; |
---|
166 | timer *t = NULL; |
---|
167 | timer_id_t result = 0; |
---|
168 | fill_timespec(alarm,sec,msec); |
---|
169 | // begin critical section |
---|
170 | pthread_mutex_lock(&mutex); // install_cleanup_mutex_lock(&mutex); |
---|
171 | // start timer |
---|
172 | t = new(nothrow) timer(alarm,tc,tcp); |
---|
173 | if (t) { |
---|
174 | result = t->id; |
---|
175 | // insert into list |
---|
176 | insert_into_list(t); |
---|
177 | // insert into hash |
---|
178 | hashmap[result] = t; |
---|
179 | // wake up threads |
---|
180 | pthread_cond_signal(&cond); |
---|
181 | } else { |
---|
182 | Log(ERROR_LOG,LOG_CRIT, "Timer", "TimerManager::start_absolute() is unable to create timer object"); |
---|
183 | } // end if t |
---|
184 | // end critical section |
---|
185 | pthread_mutex_unlock(&mutex); // uninstall_cleanup(1); |
---|
186 | return result; |
---|
187 | } // end start_absolute |
---|
188 | |
---|
189 | /** Restart a timer and set the alarm relative to the current time. |
---|
190 | * The timer must exist and go off in the future. |
---|
191 | * @return true on success, false otherwise. |
---|
192 | */ |
---|
193 | bool |
---|
194 | TimerManager::restart_relative(timer_id_t id, int32 sec, int32 msec) |
---|
195 | { |
---|
196 | struct timespec timeofday = {0,0}; |
---|
197 | struct timespec reltime = {0,0}; |
---|
198 | struct timespec alarm = {0,0}; |
---|
199 | timer *t = NULL; |
---|
200 | bool result = false; |
---|
201 | timer_hashmap_it_t hit; |
---|
202 | fill_timespec(reltime,sec,msec); |
---|
203 | // calculate absolute alarm time |
---|
204 | gettimeofday_timespec(timeofday); |
---|
205 | add_timespecs(timeofday,reltime,alarm); |
---|
206 | // begin critical section |
---|
207 | pthread_mutex_lock(&mutex); // install_cleanup_mutex_lock(&mutex); |
---|
208 | // try to get timer with given ID |
---|
209 | if ((hit=hashmap.find(id))!=hashmap.end()) t = hit->second; else t = NULL; |
---|
210 | if (t) { |
---|
211 | // delete from list, set new alarm and insert |
---|
212 | delete_from_list(t); |
---|
213 | t->time = alarm; |
---|
214 | insert_into_list(t); |
---|
215 | // wake up threads |
---|
216 | pthread_cond_signal(&cond); |
---|
217 | result = true; |
---|
218 | } else { |
---|
219 | Log(DEBUG_LOG,LOG_NORMAL, "Timer", "TimerManager::restart_relative() is unable to restart timer " << id); |
---|
220 | } // end if t |
---|
221 | pthread_mutex_unlock(&mutex); // uninstall_cleanup(1); |
---|
222 | return result; |
---|
223 | } // end restart_relative |
---|
224 | |
---|
225 | |
---|
226 | /** Restart a timer and set the alarm to an absolute time. |
---|
227 | * The timer must exist and go off in the future. |
---|
228 | * @return true on success, false otherwise. |
---|
229 | */ |
---|
230 | bool |
---|
231 | TimerManager::restart_absolute(timer_id_t id, int32 sec, int32 msec) |
---|
232 | { |
---|
233 | struct timespec alarm = {0,0}; |
---|
234 | timer *t = NULL; |
---|
235 | bool result = false; |
---|
236 | timer_hashmap_it_t hit; |
---|
237 | fill_timespec(alarm,sec,msec); |
---|
238 | // begin critical section |
---|
239 | pthread_mutex_lock(&mutex); // install_cleanup_mutex_lock(&mutex); |
---|
240 | // try to get timer with given ID |
---|
241 | if ((hit=hashmap.find(id))!=hashmap.end()) t = hit->second; else t = NULL; |
---|
242 | if (t) { |
---|
243 | // delete from list, set new alarm and insert |
---|
244 | delete_from_list(t); |
---|
245 | t->time = alarm; |
---|
246 | insert_into_list(t); |
---|
247 | // wake up threads |
---|
248 | pthread_cond_signal(&cond); |
---|
249 | result = true; |
---|
250 | } else { |
---|
251 | Log(DEBUG_LOG,LOG_NORMAL, "Timer", "TimerManager::restart_relative() is unable to restart timer " << id); |
---|
252 | } // end if t |
---|
253 | pthread_mutex_unlock(&mutex); // uninstall_cleanup(1); |
---|
254 | return result; |
---|
255 | } // end restart_absolute |
---|
256 | |
---|
257 | /** Stop the given timer. */ |
---|
258 | bool TimerManager::stop(timer_id_t id) |
---|
259 | { |
---|
260 | timer *t = NULL; |
---|
261 | bool result = false; |
---|
262 | timer_hashmap_it_t hit; |
---|
263 | // begin critical section |
---|
264 | pthread_mutex_lock(&mutex); // install_cleanup_mutex_lock(&mutex); |
---|
265 | if ((hit=hashmap.find(id))!=hashmap.end()) { |
---|
266 | t = hit->second; |
---|
267 | // erase from hashmap |
---|
268 | hashmap.erase(hit); |
---|
269 | } else t = NULL; |
---|
270 | // delete from list if t exists |
---|
271 | if (t) { |
---|
272 | delete_from_list(t); |
---|
273 | // wake up threads |
---|
274 | pthread_cond_signal(&cond); |
---|
275 | result = true; |
---|
276 | } else { |
---|
277 | Log(DEBUG_LOG,LOG_NORMAL, "Timer", "TimerManager::stop() is unable to stop timer " << id); |
---|
278 | } // end if t |
---|
279 | pthread_mutex_unlock(&mutex); // uninstall_cleanup(1); |
---|
280 | return result; |
---|
281 | } // end stop |
---|
282 | |
---|
283 | /** Check if timers have elapsed and call their callbacks. |
---|
284 | * @return the number of elapsed timers. |
---|
285 | */ |
---|
286 | uint32 |
---|
287 | TimerManager::check_timers() |
---|
288 | { |
---|
289 | timer *elapsed; |
---|
290 | pthread_mutex_lock(&mutex); // install_cleanup_mutex_lock(&mutex); |
---|
291 | elapsed = collect_elapsed(); |
---|
292 | pthread_mutex_unlock(&mutex); // uninstall_cleanup(1); |
---|
293 | return process_elapsed(); |
---|
294 | } // end check_timers |
---|
295 | |
---|
296 | /** Like check_timers() but waits msec milliseconds for a timer to elapse. */ |
---|
297 | uint32 |
---|
298 | TimerManager::check_timers_wait(int32 msec) |
---|
299 | { |
---|
300 | struct timespec now = {0,0}; |
---|
301 | struct timespec reltime = {0,0}; |
---|
302 | struct timespec abstime = {0,0}; |
---|
303 | timer* elapsed; |
---|
304 | int wait_res = 0; |
---|
305 | fill_timespec(reltime,0,msec); |
---|
306 | gettimeofday_timespec(now); |
---|
307 | // calculate timespec for pthread_cond_timedwait() |
---|
308 | add_timespecs(now,reltime,abstime); |
---|
309 | timer maxwait(abstime,NULL,NULL,false); |
---|
310 | // begin critical section |
---|
311 | pthread_mutex_lock(&mutex); // install_cleanup_mutex_lock(&mutex); |
---|
312 | // look for elapsed timers until timeout |
---|
313 | elapsed = collect_elapsed(); |
---|
314 | while ((!elapsed) && (wait_res!=ETIMEDOUT)) { |
---|
315 | // neither timeout nor elapsed timers |
---|
316 | // if there is a timer in the list, wait until it elapses. |
---|
317 | // otherwise wait abstime. |
---|
318 | if (first() && ((*first())<=maxwait)) abstime = first()->time; |
---|
319 | else abstime = maxwait.time; |
---|
320 | // wait for condition or timeout |
---|
321 | wait_res = pthread_cond_timedwait(&cond,&mutex,&abstime); |
---|
322 | #ifdef DEBUG_TIMER |
---|
323 | Log(DEBUG_LOG,LOG_NORMAL, "Timer", "TimerManager::check_timers_wait() - timedwait returned " << wait_res << ":" << strerror(wait_res)); |
---|
324 | #endif |
---|
325 | elapsed = collect_elapsed(); |
---|
326 | #ifdef DEBUG_TIMER |
---|
327 | if (elapsed) |
---|
328 | Log(DEBUG_LOG,LOG_NORMAL, "Timer", "TimerManager::check_timers_wait() - collect_elapsed() returned " << elapsed->id); |
---|
329 | #endif |
---|
330 | } // end while !elapsed and !wait_res |
---|
331 | // end critical section |
---|
332 | pthread_mutex_unlock(&mutex); // uninstall_cleanup(1); |
---|
333 | // now either timeout, cancellation or elapsed timers |
---|
334 | return process_elapsed(); |
---|
335 | } // end check_timers_wait |
---|
336 | |
---|
337 | /** Stop all timers. */ |
---|
338 | uint32 |
---|
339 | TimerManager::stop_all() |
---|
340 | { |
---|
341 | uint32 result = 0; |
---|
342 | pthread_mutex_lock(&mutex); // install_cleanup_mutex_lock(&mutex); |
---|
343 | result = cleanup(); |
---|
344 | if (result) { |
---|
345 | // wake up threads |
---|
346 | pthread_cond_signal(&cond); |
---|
347 | } // end if result |
---|
348 | pthread_mutex_unlock(&mutex); // uninstall_cleanup(1); |
---|
349 | return result; |
---|
350 | } // end stop_all_timers |
---|
351 | |
---|
352 | /** Stop all timers without locking the mutex. |
---|
353 | * So this can be called safely inside the TimerManager constructor. |
---|
354 | */ |
---|
355 | uint32 |
---|
356 | TimerManager::cleanup() |
---|
357 | { |
---|
358 | uint32 num = 0; |
---|
359 | // clear hashmap |
---|
360 | hashmap.clear(); |
---|
361 | |
---|
362 | // delete all timers |
---|
363 | timer *curr= 0; |
---|
364 | while (!active_timerlist.empty()) |
---|
365 | { |
---|
366 | if ( (curr= active_timerlist.front()) != 0 ) |
---|
367 | { |
---|
368 | delete curr; |
---|
369 | active_timerlist.pop_front(); |
---|
370 | num++; |
---|
371 | } |
---|
372 | } // end while |
---|
373 | return num; |
---|
374 | } // end cleanup |
---|
375 | |
---|
376 | /** Insert a timer object into the timer list. |
---|
377 | * Timers are stored in an ordered list, so when checking for elapsed timers |
---|
378 | * it's enough to check timers beginning at the front end until one is |
---|
379 | * still running. |
---|
380 | */ |
---|
381 | inline |
---|
382 | void |
---|
383 | TimerManager::insert_into_list(timer *t) |
---|
384 | { |
---|
385 | timerlist_t::iterator listiter= active_timerlist.begin(); |
---|
386 | while(listiter != active_timerlist.end()) |
---|
387 | { |
---|
388 | if ( *listiter ) |
---|
389 | { |
---|
390 | // if current element is greater than *t, leave the loop |
---|
391 | if (!( *(*listiter) <= *t )) |
---|
392 | break; |
---|
393 | |
---|
394 | } |
---|
395 | listiter++; |
---|
396 | } // end for |
---|
397 | active_timerlist.insert(listiter,t); |
---|
398 | |
---|
399 | |
---|
400 | #ifdef DEBUG_TIMER |
---|
401 | Log(DEBUG_LOG,LOG_NORMAL, "Timer", "TimerManager::insert_into_list() - inserting timer " << t->id << " list now:"); |
---|
402 | #endif |
---|
403 | |
---|
404 | #ifdef DEBUG_TIMER |
---|
405 | for(timerlist_t::iterator listpiter= active_timerlist.begin(); |
---|
406 | listpiter != active_timerlist.end(); |
---|
407 | listpiter++) |
---|
408 | { |
---|
409 | Log(DEBUG_LOG,LOG_NORMAL, "Timer", "TimerManager::insert_into_list() - timer list, timer#: " << (*listpiter ? (*listpiter)->id : 0)); |
---|
410 | } |
---|
411 | #endif |
---|
412 | |
---|
413 | } // end insert_into_list |
---|
414 | |
---|
415 | /** Delete a timer from the ordered timer list. |
---|
416 | * The timer object is NOT freed because it may be needed for executing its |
---|
417 | * callback or for restarting. |
---|
418 | * The timer objects must be linked correctly, no checking is done. |
---|
419 | */ |
---|
420 | void |
---|
421 | TimerManager::delete_from_list(timer *t) { |
---|
422 | |
---|
423 | if (!t) return; |
---|
424 | |
---|
425 | #ifdef DEBUG_TIMER |
---|
426 | Log(DEBUG_LOG,LOG_NORMAL, "Timer", "TimerManager::delete_from_list() - deleting timer " << t->id); |
---|
427 | #endif |
---|
428 | timerlist_t::iterator listiter= find(active_timerlist.begin(),active_timerlist.end(),t); |
---|
429 | if ( listiter != active_timerlist.end() ) |
---|
430 | active_timerlist.erase(listiter); |
---|
431 | #ifdef DEBUG_TIMER |
---|
432 | if (first()) |
---|
433 | Log(DEBUG_LOG,LOG_NORMAL, "Timer", "TimerManager::delete_from_list() - first timer now " << (first() ? first()->id : 0) ); |
---|
434 | #endif |
---|
435 | } // end delete_from_list |
---|
436 | |
---|
437 | /** Collect all elapsed timers in the elapsed_timerlist and delete them already |
---|
438 | * from the hashmap. The timers are deleted in process_elapsed(). |
---|
439 | * You must lock the TimerManager mutex before collecting timers. |
---|
440 | * When timers have elapsed, the condition is signaled. |
---|
441 | */ |
---|
442 | TimerManager::timer* |
---|
443 | TimerManager::collect_elapsed() |
---|
444 | { |
---|
445 | struct timespec tod; |
---|
446 | gettimeofday_timespec(tod); |
---|
447 | timer now(tod,NULL,NULL,false); |
---|
448 | |
---|
449 | timerlist_t::iterator currentit = active_timerlist.begin(); |
---|
450 | timer* curr= first(); |
---|
451 | #ifdef DEBUG_TIMER |
---|
452 | if (curr) |
---|
453 | Log(DEBUG_LOG,LOG_NORMAL, "Timer", "TimerManager::collect_elapsed() - first timer is " << curr->id); |
---|
454 | #endif |
---|
455 | |
---|
456 | // search the last timer in list <= now |
---|
457 | while (curr && ((*curr)<=now)) |
---|
458 | { // current timer is already elapsed |
---|
459 | hashmap.erase(curr->id); |
---|
460 | #ifdef DEBUG_TIMER |
---|
461 | Log(DEBUG_LOG,LOG_NORMAL, "Timer", "TimerManager::collect_elapsed() - deleted elapsed timer " << curr->id); |
---|
462 | #endif |
---|
463 | // remember it in elapsed list |
---|
464 | elapsed_timerlist.push_back(curr); |
---|
465 | // delete it from the active timer list |
---|
466 | currentit= active_timerlist.erase(currentit); |
---|
467 | |
---|
468 | curr= (currentit != active_timerlist.end()) ? *currentit : 0; |
---|
469 | } // end while |
---|
470 | // List is ordered, so all timers before currentit are elapsed. |
---|
471 | |
---|
472 | timer* elapsed = elapsed_timerlist.empty() ? 0 : elapsed_timerlist.front(); |
---|
473 | |
---|
474 | // wake up threads |
---|
475 | if (elapsed) pthread_cond_signal(&cond); |
---|
476 | |
---|
477 | return elapsed; |
---|
478 | } // end collect_elapsed |
---|
479 | |
---|
480 | /** Process a list of timers by executing the callback routines and deleting |
---|
481 | * the timer objects. They are NOT deleted from the TimerManager hashmap. |
---|
482 | * The mutex should not be locked when callbacks are executed, because |
---|
483 | * it is unpossible to start a new timer inside a callback routine when |
---|
484 | * the mutex is still locked. |
---|
485 | * @see collect_elapsed() |
---|
486 | */ |
---|
487 | uint32 TimerManager::process_elapsed() |
---|
488 | { |
---|
489 | uint32 num = 0; |
---|
490 | timer *tmp = NULL; |
---|
491 | |
---|
492 | // for every elapsed timer (list should be prepared by collect_elapsed) do_callback() |
---|
493 | for (timerlist_t::iterator elapsed_it= elapsed_timerlist.begin(); |
---|
494 | elapsed_it != elapsed_timerlist.end(); |
---|
495 | elapsed_it= elapsed_timerlist.erase(elapsed_it)) |
---|
496 | { |
---|
497 | // invoke callback function on elapsed timer |
---|
498 | if ( (tmp = *elapsed_it) != 0) |
---|
499 | { |
---|
500 | tmp->do_callback(); |
---|
501 | // when callback is finished, delete the stuff |
---|
502 | delete tmp; |
---|
503 | num++; |
---|
504 | } |
---|
505 | // get next elapsed timer |
---|
506 | } // end for |
---|
507 | return num; |
---|
508 | } // end process_elapsed |
---|
509 | |
---|
510 | /** Initialize a timer. |
---|
511 | * If get_id is set (default) the timer gets a unique ID, otherwise the ID |
---|
512 | * of the timer is 0. |
---|
513 | */ |
---|
514 | TimerManager::timer::timer(struct timespec& ts, TimerCallback* tc, timer_callback_param_t tcp, bool get_id) : |
---|
515 | id (0), |
---|
516 | time(ts), |
---|
517 | callback(tc), |
---|
518 | param(tcp) |
---|
519 | { |
---|
520 | if (get_id) while (id==0) id = next_id++; |
---|
521 | } // end constructor timer |
---|
522 | |
---|
523 | /** This holds the timer ID of the next timer. */ |
---|
524 | timer_id_t TimerManager::timer::next_id = 1; |
---|
525 | |
---|
526 | /** Check which timer goes off eralier. |
---|
527 | * The timespec structores of the timers are expected to have correct |
---|
528 | * format. |
---|
529 | */ |
---|
530 | inline |
---|
531 | bool |
---|
532 | TimerManager::timer::operator<=(const timer& t) { |
---|
533 | if (time.tv_sec == t.time.tv_sec) { |
---|
534 | // Seconds are equal, it depends on nanoseconds. |
---|
535 | return (time.tv_nsec <= t.time.tv_nsec); |
---|
536 | } else { |
---|
537 | // Seconds are not equal, nanoseconds do not matter. |
---|
538 | return (time.tv_sec < t.time.tv_sec); |
---|
539 | } |
---|
540 | } // end operator<= |
---|
541 | |
---|
542 | inline |
---|
543 | void |
---|
544 | TimerManager::timer::do_callback() { |
---|
545 | callback->timer_expired(id,param); |
---|
546 | } // end do_callback |
---|
547 | |
---|
548 | //@} |
---|
549 | |
---|
550 | } // end namespace protlib |
---|