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
|
---|