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
00029
00030
00031
00032
00033
00034
00035
00043 #include "timer.h"
00044 #include "timer_funcs.h"
00045 #include "timer_ticks.h"
00046 #include "dprint.h"
00047 #include <time.h>
00048 #include <sys/time.h>
00049 #include <signal.h>
00050 #include <errno.h>
00051 #include <unistd.h>
00052 #include <stdlib.h>
00053 #include "error.h"
00054 #include "signals.h"
00055
00056
00057
00058 #include "globals.h"
00059 #include "mem/mem.h"
00060 #ifdef SHM_MEM
00061 #include "mem/shm_mem.h"
00062 #endif
00063 #include "locking.h"
00064 #include "sched_yield.h"
00065 #include "cfg/cfg_struct.h"
00066
00067
00068
00069 #define TIMER_HANDLER_INTERVAL 1U
00070
00071 #define TIMER_RESYNC_TICKS (TIMER_TICKS_HZ*5U)
00072 #define TIMER_MAX_DRIFT (TIMER_TICKS_HZ/10U)
00073
00074
00075
00076 static ticks_t* ticks=0;
00077 static ticks_t last_ticks;
00078 static ticks_t last_adj_check;
00079 static ticks_t prev_ticks;
00080
00081
00082
00083 static struct timeval last_time;
00084 static struct timeval start_time;
00085
00086 static volatile int run_timer=0;
00087 static int timer_id=0;
00088
00089 static gen_lock_t* timer_lock=0;
00090 static struct timer_ln* volatile* running_timer=0;
00091 static int in_timer=0;
00092
00093 #define IS_IN_TIMER() (in_timer)
00094
00095 #define LOCK_TIMER_LIST() lock_get(timer_lock)
00096 #define UNLOCK_TIMER_LIST() lock_release(timer_lock)
00097
00098
00099
00100
00101 #define SET_RUNNING(t) (*running_timer=(t))
00102 #define IS_RUNNING(t) (*running_timer==(t))
00103 #define UNSET_RUNNING() (*running_timer=0)
00104
00105 #ifdef USE_SLOW_TIMER
00106
00107 #define SLOW_TIMER_SIG SIGUSR2
00108
00109 #define IS_FAST_TIMER(t) (t->flags&F_TIMER_FAST)
00110 #define SET_SLOW_LIST(t) (t->flags|=F_TIMER_ON_SLOW_LIST)
00111 #define RESET_SLOW_LIST(t) (t->flags&=~F_TIMER_ON_SLOW_LIST)
00112 #define IS_ON_SLOW_LIST(t) (t->flags&F_TIMER_ON_SLOW_LIST)
00113
00114 #define SLOW_LISTS_NO 1024U
00115
00116
00117 static gen_lock_t* slow_timer_lock;
00118 static struct timer_head* slow_timer_lists;
00119 static volatile unsigned short* t_idx;
00120 static volatile unsigned short* s_idx;
00121 static struct timer_ln* volatile* running_timer2=0;
00122
00123 static sigset_t slow_timer_sset;
00124 pid_t slow_timer_pid;
00125 static int in_slow_timer=0;
00126
00127 #define IS_IN_TIMER_SLOW() (in_slow_timer)
00128 #define SET_RUNNING_SLOW(t) (*running_timer2=(t))
00129 #define IS_RUNNING_SLOW(t) (*running_timer2==(t))
00130 #define UNSET_RUNNING_SLOW() (*running_timer2=0)
00131
00132 #define LOCK_SLOW_TIMER_LIST() lock_get(slow_timer_lock)
00133 #define UNLOCK_SLOW_TIMER_LIST() lock_release(slow_timer_lock)
00134
00135
00136 #endif
00137
00138
00139 struct timer_lists* timer_lst=0;
00140
00141 void sig_timer(int signo)
00142 {
00143 (*ticks)++;
00144 if (( *ticks % TIMER_HANDLER_INTERVAL)==0){
00145
00146 run_timer=1;
00147 }
00148 }
00149
00150
00151
00152 void destroy_timer()
00153 {
00154 struct itimerval it;
00155
00156
00157 memset(&it, 0, sizeof(it));
00158 setitimer(ITIMER_REAL, &it, 0);
00159 set_sig_h(SIGALRM, SIG_IGN);
00160 if (timer_lock){
00161 lock_destroy(timer_lock);
00162 lock_dealloc(timer_lock);
00163 timer_lock=0;
00164 }
00165 if (ticks){
00166 #ifdef SHM_MEM
00167 shm_free(ticks);
00168 #else
00169 pkg_free(ticks);
00170 #endif
00171 ticks=0;
00172 }
00173 if (timer_lst){
00174 #ifdef SHM_MEM
00175 shm_free(timer_lst);
00176 #else
00177 pkg_free(timer_lst);
00178 #endif
00179 timer_lst=0;
00180 }
00181 if (running_timer){
00182 shm_free((void*)running_timer);
00183 running_timer=0;
00184 }
00185 #ifdef USE_SLOW_TIMER
00186 if (slow_timer_lock){
00187 lock_destroy(slow_timer_lock);
00188 lock_dealloc(slow_timer_lock);
00189 slow_timer_lock=0;
00190 }
00191 if (slow_timer_lists){
00192 shm_free((void*)slow_timer_lists);
00193 slow_timer_lists=0;
00194 }
00195 if (t_idx){
00196 shm_free((void*)t_idx);
00197 t_idx=0;
00198 }
00199 if (s_idx){
00200 shm_free((void*)s_idx);
00201 s_idx=0;
00202 }
00203 if(running_timer2){
00204 shm_free((void*)running_timer2);
00205 running_timer2=0;
00206 }
00207 #endif
00208 }
00209
00210
00211
00212
00213 int init_timer()
00214 {
00215 int r;
00216 int ret;
00217
00218 ret=-1;
00219
00220
00221 timer_lock=lock_alloc();
00222 if (timer_lock==0){
00223 ret=E_OUT_OF_MEM;
00224 goto error;
00225 }
00226 if (lock_init(timer_lock)==0){
00227 lock_dealloc(timer_lock);
00228 timer_lock=0;
00229 ret=-1;
00230 goto error;
00231 }
00232
00233 #ifdef SHM_MEM
00234 ticks=shm_malloc(sizeof(ticks_t));
00235 timer_lst=shm_malloc(sizeof(struct timer_lists));
00236 #else
00237
00238 LOG(L_INFO, "WARNING: no shared memory support compiled in"
00239 " get_ticks won't work\n");
00240 ticks=pkg_malloc(sizeof(ticks_t));
00241 timer_lst=pkg_malloc(sizeof(struct timer_lists));
00242 #endif
00243 if (ticks==0){
00244 LOG(L_CRIT, "ERROR: init_timer: out of shared memory (ticks)\n");
00245 ret=E_OUT_OF_MEM;
00246 goto error;
00247 }
00248 if (timer_lst==0){
00249 LOG(L_CRIT, "ERROR: init_timer: out of shared memory (timer_lst)\n");
00250 ret=E_OUT_OF_MEM;
00251 goto error;
00252 }
00253 running_timer=shm_malloc(sizeof(struct timer_ln*));
00254 if (running_timer==0){
00255 LOG(L_CRIT, "ERROR: init_timer: out of memory (running_timer)\n");
00256 ret=E_OUT_OF_MEM;
00257 goto error;
00258 }
00259
00260
00261 memset(timer_lst, 0, sizeof(struct timer_lists));
00262 *ticks=random();
00263 prev_ticks=last_ticks=last_adj_check=*ticks;
00264 *running_timer=0;
00265 if (gettimeofday(&start_time, 0)<0){
00266 LOG(L_ERR, "ERROR: init_timer: gettimeofday failed: %s [%d]\n",
00267 strerror(errno), errno);
00268 ret=-1;
00269 goto error;
00270 }
00271 last_time=start_time;
00272 DBG("init_timer: starting with *ticks=%u\n", (unsigned) *ticks);
00273
00274
00275 for (r=0; r<H0_ENTRIES; r++)
00276 _timer_init_list(&timer_lst->h0[r]);
00277 for (r=0; r<H1_ENTRIES; r++)
00278 _timer_init_list(&timer_lst->h1[r]);
00279 for (r=0; r<H2_ENTRIES; r++)
00280 _timer_init_list(&timer_lst->h2[r]);
00281 _timer_init_list(&timer_lst->expired);
00282
00283 #ifdef USE_SLOW_TIMER
00284
00285
00286 slow_timer_lock=lock_alloc();
00287 if (slow_timer_lock==0){
00288 ret=E_OUT_OF_MEM;
00289 goto error;
00290 }
00291 if (lock_init(slow_timer_lock)==0){
00292 lock_dealloc(slow_timer_lock);
00293 slow_timer_lock=0;
00294 ret=-1;
00295 goto error;
00296 }
00297 t_idx=shm_malloc(sizeof(*t_idx));
00298 s_idx=shm_malloc(sizeof(*s_idx));
00299 slow_timer_lists=shm_malloc(sizeof(struct timer_head)*SLOW_LISTS_NO);
00300 running_timer2=shm_malloc(sizeof(struct timer_ln*));
00301 if ((t_idx==0)||(s_idx==0) || (slow_timer_lists==0) ||(running_timer2==0)){
00302 LOG(L_ERR, "ERROR: init_timer: out of shared memory (slow)\n");
00303 ret=E_OUT_OF_MEM;
00304 goto error;
00305 }
00306 *t_idx=*s_idx=0;
00307 *running_timer2=0;
00308 for (r=0; r<SLOW_LISTS_NO; r++)
00309 _timer_init_list(&slow_timer_lists[r]);
00310
00311 #endif
00312
00313 DBG("init_timer: timer_list between %p and %p\n",
00314 &timer_lst->h0[0], &timer_lst->h2[H2_ENTRIES]);
00315 return 0;
00316 error:
00317 destroy_timer();
00318 return ret;
00319 }
00320
00321
00322
00323 #ifdef USE_SLOW_TIMER
00324
00325
00326
00327
00328
00329 int arm_slow_timer()
00330 {
00331 sigemptyset(&slow_timer_sset);
00332 sigaddset(&slow_timer_sset, SLOW_TIMER_SIG);
00333 again:
00334 if (sigprocmask(SIG_BLOCK, &slow_timer_sset, 0)==-1){
00335 if (errno==EINTR) goto again;
00336 LOG(L_ERR, "ERROR: arm_slow_timer: sigprocmask failed: %s [%d]}n",
00337 strerror(errno), errno);
00338 goto error;
00339 }
00340 #ifdef __OS_darwin
00341
00342
00343
00344 sigaddset(&slow_timer_sset, SIGINT);
00345 sigaddset(&slow_timer_sset, SIGTERM);
00346 sigaddset(&slow_timer_sset, SIGUSR1);
00347 sigaddset(&slow_timer_sset, SIGHUP);
00348 sigaddset(&slow_timer_sset, SIGCHLD);
00349 sigaddset(&slow_timer_sset, SIGALRM);
00350 #endif
00351
00352 if (cfg_child_init()) goto error;
00353
00354 return 0;
00355 error:
00356 return -1;
00357 }
00358 #endif
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368 int arm_timer()
00369 {
00370 struct itimerval it;
00371
00372 it.it_interval.tv_sec=0;
00373 it.it_interval.tv_usec=1000000/TIMER_TICKS_HZ;
00374 it.it_value=it.it_interval;
00375
00376 if (set_sig_h(SIGALRM, sig_timer) == SIG_ERR ){
00377 LOG(L_CRIT, "ERROR: init_timer: the SIGALRM signal handler cannot"
00378 " be installed: %s [%d]\n", strerror(errno), errno);
00379 return -1;
00380 }
00381 if (setitimer(ITIMER_REAL, &it, 0) == -1){
00382 LOG(L_CRIT, "ERROR: init_timer: setitimer failed: %s [%d]\n",
00383 strerror(errno), errno);
00384 return -1;
00385 }
00386 if (gettimeofday(&last_time, 0)<0){
00387 LOG(L_ERR, "ERROR: arm_timer: gettimeofday failed: %s [%d]\n",
00388 strerror(errno), errno);
00389 return -1;
00390 }
00391
00392 if (cfg_child_init()) return -1;
00393
00394 return 0;
00395 }
00396
00397
00398
00399 #ifdef DBG_ser_time
00400
00401 void check_ser_drift();
00402 #endif
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414 inline static void adjust_ticks(void)
00415 {
00416 struct timeval crt_time;
00417 long long diff_time;
00418 ticks_t diff_time_ticks;
00419 ticks_t diff_ticks_raw;
00420 s_ticks_t delta;
00421
00422
00423 if ((*ticks-last_adj_check)>=(ticks_t)TIMER_RESYNC_TICKS){
00424 #ifdef DBG_ser_time
00425 check_ser_drift();
00426 #endif
00427 last_adj_check=*ticks;
00428 if (gettimeofday(&crt_time, 0)<0){
00429 LOG(L_ERR, "ERROR: adjust_ticks: gettimeofday failed: %s [%d]\n",
00430 strerror(errno), errno);
00431 return;
00432 }
00433 diff_time=(long long)crt_time.tv_sec*1000000+crt_time.tv_usec-
00434 ((long long) last_time.tv_sec*1000000+last_time.tv_usec);
00435 if (diff_time<0){
00436 LOG(L_WARN, "WARNING: time changed backwards %ld ms ignoring...\n",
00437 (long)(diff_time/1000));
00438 last_time=crt_time;
00439 last_ticks=*ticks;
00440 }else{
00441 diff_ticks_raw=*ticks-last_ticks;
00442 diff_time_ticks=(ticks_t)((diff_time*TIMER_TICKS_HZ)/1000000LL);
00443 delta=(s_ticks_t)(diff_time_ticks-diff_ticks_raw);
00444 if (delta<-1){
00445 LOG(L_WARN, "WARNING: our timer runs faster then real-time"
00446 " (%lu ms / %u ticks our time .->"
00447 " %lu ms / %u ticks real time)\n",
00448 (unsigned long)(diff_ticks_raw*1000L/TIMER_TICKS_HZ),
00449 diff_ticks_raw,
00450 (unsigned long)(diff_time/1000), diff_time_ticks);
00451 last_time=crt_time;
00452 last_ticks=*ticks;
00453 }else{
00454
00455 if (delta>(s_ticks_t)TIMER_MAX_DRIFT){
00456 #ifndef TIMER_DEBUG
00457 if (delta > 2*(s_ticks_t)TIMER_MAX_DRIFT+1)
00458 #endif
00459 DBG("adjusting timer ticks (%lu) with %ld ms"
00460 " (%ld ticks)\n",
00461 (unsigned long)*ticks,
00462 (long)(delta*1000)/TIMER_TICKS_HZ, (long)delta);
00463 *ticks+=(ticks_t)delta;
00464 }else{
00465
00466
00467
00468 }
00469 }
00470 }
00471 }
00472 }
00473
00474
00475
00476
00477 time_t ser_time(time_t *t)
00478 {
00479 if (likely(t==0))
00480 return last_time.tv_sec+TICKS_TO_S(*ticks-last_ticks);
00481 *t=last_time.tv_sec+TICKS_TO_S(*ticks-last_ticks);
00482 return *t;
00483 }
00484
00485
00486
00487
00488
00489
00490 int ser_gettimeofday(struct timeval* tv, struct timezone* tz)
00491 {
00492 if (likely(tv!=0)){
00493 tv->tv_sec=last_time.tv_sec+TICKS_TO_S(*ticks-last_ticks);
00494 tv->tv_usec=last_time.tv_usec+
00495 (TICKS_TO_MS(*ticks-last_ticks)%1000)*1000;
00496 }
00497 return 0;
00498 }
00499
00500
00501
00502 #ifdef DBG_ser_time
00503
00504 void check_ser_drift()
00505 {
00506 time_t t1, t2;
00507 struct timeval tv1, tv2;
00508 int r;
00509
00510 t1=time(0);
00511 t2=ser_time(0);
00512 if (t1!=t2)
00513 BUG("time(0)!=ser_time(0) : %d != %d \n", (unsigned)t1, (unsigned)t2);
00514
00515 r=gettimeofday(&tv1, 0);
00516 ser_gettimeofday(&tv2, 0);
00517 if (tv1.tv_sec!=tv2.tv_sec)
00518 BUG("gettimeofday seconds!=ser_gettimeofday seconds : %d != %d \n",
00519 (unsigned)tv1.tv_sec, (unsigned)tv2.tv_sec);
00520 else if ((tv1.tv_usec > tv2.tv_usec) &&
00521 (unsigned)(tv1.tv_usec-tv2.tv_usec)>100000)
00522 BUG("gettimeofday usecs > ser_gettimeofday with > 0.1s : %d ms\n",
00523 (unsigned)(tv1.tv_usec-tv2.tv_usec)/1000);
00524 else if ((tv1.tv_usec < tv2.tv_usec) &&
00525 (unsigned)(tv2.tv_usec-tv1.tv_usec)>100000)
00526 BUG("gettimeofday usecs < ser_gettimeofday with > 0.1s : %d ms\n",
00527 (unsigned)(tv2.tv_usec-tv1.tv_usec)/1000);
00528 }
00529 #endif
00530
00531
00532
00533 struct timer_ln* timer_alloc()
00534 {
00535 return shm_malloc(sizeof(struct timer_ln));
00536 }
00537
00538 void timer_free(struct timer_ln* t)
00539 {
00540 shm_free(t);
00541 }
00542
00543
00544
00545
00546
00547
00548 static inline int _timer_add(ticks_t t, struct timer_ln* tl)
00549 {
00550 ticks_t delta;
00551
00552 #ifdef USE_SLOW_TIMER
00553 tl->flags&=~((unsigned short)F_TIMER_ON_SLOW_LIST);
00554 tl->slow_idx=0;
00555 #endif
00556 delta=tl->initial_timeout;
00557 tl->expire=t+delta;
00558 return _timer_dist_tl(tl, delta);
00559 }
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571 #ifdef TIMER_DEBUG
00572 int timer_add_safe(struct timer_ln* tl, ticks_t delta,
00573 const char* file, const char* func, unsigned line)
00574 #else
00575 int timer_add_safe(struct timer_ln* tl, ticks_t delta)
00576 #endif
00577 {
00578 int ret;
00579
00580 LOCK_TIMER_LIST();
00581 if (tl->flags & F_TIMER_ACTIVE){
00582 #ifdef TIMER_DEBUG
00583 LOG(timerlog, "timer_add called on an active timer %p (%p, %p),"
00584 " flags %x\n", tl, tl->next, tl->prev, tl->flags);
00585 LOG(timerlog, "WARN: -timer_add-; called from %s(%s):%d\n",
00586 func, file, line);
00587 LOG(timerlog, "WARN: -timer_add-: added %d times"
00588 ", last from: %s(%s):%d, deleted %d times"
00589 ", last from: %s(%s):%d, init %d times, expired %d \n",
00590 tl->add_calls, tl->add_func, tl->add_file, tl->add_line,
00591 tl->del_calls, tl->del_func, tl->del_file, tl->del_line,
00592 tl->init, tl->expires_no);
00593 #else
00594 DBG("timer_add called on an active timer %p (%p, %p),"
00595 " flags %x\n", tl, tl->next, tl->prev, tl->flags);
00596 #endif
00597 ret=-1;
00598 goto error;
00599 }
00600 tl->initial_timeout=delta;
00601 if ((tl->next!=0) || (tl->prev!=0)){
00602 LOG(L_CRIT, "BUG: timer_add: called with linked timer: %p (%p, %p)\n",
00603 tl, tl->next, tl->prev);
00604 ret=-1;
00605 goto error;
00606 }
00607 tl->flags|=F_TIMER_ACTIVE;
00608 #ifdef TIMER_DEBUG
00609 tl->add_file=file;
00610 tl->add_func=func;
00611 tl->add_line=line;
00612 tl->add_calls++;
00613 #endif
00614 ret=_timer_add(*ticks, tl);
00615 error:
00616 UNLOCK_TIMER_LIST();
00617 return ret;
00618 }
00619
00620
00621
00622
00623
00624
00625
00626
00627 #ifdef TIMER_DEBUG
00628 int timer_del_safe(struct timer_ln* tl,
00629 const char* file, const char* func, unsigned line)
00630 #else
00631 int timer_del_safe(struct timer_ln* tl)
00632 #endif
00633 {
00634 int ret;
00635
00636 ret=-1;
00637 again:
00638
00639 if ( !(tl->flags & F_TIMER_ACTIVE)){
00640 #ifdef TIMER_DEBUG
00641 LOG(timerlog, "timer_del called on an inactive timer %p (%p, %p),"
00642 " flags %x\n", tl, tl->next, tl->prev, tl->flags);
00643 LOG(timerlog, "WARN: -timer_del-; called from %s(%s):%d\n",
00644 func, file, line);
00645 LOG(timerlog, "WARN: -timer_del-: added %d times"
00646 ", last from: %s(%s):%d, deleted %d times"
00647 ", last from: %s(%s):%d, init %d times, expired %d \n",
00648 tl->add_calls, tl->add_func, tl->add_file, tl->add_line,
00649 tl->del_calls, tl->del_func, tl->del_file, tl->del_line,
00650 tl->init, tl->expires_no);
00651 #else
00652
00653
00654
00655
00656 #endif
00657 return -1;
00658 }
00659 #ifdef USE_SLOW_TIMER
00660 if (IS_ON_SLOW_LIST(tl) && (tl->slow_idx!=*t_idx)){
00661 LOCK_SLOW_TIMER_LIST();
00662 if (!IS_ON_SLOW_LIST(tl) || (tl->slow_idx==*t_idx)){
00663 UNLOCK_SLOW_TIMER_LIST();
00664 goto again;
00665 }
00666 if (IS_RUNNING_SLOW(tl)){
00667 UNLOCK_SLOW_TIMER_LIST();
00668 if (IS_IN_TIMER_SLOW()){
00669
00670
00671 LOG(L_CRIT, "BUG: timer handle %p (s) tried to delete"
00672 " itself\n", tl);
00673 #ifdef TIMER_DEBUG
00674 LOG(timerlog, "WARN: -timer_del-: called from %s(%s):%d\n",
00675 func, file, line);
00676 LOG(timerlog, "WARN: -timer_del-: added %d times"
00677 ", last from: %s(%s):%d, deleted %d times"
00678 ", last from: %s(%s):%d, init %d times, expired %d \n",
00679 tl->add_calls, tl->add_func, tl->add_file,
00680 tl->add_line, tl->del_calls, tl->del_func,
00681 tl->del_file, tl->del_line, tl->init, tl->expires_no);
00682 #endif
00683 return -2;
00684 }
00685 sched_yield();
00686 goto again;
00687 }
00688 if (tl->next!=0){
00689 _timer_rm_list(tl);
00690 tl->next=tl->prev=0;
00691 ret=0;
00692 #ifdef TIMER_DEBUG
00693 tl->del_file=file;
00694 tl->del_func=func;
00695 tl->del_line=line;
00696 tl->flags|=F_TIMER_DELETED;
00697 #endif
00698 }else{
00699 #ifdef TIMER_DEBUG
00700 LOG(timerlog, "timer_del: (s) timer %p (%p, %p) flags %x "
00701 "already detached\n",
00702 tl, tl->next, tl->prev, tl->flags);
00703 LOG(timerlog, "WARN: -timer_del-: @%d tl=%p "
00704 "{ %p, %p, %d, %d, %p, %p, %04x, -}\n", get_ticks_raw(),
00705 tl, tl->next, tl->prev, tl->expire, tl->initial_timeout,
00706 tl->data, tl->f, tl->flags);
00707 LOG(timerlog, "WARN: -timer_del-; called from %s(%s):%d\n",
00708 func, file, line);
00709 LOG(timerlog, "WARN: -timer_del-: added %d times"
00710 ", last from: %s(%s):%d, deleted %d times"
00711 ", last from: %s(%s):%d, init %d times, expired %d \n",
00712 tl->add_calls,
00713 tl->add_func, tl->add_file, tl->add_line,
00714 tl->del_calls,
00715 tl->del_func, tl->del_file, tl->del_line,
00716 tl->init, tl->expires_no);
00717 #else
00718
00719
00720
00721
00722
00723 #endif
00724 ret=-1;
00725 }
00726 UNLOCK_SLOW_TIMER_LIST();
00727 }else{
00728 #endif
00729 LOCK_TIMER_LIST();
00730 #ifdef USE_SLOW_TIMER
00731 if (IS_ON_SLOW_LIST(tl) && (tl->slow_idx!=*t_idx)){
00732 UNLOCK_TIMER_LIST();
00733 goto again;
00734 }
00735 #endif
00736 if (IS_RUNNING(tl)){
00737 UNLOCK_TIMER_LIST();
00738 if (IS_IN_TIMER()){
00739
00740
00741 LOG(L_CRIT, "BUG: timer handle %p tried to delete"
00742 " itself\n", tl);
00743 #ifdef TIMER_DEBUG
00744 LOG(timerlog, "WARN: -timer_del-: called from %s(%s):%d\n",
00745 func, file, line);
00746 LOG(timerlog, "WARN: -timer_del-: added %d times"
00747 ", last from: %s(%s):%d, deleted %d times"
00748 ", last from: %s(%s):%d, init %d times, expired %d \n",
00749 tl->add_calls, tl->add_func, tl->add_file,
00750 tl->add_line, tl->del_calls, tl->del_func,
00751 tl->del_file, tl->del_line, tl->init, tl->expires_no);
00752 #endif
00753 return -2;
00754 }
00755 sched_yield();
00756 goto again;
00757 }
00758 if ((tl->next!=0)&&(tl->prev!=0)){
00759 _timer_rm_list(tl);
00760 tl->next=tl->prev=0;
00761 ret=0;
00762 #ifdef TIMER_DEBUG
00763 tl->del_file=file;
00764 tl->del_func=func;
00765 tl->del_line=line;
00766 tl->flags|=F_TIMER_DELETED;
00767 #endif
00768 }else{
00769 #ifdef TIMER_DEBUG
00770 LOG(timerlog, "timer_del: (f) timer %p (%p, %p) flags %x "
00771 "already detached\n",
00772 tl, tl->next, tl->prev, tl->flags);
00773 LOG(timerlog, "WARN: -timer_del-: @%d tl=%p "
00774 "{ %p, %p, %d, %d, %p, %p, %04x, -}\n", get_ticks_raw(),
00775 tl, tl->next, tl->prev, tl->expire, tl->initial_timeout,
00776 tl->data, tl->f, tl->flags);
00777 LOG(timerlog, "WARN: -timer_del-; called from %s(%s):%d\n",
00778 func, file, line);
00779 LOG(timerlog, "WARN: -timer_del-: added %d times"
00780 ", last from: %s(%s):%d, deleted %d times"
00781 ", last from: %s(%s):%d, init %d times, expired %d \n",
00782 tl->add_calls,
00783 tl->add_func, tl->add_file, tl->add_line,
00784 tl->del_calls,
00785 tl->del_func, tl->del_file, tl->del_line,
00786 tl->init, tl->expires_no);
00787 #else
00788
00789
00790
00791
00792
00793 #endif
00794 ret=-1;
00795 }
00796 UNLOCK_TIMER_LIST();
00797 #ifdef USE_SLOW_TIMER
00798 }
00799 #endif
00800 return ret;
00801 }
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818 void timer_allow_del(void)
00819 {
00820 if (IS_IN_TIMER() ){
00821 UNSET_RUNNING();
00822 }else
00823 #ifdef USE_SLOW_TIMER
00824 if (IS_IN_TIMER_SLOW()){
00825 UNSET_RUNNING_SLOW();
00826 }else
00827 #endif
00828 LOG(L_CRIT, "BUG: timer_allow_del called outside a timer handle\n");
00829 }
00830
00831
00832
00833
00834
00835
00836 inline static void timer_list_expire(ticks_t t, struct timer_head* h
00837 #ifdef USE_SLOW_TIMER
00838 , struct timer_head* slow_l,
00839 slow_idx_t slow_mark
00840 #endif
00841 )
00842 {
00843 struct timer_ln * tl;
00844 ticks_t ret;
00845 #ifdef TIMER_DEBUG
00846 struct timer_ln* first;
00847 int i=0;
00848
00849 first=h->next;
00850 #endif
00851
00852
00853
00854
00855 while(h->next!=(struct timer_ln*)h){
00856 tl=h->next;
00857 #ifdef TIMER_DEBUG
00858 if (tl==0){
00859 LOG(L_CRIT, "BUG: timer_list_expire: tl=%p, h=%p {%p, %p}\n",
00860 tl, h, h->next, h->prev);
00861 abort();
00862 }else if((tl->next==0) || (tl->prev==0)){
00863 LOG(L_CRIT, "BUG: timer_list_expire: @%d tl=%p "
00864 "{ %p, %p, %d, %d, %p, %p, %04x, -},"
00865 " h=%p {%p, %p}\n", t,
00866 tl, tl->next, tl->prev, tl->expire, tl->initial_timeout,
00867 tl->data, tl->f, tl->flags,
00868 h, h->next, h->prev);
00869 LOG(L_CRIT, "BUG: -timer_list_expire-: cycle %d, first %p,"
00870 "running %p\n", i, first, *running_timer);
00871 LOG(L_CRIT, "BUG: -timer_list_expire-: added %d times"
00872 ", last from: %s(%s):%d, deleted %d times"
00873 ", last from: %s(%s):%d, init %d times, expired %d \n",
00874 tl->add_calls,
00875 tl->add_func, tl->add_file, tl->add_line,
00876 tl->del_calls,
00877 tl->del_func, tl->del_file, tl->del_line,
00878 tl->init, tl->expires_no);
00879 abort();
00880 }
00881 i++;
00882 #endif
00883 _timer_rm_list(tl);
00884 #ifdef USE_SLOW_TIMER
00885 if (IS_FAST_TIMER(tl)){
00886 #endif
00887
00888 SET_RUNNING(tl);
00889 tl->next=tl->prev=0;
00890 #ifdef TIMER_DEBUG
00891 tl->expires_no++;
00892 #endif
00893 UNLOCK_TIMER_LIST();
00894 ret=tl->f(t, tl, tl->data);
00895
00896 cfg_reset_all();
00897 if (ret==0){
00898 UNSET_RUNNING();
00899 LOCK_TIMER_LIST();
00900 }else{
00901
00902 LOCK_TIMER_LIST();
00903 if (ret!=(ticks_t)-1)
00904 tl->initial_timeout=ret;
00905 _timer_add(t, tl);
00906 UNSET_RUNNING();
00907 }
00908 #ifdef USE_SLOW_TIMER
00909 }else{
00910
00911 SET_SLOW_LIST(tl);
00912 tl->slow_idx=slow_mark;
00913
00914 _timer_add_list(slow_l, tl);
00915
00916 }
00917 #endif
00918 }
00919 }
00920
00921
00922
00923
00924
00925
00926
00927 static void timer_handler(void)
00928 {
00929 ticks_t saved_ticks;
00930 #ifdef USE_SLOW_TIMER
00931 int run_slow_timer;
00932 int i;
00933
00934 run_slow_timer=0;
00935 i=(slow_idx_t)(*t_idx%SLOW_LISTS_NO);
00936 #endif
00937
00938
00939
00940
00941 run_timer=0;
00942 adjust_ticks();
00943 LOCK_TIMER_LIST();
00944 do{
00945 saved_ticks=*ticks;
00946 if (prev_ticks>=saved_ticks){
00947 LOG(L_CRIT, "BUG: timer_handler: backwards or still time\n");
00948
00949 prev_ticks=saved_ticks-1;
00950 break;
00951 }
00952
00953
00954 for (prev_ticks=prev_ticks+1; prev_ticks!=saved_ticks; prev_ticks++)
00955 timer_run(prev_ticks);
00956 timer_run(prev_ticks);
00957 }while(saved_ticks!=*ticks);
00958 #ifdef USE_SLOW_TIMER
00959 timer_list_expire(*ticks, &timer_lst->expired, &slow_timer_lists[i],
00960 *t_idx);
00961 #else
00962 timer_list_expire(*ticks, &timer_lst->expired);
00963 #endif
00964
00965
00966
00967 #ifdef USE_SLOW_TIMER
00968 if (slow_timer_lists[i].next!=(struct timer_ln*)&slow_timer_lists[i]){
00969 run_slow_timer=1;
00970 if ((slow_idx_t)(*t_idx-*s_idx) < (SLOW_LISTS_NO-1U))
00971 (*t_idx)++;
00972 else{
00973 LOG(L_WARN, "slow timer too slow: overflow (%d - %d = %d)\n",
00974 *t_idx, *s_idx, *t_idx-*s_idx);
00975
00976 }
00977 }
00978 #endif
00979 UNLOCK_TIMER_LIST();
00980 #ifdef USE_SLOW_TIMER
00981
00982 if (run_slow_timer)
00983 kill(slow_timer_pid, SLOW_TIMER_SIG);
00984 #endif
00985 }
00986
00987
00988
00989
00990 void timer_main()
00991 {
00992 in_timer=1;
00993 while(1){
00994 if (run_timer){
00995
00996 cfg_update();
00997
00998 timer_handler();
00999 }
01000 pause();
01001 }
01002 }
01003
01004
01005
01006
01007 static ticks_t compat_old_handler(ticks_t ti, struct timer_ln* tl,
01008 void * data)
01009 {
01010 struct sr_timer* t;
01011
01012 #ifdef TIMER_DEBUG
01013 DBG("timer: compat_old_handler: calling, ticks=%u/%u, tl=%p, t=%p\n",
01014 prev_ticks, (unsigned)*ticks, tl, data);
01015 #endif
01016 t=(struct sr_timer*)data;
01017 t->timer_f(TICKS_TO_S(*ticks), t->t_param);
01018 return (ticks_t)-1;
01019 }
01020
01021
01022
01023
01024
01025
01026
01027
01028 int register_timer(timer_function f, void* param, unsigned int interval)
01029 {
01030 struct sr_timer* t;
01031
01032 t=shm_malloc(sizeof(struct sr_timer));
01033 if (t==0){
01034 LOG(L_ERR, "ERROR: register_timer: out of memory\n");
01035 goto error;
01036 }
01037 t->id=timer_id++;
01038 t->timer_f=f;
01039 t->t_param=param;
01040
01041 timer_init(&t->tl, compat_old_handler, t, 0);
01042 if (timer_add(&t->tl, S_TO_TICKS(interval))!=0){
01043 LOG(L_ERR, "ERROR: register_timer: timer_add failed\n");
01044 return -1;
01045 }
01046
01047 return t->id;
01048
01049 error:
01050 return E_OUT_OF_MEM;
01051 }
01052
01053
01054
01055 ticks_t get_ticks_raw()
01056 {
01057 #ifndef SHM_MEM
01058 LOG(L_CRIT, "WARNING: get_ticks: no shared memory support compiled in"
01059 ", returning 0 (probably wrong)");
01060 return 0;
01061 #endif
01062 return *ticks;
01063 }
01064
01065
01066
01067
01068 ticks_t get_ticks()
01069 {
01070 #ifndef SHM_MEM
01071 LOG(L_CRIT, "WARNING: get_ticks: no shared memory support compiled in"
01072 ", returning 0 (probably wrong)");
01073 return 0;
01074 #endif
01075 return TICKS_TO_S(*ticks);
01076 }
01077
01078
01079 #ifdef USE_SLOW_TIMER
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089
01090
01091
01092
01093 #ifdef __OS_darwin
01094 extern void sig_usr(int signo);
01095 #endif
01096
01097 void slow_timer_main()
01098 {
01099 int n;
01100 ticks_t ret;
01101 struct timer_ln* tl;
01102 unsigned short i;
01103 #ifdef USE_SIGWAIT
01104 int sig;
01105 #endif
01106
01107 in_slow_timer=1;
01108 while(1){
01109 #ifdef USE_SIGWAIT
01110 n=sigwait(&slow_timer_sset, &sig);
01111 #else
01112 n=sigwaitinfo(&slow_timer_sset, 0);
01113 #endif
01114 if (n==-1){
01115 if (errno==EINTR) continue;
01116 LOG(L_ERR, "ERROR: slow_timer_main: sigwaitinfo failed: %s [%d]\n",
01117 strerror(errno), errno);
01118 sleep(1);
01119
01120 }
01121 #ifdef USE_SIGWAIT
01122 if (sig!=SLOW_TIMER_SIG){
01123 #ifdef __OS_darwin
01124
01125
01126
01127
01128
01129
01130 sig_usr(sig);
01131 #endif
01132 continue;
01133 }
01134 #endif
01135
01136 cfg_update();
01137
01138 LOCK_SLOW_TIMER_LIST();
01139 while(*s_idx!=*t_idx){
01140 i= *s_idx%SLOW_LISTS_NO;
01141 while(slow_timer_lists[i].next!=
01142 (struct timer_ln*)&slow_timer_lists[i]){
01143 tl=slow_timer_lists[i].next;
01144 _timer_rm_list(tl);
01145 tl->next=tl->prev=0;
01146 #ifdef TIMER_DEBUG
01147 tl->expires_no++;
01148 #endif
01149 SET_RUNNING_SLOW(tl);
01150 UNLOCK_SLOW_TIMER_LIST();
01151 ret=tl->f(*ticks, tl, tl->data);
01152
01153 cfg_reset_all();
01154 if (ret==0){
01155
01156 UNSET_RUNNING_SLOW();
01157 LOCK_SLOW_TIMER_LIST();
01158 }else{
01159
01160 LOCK_TIMER_LIST();
01161 RESET_SLOW_LIST(tl);
01162 if (ret!=(ticks_t)-1)
01163 tl->initial_timeout=ret;
01164 _timer_add(*ticks, tl);
01165 UNLOCK_TIMER_LIST();
01166 LOCK_SLOW_TIMER_LIST();
01167 UNSET_RUNNING_SLOW();
01168 }
01169 }
01170 (*s_idx)++;
01171 }
01172 UNLOCK_SLOW_TIMER_LIST();
01173 }
01174
01175 }
01176
01177 #endif