00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00039
00040
00041 #include <errno.h>
00042
00043 #include "cleanuphandler.h"
00044 #include "timer.h"
00045 #include "logfile.h"
00046
00047 namespace protlib {
00048
00053 using namespace log;
00054
00055 static inline
00056 void
00057 normalize_timespec(struct timespec& ts)
00058 {
00059 while (ts.tv_nsec>=1000000000) {
00060 ts.tv_sec++;
00061 ts.tv_nsec -= 1000000000;
00062 }
00063 if (ts.tv_sec<0) ts.tv_sec = 0;
00064 if (ts.tv_nsec<0) ts.tv_nsec = 0;
00065 }
00066
00070 static inline
00071 void
00072 fill_timespec(struct timespec& ts, int32 sec, int32 msec)
00073 {
00074 if (sec<0) sec = 0;
00075 if (msec<0) msec = 0;
00076 ts.tv_sec = sec + (msec/1000);
00077 ts.tv_nsec = (msec%1000)*1000000;
00078 normalize_timespec(ts);
00079 }
00080
00081 static inline
00082 void
00083 add_timespecs(struct timespec& ts1, struct timespec& ts2, struct timespec& res) {
00084 res.tv_sec = ts1.tv_sec + ts2.tv_sec;
00085 res.tv_nsec = ts1.tv_nsec + ts2.tv_nsec;
00086 normalize_timespec(res);
00087 }
00088
00089 static inline void gettimeofday_timespec(struct timespec& ts) {
00090 struct timeval now = {0,0};
00091 gettimeofday(&now,NULL);
00092 ts.tv_sec = now.tv_sec;
00093 ts.tv_nsec = now.tv_usec*1000;
00094 }
00095
00097 TimerManager::TimerManager()
00098 {
00099 pthread_mutexattr_init(&mutex_attr);
00100 #ifdef _DEBUG
00101 pthread_mutexattr_settype(&mutex_attr,PTHREAD_MUTEX_ERRORCHECK);
00102 #else
00103 pthread_mutexattr_settype(&mutex_attr,PTHREAD_MUTEX_NORMAL);
00104 #endif
00105
00106 pthread_mutex_init(&mutex,&mutex_attr);
00107 pthread_cond_init(&cond,NULL);
00108
00109 Log(DEBUG_LOG,LOG_NORMAL, "Timer", "Creating TimerManager");
00110 }
00111
00113 TimerManager::~TimerManager() {
00114 #ifndef _NO_LOGGING
00115 int num = cleanup();
00116 #else
00117 cleanup();
00118 #endif
00119 DLog("Timer", "Destroying TimerManager with " << num << " timers");
00120 pthread_cond_destroy(&cond);
00121 pthread_mutex_destroy(&mutex);
00122 pthread_mutexattr_destroy(&mutex_attr);
00123 }
00124
00128 timer_id_t
00129 TimerManager::start_relative(TimerCallback* tc, int32 sec, int32 msec, timer_callback_param_t tcp)
00130 {
00131 struct timespec timeofday = {0,0};
00132 struct timespec reltime = {0,0};
00133 struct timespec alarm = {0,0};
00134 timer *t = NULL;
00135 timer_id_t result = 0;
00136 fill_timespec(reltime,sec,msec);
00137
00138 gettimeofday_timespec(timeofday);
00139 add_timespecs(timeofday,reltime,alarm);
00140
00141 pthread_mutex_lock(&mutex);
00142
00143 t = new(nothrow) timer(alarm,tc,tcp);
00144 if (t) {
00145 result = t->id;
00146
00147 insert_into_list(t);
00148
00149 hashmap[result] = t;
00150
00151 pthread_cond_signal(&cond);
00152 } else {
00153 Log(ERROR_LOG,LOG_CRIT, "Timer", "TimerManager::start_relative() is unable to create timer object");
00154 }
00155
00156 pthread_mutex_unlock(&mutex);
00157 return result;
00158 }
00159
00163 timer_id_t
00164 TimerManager::start_absolute(TimerCallback* tc, int32 sec, int32 msec, timer_callback_param_t tcp) {
00165 struct timespec alarm = {0,0};
00166 timer *t = NULL;
00167 timer_id_t result = 0;
00168 fill_timespec(alarm,sec,msec);
00169
00170 pthread_mutex_lock(&mutex);
00171
00172 t = new(nothrow) timer(alarm,tc,tcp);
00173 if (t) {
00174 result = t->id;
00175
00176 insert_into_list(t);
00177
00178 hashmap[result] = t;
00179
00180 pthread_cond_signal(&cond);
00181 } else {
00182 Log(ERROR_LOG,LOG_CRIT, "Timer", "TimerManager::start_absolute() is unable to create timer object");
00183 }
00184
00185 pthread_mutex_unlock(&mutex);
00186 return result;
00187 }
00188
00193 bool
00194 TimerManager::restart_relative(timer_id_t id, int32 sec, int32 msec)
00195 {
00196 struct timespec timeofday = {0,0};
00197 struct timespec reltime = {0,0};
00198 struct timespec alarm = {0,0};
00199 timer *t = NULL;
00200 bool result = false;
00201 timer_hashmap_it_t hit;
00202 fill_timespec(reltime,sec,msec);
00203
00204 gettimeofday_timespec(timeofday);
00205 add_timespecs(timeofday,reltime,alarm);
00206
00207 pthread_mutex_lock(&mutex);
00208
00209 if ((hit=hashmap.find(id))!=hashmap.end()) t = hit->second; else t = NULL;
00210 if (t) {
00211
00212 delete_from_list(t);
00213 t->time = alarm;
00214 insert_into_list(t);
00215
00216 pthread_cond_signal(&cond);
00217 result = true;
00218 } else {
00219 Log(DEBUG_LOG,LOG_NORMAL, "Timer", "TimerManager::restart_relative() is unable to restart timer " << id);
00220 }
00221 pthread_mutex_unlock(&mutex);
00222 return result;
00223 }
00224
00225
00230 bool
00231 TimerManager::restart_absolute(timer_id_t id, int32 sec, int32 msec)
00232 {
00233 struct timespec alarm = {0,0};
00234 timer *t = NULL;
00235 bool result = false;
00236 timer_hashmap_it_t hit;
00237 fill_timespec(alarm,sec,msec);
00238
00239 pthread_mutex_lock(&mutex);
00240
00241 if ((hit=hashmap.find(id))!=hashmap.end()) t = hit->second; else t = NULL;
00242 if (t) {
00243
00244 delete_from_list(t);
00245 t->time = alarm;
00246 insert_into_list(t);
00247
00248 pthread_cond_signal(&cond);
00249 result = true;
00250 } else {
00251 Log(DEBUG_LOG,LOG_NORMAL, "Timer", "TimerManager::restart_relative() is unable to restart timer " << id);
00252 }
00253 pthread_mutex_unlock(&mutex);
00254 return result;
00255 }
00256
00258 bool TimerManager::stop(timer_id_t id)
00259 {
00260 timer *t = NULL;
00261 bool result = false;
00262 timer_hashmap_it_t hit;
00263
00264 pthread_mutex_lock(&mutex);
00265 if ((hit=hashmap.find(id))!=hashmap.end()) {
00266 t = hit->second;
00267
00268 hashmap.erase(hit);
00269 } else t = NULL;
00270
00271 if (t) {
00272 delete_from_list(t);
00273
00274 pthread_cond_signal(&cond);
00275 result = true;
00276 } else {
00277 Log(DEBUG_LOG,LOG_NORMAL, "Timer", "TimerManager::stop() is unable to stop timer " << id);
00278 }
00279 pthread_mutex_unlock(&mutex);
00280 return result;
00281 }
00282
00286 uint32
00287 TimerManager::check_timers()
00288 {
00289 timer *elapsed;
00290 pthread_mutex_lock(&mutex);
00291 elapsed = collect_elapsed();
00292 pthread_mutex_unlock(&mutex);
00293 return process_elapsed();
00294 }
00295
00297 uint32
00298 TimerManager::check_timers_wait(int32 msec)
00299 {
00300 struct timespec now = {0,0};
00301 struct timespec reltime = {0,0};
00302 struct timespec abstime = {0,0};
00303 timer* elapsed;
00304 int wait_res = 0;
00305 fill_timespec(reltime,0,msec);
00306 gettimeofday_timespec(now);
00307
00308 add_timespecs(now,reltime,abstime);
00309 timer maxwait(abstime,NULL,NULL,false);
00310
00311 pthread_mutex_lock(&mutex);
00312
00313 elapsed = collect_elapsed();
00314 while ((!elapsed) && (wait_res!=ETIMEDOUT)) {
00315
00316
00317
00318 if (first() && ((*first())<=maxwait)) abstime = first()->time;
00319 else abstime = maxwait.time;
00320
00321 wait_res = pthread_cond_timedwait(&cond,&mutex,&abstime);
00322 #ifdef DEBUG_TIMER
00323 Log(DEBUG_LOG,LOG_NORMAL, "Timer", "TimerManager::check_timers_wait() - timedwait returned " << wait_res << ":" << strerror(wait_res));
00324 #endif
00325 elapsed = collect_elapsed();
00326 #ifdef DEBUG_TIMER
00327 if (elapsed)
00328 Log(DEBUG_LOG,LOG_NORMAL, "Timer", "TimerManager::check_timers_wait() - collect_elapsed() returned " << elapsed->id);
00329 #endif
00330 }
00331
00332 pthread_mutex_unlock(&mutex);
00333
00334 return process_elapsed();
00335 }
00336
00338 uint32
00339 TimerManager::stop_all()
00340 {
00341 uint32 result = 0;
00342 pthread_mutex_lock(&mutex);
00343 result = cleanup();
00344 if (result) {
00345
00346 pthread_cond_signal(&cond);
00347 }
00348 pthread_mutex_unlock(&mutex);
00349 return result;
00350 }
00351
00355 uint32
00356 TimerManager::cleanup()
00357 {
00358 uint32 num = 0;
00359
00360 hashmap.clear();
00361
00362
00363 timer *curr= 0;
00364 while (!active_timerlist.empty())
00365 {
00366 if ( (curr= active_timerlist.front()) != 0 )
00367 {
00368 delete curr;
00369 active_timerlist.pop_front();
00370 num++;
00371 }
00372 }
00373 return num;
00374 }
00375
00381 inline
00382 void
00383 TimerManager::insert_into_list(timer *t)
00384 {
00385 timerlist_t::iterator listiter= active_timerlist.begin();
00386 while(listiter != active_timerlist.end())
00387 {
00388 if ( *listiter )
00389 {
00390
00391 if (!( *(*listiter) <= *t ))
00392 break;
00393
00394 }
00395 listiter++;
00396 }
00397 active_timerlist.insert(listiter,t);
00398
00399
00400 #ifdef DEBUG_TIMER
00401 Log(DEBUG_LOG,LOG_NORMAL, "Timer", "TimerManager::insert_into_list() - inserting timer " << t->id << " list now:");
00402 #endif
00403
00404 #ifdef DEBUG_TIMER
00405 for(timerlist_t::iterator listpiter= active_timerlist.begin();
00406 listpiter != active_timerlist.end();
00407 listpiter++)
00408 {
00409 Log(DEBUG_LOG,LOG_NORMAL, "Timer", "TimerManager::insert_into_list() - timer list, timer#: " << (*listpiter ? (*listpiter)->id : 0));
00410 }
00411 #endif
00412
00413 }
00414
00420 void
00421 TimerManager::delete_from_list(timer *t) {
00422
00423 if (!t) return;
00424
00425 #ifdef DEBUG_TIMER
00426 Log(DEBUG_LOG,LOG_NORMAL, "Timer", "TimerManager::delete_from_list() - deleting timer " << t->id);
00427 #endif
00428 timerlist_t::iterator listiter= find(active_timerlist.begin(),active_timerlist.end(),t);
00429 if ( listiter != active_timerlist.end() )
00430 active_timerlist.erase(listiter);
00431 #ifdef DEBUG_TIMER
00432 if (first())
00433 Log(DEBUG_LOG,LOG_NORMAL, "Timer", "TimerManager::delete_from_list() - first timer now " << (first() ? first()->id : 0) );
00434 #endif
00435 }
00436
00442 TimerManager::timer*
00443 TimerManager::collect_elapsed()
00444 {
00445 struct timespec tod;
00446 gettimeofday_timespec(tod);
00447 timer now(tod,NULL,NULL,false);
00448
00449 timerlist_t::iterator currentit = active_timerlist.begin();
00450 timer* curr= first();
00451 #ifdef DEBUG_TIMER
00452 if (curr)
00453 Log(DEBUG_LOG,LOG_NORMAL, "Timer", "TimerManager::collect_elapsed() - first timer is " << curr->id);
00454 #endif
00455
00456
00457 while (curr && ((*curr)<=now))
00458 {
00459 hashmap.erase(curr->id);
00460 #ifdef DEBUG_TIMER
00461 Log(DEBUG_LOG,LOG_NORMAL, "Timer", "TimerManager::collect_elapsed() - deleted elapsed timer " << curr->id);
00462 #endif
00463
00464 elapsed_timerlist.push_back(curr);
00465
00466 currentit= active_timerlist.erase(currentit);
00467
00468 curr= (currentit != active_timerlist.end()) ? *currentit : 0;
00469 }
00470
00471
00472 timer* elapsed = elapsed_timerlist.empty() ? 0 : elapsed_timerlist.front();
00473
00474
00475 if (elapsed) pthread_cond_signal(&cond);
00476
00477 return elapsed;
00478 }
00479
00487 uint32 TimerManager::process_elapsed()
00488 {
00489 uint32 num = 0;
00490 timer *tmp = NULL;
00491
00492
00493 for (timerlist_t::iterator elapsed_it= elapsed_timerlist.begin();
00494 elapsed_it != elapsed_timerlist.end();
00495 elapsed_it= elapsed_timerlist.erase(elapsed_it))
00496 {
00497
00498 if ( (tmp = *elapsed_it) != 0)
00499 {
00500 tmp->do_callback();
00501
00502 delete tmp;
00503 num++;
00504 }
00505
00506 }
00507 return num;
00508 }
00509
00514 TimerManager::timer::timer(struct timespec& ts, TimerCallback* tc, timer_callback_param_t tcp, bool get_id) :
00515 id (0),
00516 time(ts),
00517 callback(tc),
00518 param(tcp)
00519 {
00520 if (get_id) while (id==0) id = next_id++;
00521 }
00522
00524 timer_id_t TimerManager::timer::next_id = 1;
00525
00530 inline
00531 bool
00532 TimerManager::timer::operator<=(const timer& t) {
00533 if (time.tv_sec == t.time.tv_sec) {
00534
00535 return (time.tv_nsec <= t.time.tv_nsec);
00536 } else {
00537
00538 return (time.tv_sec < t.time.tv_sec);
00539 }
00540 }
00541
00542 inline
00543 void
00544 TimerManager::timer::do_callback() {
00545 callback->timer_expired(id,param);
00546 }
00547
00549
00550 }