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