core: fix two more 'no real prototype' warnings, fix one wrong caller in timer mod
[sip-router] / timer.c
1 /*
2  * $Id$
3  *
4  * Copyright (C) 2001-2003 FhG Fokus
5  *
6  * This file is part of SIP-router, a free SIP server.
7  *
8  * SIP-router is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version
12  *
13  * SIP-router is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License 
19  * along with this program; if not, write to the Free Software 
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22 /* History:
23  * --------
24  *  2003-03-19  replaced all the mallocs/frees w/ pkg_malloc/pkg_free (andrei)
25  *  2003-03-29  cleaning pkg_mallocs introduced (jiri)
26  *  2005-07-27  complete re-design/re-implementation (andrei)
27  *  2005-12-12  workaround & bug reporting for timer_del(self) called from
28  *              a timer handle; added timer_allow_del()  (andrei)
29  *  2007-05-26  workaround for darwin sigwait() bug, see slow_timer_main() or
30  *              grep __OS_darwin for more info (andrei)
31  *  2007-07-01  timer_del() returns <0 if the timer is not active or 
32  *               cannot be deleted (andrei)
33  */
34
35
36 /**
37  * @file
38  * @brief SIP-router core :: 
39  * @ingroup core
40  * Module: @ref core
41  */
42
43 #include "timer.h"
44 #include "timer_funcs.h"
45 #include "timer_ticks.h"
46 #include "dprint.h"
47 #include <time.h>     /* gettimeofday */
48 #include <sys/time.h> /* setitimer, gettimeofday */
49 #include <signal.h>   /* SIGALRM */
50 #include <errno.h>
51 #include <unistd.h> /* pause() */
52 #include <stdlib.h> /* random, debugging only */
53 #include "error.h"
54 #include "signals.h"
55 /*
56 #include "config.h"
57 */
58 #include "globals.h"
59 #include "mem/mem.h"
60 #ifdef SHM_MEM
61 #include "mem/shm_mem.h"
62 #endif
63 #include "locking.h"
64 #include "sched_yield.h"
65 #include "cfg/cfg_struct.h"
66
67
68 /* how often will the timer handler be called (in ticks) */
69 #define TIMER_HANDLER_INTERVAL  1U
70 /* how often to try to re-adjust the ticks */
71 #define TIMER_RESYNC_TICKS      (TIMER_TICKS_HZ*5U)  /* each 5 s */
72 #define TIMER_MAX_DRIFT (TIMER_TICKS_HZ/10U) /* if drift > 0.1s adjust */
73
74
75
76 static ticks_t* ticks=0;
77 static ticks_t last_ticks; /* last time we adjusted the time */
78 static ticks_t last_adj_check; /* last time we ran adjust_ticks */
79 static ticks_t prev_ticks; /* last time we ran the timer, also used as
80                                                           "current" ticks when running the timer for
81                                                           "skipped" ticks */
82
83 static struct timeval last_time;
84 static struct timeval start_time; /* for debugging */
85
86 static volatile int run_timer=0;
87 static int timer_id=0;
88
89 static gen_lock_t* timer_lock=0;
90 static struct timer_ln* volatile* running_timer=0;/* running timer handler */
91 static int in_timer=0;
92
93 #define IS_IN_TIMER() (in_timer)
94
95 #define LOCK_TIMER_LIST()               lock_get(timer_lock)
96 #define UNLOCK_TIMER_LIST()             lock_release(timer_lock)
97
98 /* we can get away without atomic_set/atomic_cmp and write barriers because we
99  * always call SET_RUNNING and IS_RUNNING while holding the timer lock
100  * => it's implicitly atomic and the lock acts as write barrier */
101 #define SET_RUNNING(t)          (*running_timer=(t))
102 #define IS_RUNNING(t)           (*running_timer==(t))
103 #define UNSET_RUNNING()         (*running_timer=0)
104
105 #ifdef USE_SLOW_TIMER
106
107 #define SLOW_TIMER_SIG  SIGUSR2
108 /* timer flags checks */
109 #define IS_FAST_TIMER(t)        (t->flags&F_TIMER_FAST)
110 #define SET_SLOW_LIST(t)        (t->flags|=F_TIMER_ON_SLOW_LIST)
111 #define RESET_SLOW_LIST(t)      (t->flags&=~F_TIMER_ON_SLOW_LIST)
112 #define IS_ON_SLOW_LIST(t)      (t->flags&F_TIMER_ON_SLOW_LIST)
113
114 #define SLOW_LISTS_NO   1024U  /* slow lists number, 2^k recommended */
115
116
117 static gen_lock_t*  slow_timer_lock; /* slow timer lock */
118 static struct timer_head* slow_timer_lists; 
119 static volatile unsigned short* t_idx; /* "main" timer index in slow_lists[] */
120 static volatile unsigned short* s_idx; /* "slow" timer index in slow_lists[] */
121 static struct timer_ln* volatile* running_timer2=0; /* timer handler running
122                                                                                                              in the "slow" timer */
123 static sigset_t slow_timer_sset;
124 pid_t slow_timer_pid;
125 static int in_slow_timer=0;
126
127 #define IS_IN_TIMER_SLOW() (in_slow_timer)
128 #define SET_RUNNING_SLOW(t)             (*running_timer2=(t))
129 #define IS_RUNNING_SLOW(t)              (*running_timer2==(t))
130 #define UNSET_RUNNING_SLOW()    (*running_timer2=0)
131
132 #define LOCK_SLOW_TIMER_LIST()          lock_get(slow_timer_lock)
133 #define UNLOCK_SLOW_TIMER_LIST()        lock_release(slow_timer_lock)
134
135
136 #endif
137
138
139 struct timer_lists* timer_lst=0;
140
141 void sig_timer(int signo)
142 {
143         (*ticks)++;
144         if (( *ticks % TIMER_HANDLER_INTERVAL)==0){
145                 /* set a flag to run the handler */
146                 run_timer=1;
147         }
148 }
149
150
151
152 void destroy_timer()
153 {
154         struct itimerval it;
155         
156         /* disable timer */
157         memset(&it, 0, sizeof(it));
158         setitimer(ITIMER_REAL, &it, 0); 
159         set_sig_h(SIGALRM, SIG_IGN);
160         if (timer_lock){
161                 lock_destroy(timer_lock);
162                 lock_dealloc(timer_lock);
163                 timer_lock=0;
164         }
165         if (ticks){
166 #ifdef SHM_MEM
167                 shm_free(ticks);
168 #else
169                 pkg_free(ticks);
170 #endif
171                 ticks=0;
172         }
173         if (timer_lst){
174 #ifdef SHM_MEM
175                 shm_free(timer_lst);
176 #else
177                 pkg_free(timer_lst);
178 #endif
179                 timer_lst=0;
180         }
181         if (running_timer){
182                 shm_free((void*)running_timer);
183                 running_timer=0;
184         }
185 #ifdef USE_SLOW_TIMER
186         if (slow_timer_lock){
187                 lock_destroy(slow_timer_lock);
188                 lock_dealloc(slow_timer_lock);
189                 slow_timer_lock=0;
190         }
191         if (slow_timer_lists){
192                 shm_free((void*)slow_timer_lists);
193                 slow_timer_lists=0;
194         }
195         if (t_idx){
196                 shm_free((void*)t_idx);
197                 t_idx=0;
198         }
199         if (s_idx){
200                 shm_free((void*)s_idx);
201                 s_idx=0;
202         }
203         if(running_timer2){
204                 shm_free((void*)running_timer2);
205                 running_timer2=0;
206         }
207 #endif
208 }
209
210
211
212 /* ret 0 on success, <0 on error*/
213 int init_timer()
214 {
215         int r;
216         int ret;
217         
218         ret=-1;
219         
220         /* init the locks */
221         timer_lock=lock_alloc();
222         if (timer_lock==0){
223                 ret=E_OUT_OF_MEM;
224                 goto error;
225         }
226         if (lock_init(timer_lock)==0){
227                 lock_dealloc(timer_lock);
228                 timer_lock=0;
229                 ret=-1;
230                 goto error;
231         }
232         /* init the shared structs */
233 #ifdef SHM_MEM
234         ticks=shm_malloc(sizeof(ticks_t));
235         timer_lst=shm_malloc(sizeof(struct timer_lists));
236 #else
237         /* in this case get_ticks won't work! */
238         LOG(L_INFO, "WARNING: no shared memory support compiled in"
239                                 " get_ticks won't work\n");
240         ticks=pkg_malloc(sizeof(ticks_t));
241         timer_lst=pkg_malloc(sizeof(struct timer_lists));
242 #endif
243         if (ticks==0){
244                 LOG(L_CRIT, "ERROR: init_timer: out of shared memory (ticks)\n");
245                 ret=E_OUT_OF_MEM;
246                 goto error;
247         }
248         if (timer_lst==0){
249                 LOG(L_CRIT, "ERROR: init_timer: out of shared memory (timer_lst)\n");
250                 ret=E_OUT_OF_MEM;
251                 goto error;
252         }
253         running_timer=shm_malloc(sizeof(struct timer_ln*));
254         if (running_timer==0){
255                 LOG(L_CRIT, "ERROR: init_timer: out of memory (running_timer)\n");
256                 ret=E_OUT_OF_MEM;
257                 goto error;
258         }
259
260         /* initial values */
261         memset(timer_lst, 0, sizeof(struct timer_lists));
262         *ticks=random(); /* random value for start, for debugging */
263         prev_ticks=last_ticks=last_adj_check=*ticks;
264         *running_timer=0;
265         if (gettimeofday(&start_time, 0)<0){
266                 LOG(L_ERR, "ERROR: init_timer: gettimeofday failed: %s [%d]\n",
267                                 strerror(errno), errno);
268                 ret=-1;
269                 goto error;
270         }
271         last_time=start_time;
272         DBG("init_timer: starting with *ticks=%u\n", (unsigned) *ticks);
273         
274         /* init timer structures */
275         for (r=0; r<H0_ENTRIES; r++)
276                 _timer_init_list(&timer_lst->h0[r]);
277         for (r=0; r<H1_ENTRIES; r++)
278                 _timer_init_list(&timer_lst->h1[r]);
279         for (r=0; r<H2_ENTRIES; r++)
280                 _timer_init_list(&timer_lst->h2[r]);
281         _timer_init_list(&timer_lst->expired);
282         
283 #ifdef USE_SLOW_TIMER
284         
285         /* init the locks */
286         slow_timer_lock=lock_alloc();
287         if (slow_timer_lock==0){
288                 ret=E_OUT_OF_MEM;
289                 goto error;
290         }
291         if (lock_init(slow_timer_lock)==0){
292                 lock_dealloc(slow_timer_lock);
293                 slow_timer_lock=0;
294                 ret=-1;
295                 goto error;
296         }
297         t_idx=shm_malloc(sizeof(*t_idx));
298         s_idx=shm_malloc(sizeof(*s_idx));
299         slow_timer_lists=shm_malloc(sizeof(struct timer_head)*SLOW_LISTS_NO);
300         running_timer2=shm_malloc(sizeof(struct timer_ln*));
301         if ((t_idx==0)||(s_idx==0) || (slow_timer_lists==0) ||(running_timer2==0)){
302                 LOG(L_ERR, "ERROR: init_timer: out of shared memory (slow)\n");
303                 ret=E_OUT_OF_MEM;
304                 goto error;
305         }
306         *t_idx=*s_idx=0;
307         *running_timer2=0;
308         for (r=0; r<SLOW_LISTS_NO; r++)
309                 _timer_init_list(&slow_timer_lists[r]);
310         
311 #endif
312         
313         DBG("init_timer: timer_list between %p and %p\n",
314                         &timer_lst->h0[0], &timer_lst->h2[H2_ENTRIES]);
315         return 0;
316 error:
317         destroy_timer();
318         return ret;
319 }
320
321
322
323 #ifdef USE_SLOW_TIMER
324 /* arm the "slow" timer ( start it) 
325  * returns -1 on error
326  * WARNING: use it in the same process as the timer
327  *  (the one using pause(); timer_handler()) or
328  *  change run_timer to a pointer in shared mem */
329 int arm_slow_timer()
330 {
331         sigemptyset(&slow_timer_sset);
332         sigaddset(&slow_timer_sset, SLOW_TIMER_SIG);
333 again:
334         if (sigprocmask(SIG_BLOCK, &slow_timer_sset, 0)==-1){
335                 if (errno==EINTR) goto again;
336                 LOG(L_ERR, "ERROR: arm_slow_timer: sigprocmask failed: %s [%d]}n",
337                                 strerror(errno), errno);
338                 goto error;
339         }
340 #ifdef __OS_darwin
341         /* workaround for darwin sigwait bug, see slow_timer_main() for more
342            info (or grep __OS_darwin) */
343         /* keep in sync wih main.c: sig_usr() - signals we are interested in */
344         sigaddset(&slow_timer_sset, SIGINT);
345         sigaddset(&slow_timer_sset, SIGTERM);
346         sigaddset(&slow_timer_sset, SIGUSR1);
347         sigaddset(&slow_timer_sset, SIGHUP);
348         sigaddset(&slow_timer_sset, SIGCHLD);
349         sigaddset(&slow_timer_sset, SIGALRM);
350 #endif
351         /* initialize the config framework */
352         if (cfg_child_init()) goto error;
353
354         return 0;
355 error:
356         return -1;
357 }
358 #endif
359
360
361
362
363 /* arm the timer ( start it) 
364  * returns -1 on error
365  * WARNING: use it in the same process as the timer
366  *  (the one using pause(); timer_handler()) or
367  *  change run_timer to a pointer in shared mem */
368 int arm_timer()
369 {
370         struct itimerval it;
371         /* init signal generation */
372         it.it_interval.tv_sec=0;
373         it.it_interval.tv_usec=1000000/TIMER_TICKS_HZ;
374         it.it_value=it.it_interval;
375         /* install the signal handler */
376         if (set_sig_h(SIGALRM, sig_timer) == SIG_ERR ){
377                 LOG(L_CRIT, "ERROR: init_timer: the SIGALRM signal handler cannot"
378                                         " be installed: %s [%d]\n", strerror(errno), errno);
379                 return -1;
380         }
381         if (setitimer(ITIMER_REAL, &it, 0) == -1){
382                 LOG(L_CRIT, "ERROR: init_timer: setitimer failed: %s [%d]\n",
383                                         strerror(errno), errno);
384                 return -1;
385         }
386         if (gettimeofday(&last_time, 0)<0){
387                 LOG(L_ERR, "ERROR: arm_timer: gettimeofday failed: %s [%d]\n",
388                                 strerror(errno), errno);
389                 return -1;
390         }
391         /* initialize the config framework */
392         if (cfg_child_init()) return -1;
393
394         return 0;
395 }
396
397
398
399 #ifdef DBG_ser_time
400 /* debugging  only */
401 void check_ser_drift();
402 #endif /* DBG_set_time */
403
404
405
406 /* adjust the timer using the "real" time, each TIMER_RESYNC_TICKS, but only
407  * if timer drift > TIMER_MAX_DRIFT
408  * NOTES: - it will adjust time within  TIMER_MAX_DRIFT from the "real"
409  *          elapsed time
410  *        - it will never decrease the *ticks, only increase it (monotonic)
411  *        - it works ok as long as the adjustment interval < MAX_TICKS_T
412  * -- andrei
413  */
414 inline static void adjust_ticks()
415 {
416         struct timeval crt_time;
417         long long diff_time;
418         ticks_t diff_time_ticks;
419         ticks_t diff_ticks_raw;
420         s_ticks_t delta;
421         
422         /* fix ticks if necessary */
423         if ((*ticks-last_adj_check)>=(ticks_t)TIMER_RESYNC_TICKS){
424 #ifdef DBG_ser_time
425                 check_ser_drift();
426 #endif /* DBG_ser_time */
427                 last_adj_check=*ticks;
428                 if (gettimeofday(&crt_time, 0)<0){
429                         LOG(L_ERR, "ERROR: adjust_ticks: gettimeofday failed: %s [%d]\n",
430                                 strerror(errno), errno);
431                         return; /* ignore */
432                 }
433                 diff_time=(long long)crt_time.tv_sec*1000000+crt_time.tv_usec-
434                                         ((long long) last_time.tv_sec*1000000+last_time.tv_usec);
435                 if (diff_time<0){
436                         LOG(L_WARN, "WARNING: time changed backwards %ld ms ignoring...\n",
437                                                 (long)(diff_time/1000));
438                         last_time=crt_time;
439                         last_ticks=*ticks;
440                 }else{
441                         diff_ticks_raw=*ticks-last_ticks;
442                         diff_time_ticks=(ticks_t)((diff_time*TIMER_TICKS_HZ)/1000000LL);
443                         delta=(s_ticks_t)(diff_time_ticks-diff_ticks_raw);
444                         if (delta<-1){
445                                 LOG(L_WARN, "WARNING: our timer runs faster then real-time"
446                                                 " (%lu ms / %u ticks our time .->"
447                                                  " %lu ms / %u ticks real time)\n", 
448                                                 (unsigned long)(diff_ticks_raw*1000L/TIMER_TICKS_HZ),
449                                                 diff_ticks_raw,
450                                                 (unsigned long)(diff_time/1000), diff_time_ticks);
451                                 last_time=crt_time;
452                                 last_ticks=*ticks;
453                         }else{
454                                 /* fix the ticks */
455                                 if (delta>(s_ticks_t)TIMER_MAX_DRIFT){
456 #ifndef TIMER_DEBUG
457                                         if (delta > 2*(s_ticks_t)TIMER_MAX_DRIFT+1)
458 #endif
459                                                 DBG("adjusting timer ticks (%lu) with %ld ms"
460                                                                 " (%ld ticks)\n",
461                                                                 (unsigned long)*ticks,
462                                                         (long)(delta*1000)/TIMER_TICKS_HZ, (long)delta);
463                                         *ticks+=(ticks_t)delta;
464                                 }else{
465                                         /*DBG("incredible, but our timer is in sync with"
466                                                         " real time (%lu)\n", (unsigned long)*ticks);
467                                         */
468                                 }
469                         }
470                 }
471         }
472 }
473
474
475
476 /* time(2) equivalent, using ser internal timers (faster then a syscall) */
477 time_t ser_time(time_t *t)
478 {
479         if (likely(t==0))
480                 return last_time.tv_sec+TICKS_TO_S(*ticks-last_ticks);
481         *t=last_time.tv_sec+TICKS_TO_S(*ticks-last_ticks);
482         return *t;
483 }
484
485
486
487 /* gettimeofday(2) equivalent, using ser internal timers (faster 
488  * but more imprecise)
489  * WARNING: ignores tz (it's obsolete anyway)*/
490 int ser_gettimeofday(struct timeval* tv, struct timezone* tz)
491 {
492         if (likely(tv!=0)){
493                 tv->tv_sec=last_time.tv_sec+TICKS_TO_S(*ticks-last_ticks);
494                 tv->tv_usec=last_time.tv_usec+
495                                         (TICKS_TO_MS(*ticks-last_ticks)%1000)*1000;
496         }
497         return 0;
498 }
499
500
501
502 #ifdef DBG_ser_time
503 /* debugging  only, remove */
504 void check_ser_drift()
505 {
506         time_t t1, t2;
507         struct timeval tv1, tv2;
508         int r;
509         
510         t1=time(0);
511         t2=ser_time(0);
512         if (t1!=t2)
513                 BUG("time(0)!=ser_time(0) : %d != %d \n", (unsigned)t1, (unsigned)t2);
514         
515         r=gettimeofday(&tv1, 0);
516         ser_gettimeofday(&tv2, 0);
517         if (tv1.tv_sec!=tv2.tv_sec)
518                 BUG("gettimeofday seconds!=ser_gettimeofday seconds : %d != %d \n",
519                                 (unsigned)tv1.tv_sec, (unsigned)tv2.tv_sec);
520         else if ((tv1.tv_usec > tv2.tv_usec) && 
521                                 (unsigned)(tv1.tv_usec-tv2.tv_usec)>100000)
522                 BUG("gettimeofday usecs > ser_gettimeofday with > 0.1s : %d ms\n",
523                         (unsigned)(tv1.tv_usec-tv2.tv_usec)/1000);
524         else if ((tv1.tv_usec < tv2.tv_usec) && 
525                                 (unsigned)(tv2.tv_usec-tv1.tv_usec)>100000)
526                 BUG("gettimeofday usecs < ser_gettimeofday with > 0.1s : %d ms\n",
527                         (unsigned)(tv2.tv_usec-tv1.tv_usec)/1000);
528 }
529 #endif /* DBG_ser_time */
530
531
532
533 struct timer_ln* timer_alloc()
534 {
535         return shm_malloc(sizeof(struct timer_ln));
536 }
537
538 void timer_free(struct timer_ln* t)
539 {
540         shm_free(t);
541 }
542
543
544 /* unsafe (no lock ) timer add function
545  * t = current ticks
546  * tl must be filled (the intial_timeout and flags must be set)
547  * returns -1 on error, 0 on success */
548 static inline int _timer_add(ticks_t t, struct timer_ln* tl)
549 {
550         ticks_t delta;
551
552 #ifdef USE_SLOW_TIMER
553         tl->flags&=~((unsigned short)F_TIMER_ON_SLOW_LIST);
554         tl->slow_idx=0;
555 #endif
556         delta=tl->initial_timeout;
557         tl->expire=t+delta;
558         return _timer_dist_tl(tl, delta);
559 }
560
561
562
563 /* "public", safe timer add functions
564  * adds a timer at delta ticks from the current time
565  * returns -1 on error, 0 on success
566  * WARNING: to re-add an expired or deleted timer you must call
567  *          timer_reinit(tl) prior to timer_add
568  *          The default behaviour allows timer_add to add a timer only if it
569  *          has never been added before.
570  */
571 #ifdef TIMER_DEBUG
572 int timer_add_safe(struct timer_ln* tl, ticks_t delta,
573                                         const char* file, const char* func, unsigned line)
574 #else
575 int timer_add_safe(struct timer_ln* tl, ticks_t delta)
576 #endif
577 {
578         int ret;
579         
580         LOCK_TIMER_LIST();
581         if (tl->flags & F_TIMER_ACTIVE){
582 #ifdef TIMER_DEBUG
583                 LOG(timerlog, "timer_add called on an active timer %p (%p, %p),"
584                                         " flags %x\n", tl, tl->next, tl->prev, tl->flags);
585                 LOG(timerlog, "WARN: -timer_add-; called from %s(%s):%d\n",
586                                         func, file, line);
587                 LOG(timerlog, "WARN: -timer_add-: added %d times"
588                                         ", last from: %s(%s):%d, deleted %d times"
589                                         ", last from: %s(%s):%d, init %d times, expired %d \n",
590                                         tl->add_calls, tl->add_func, tl->add_file, tl->add_line,
591                                         tl->del_calls, tl->del_func, tl->del_file, tl->del_line,
592                                         tl->init, tl->expires_no);
593 #else
594                 DBG("timer_add called on an active timer %p (%p, %p),"
595                                         " flags %x\n", tl, tl->next, tl->prev, tl->flags);
596 #endif
597                 ret=-1; /* refusing to add active or non-reinit. timer */
598                 goto error;
599         }
600         tl->initial_timeout=delta;
601         if ((tl->next!=0) || (tl->prev!=0)){
602                 LOG(L_CRIT, "BUG: timer_add: called with linked timer: %p (%p, %p)\n",
603                                 tl, tl->next, tl->prev);
604                 ret=-1;
605                 goto error;
606         }
607         tl->flags|=F_TIMER_ACTIVE;
608 #ifdef TIMER_DEBUG
609         tl->add_file=file;
610         tl->add_func=func;
611         tl->add_line=line;
612         tl->add_calls++;
613 #endif
614         ret=_timer_add(*ticks, tl);
615 error:
616         UNLOCK_TIMER_LIST();
617         return ret;
618 }
619
620
621
622 /* safe timer delete
623  * deletes tl and inits the list pointer to 0
624  * returns  <0 on error (-1 if timer not active/already deleted and -2 if 
625  *           delete attempted from the timer handler) and 0 on success
626  */
627 #ifdef TIMER_DEBUG
628 int timer_del_safe(struct timer_ln* tl,
629                                         const char* file, const char* func, unsigned line)
630 #else
631 int timer_del_safe(struct timer_ln* tl)
632 #endif
633 {
634         int ret;
635         
636         ret=-1;
637 again:
638         /* quick exit if timer inactive */
639         if ( !(tl->flags & F_TIMER_ACTIVE)){
640 #ifdef TIMER_DEBUG
641                 LOG(timerlog, "timer_del called on an inactive timer %p (%p, %p),"
642                                         " flags %x\n", tl, tl->next, tl->prev, tl->flags);
643                 LOG(timerlog, "WARN: -timer_del-; called from %s(%s):%d\n",
644                                         func, file, line);
645                 LOG(timerlog, "WARN: -timer_del-: added %d times"
646                                         ", last from: %s(%s):%d, deleted %d times"
647                                         ", last from: %s(%s):%d, init %d times, expired %d \n",
648                                         tl->add_calls, tl->add_func, tl->add_file, tl->add_line,
649                                         tl->del_calls, tl->del_func, tl->del_file, tl->del_line,
650                                         tl->init, tl->expires_no);
651 #else
652 /*
653                 DBG("timer_del called on an inactive timer %p (%p, %p),"
654                                         " flags %x\n", tl, tl->next, tl->prev, tl->flags);
655 */
656 #endif
657                 return -1;
658         }
659 #ifdef USE_SLOW_TIMER
660                 if (IS_ON_SLOW_LIST(tl) && (tl->slow_idx!=*t_idx)){
661                         LOCK_SLOW_TIMER_LIST();
662                         if (!IS_ON_SLOW_LIST(tl) || (tl->slow_idx==*t_idx)){
663                                 UNLOCK_SLOW_TIMER_LIST();
664                                 goto again;
665                         }
666                         if (IS_RUNNING_SLOW(tl)){
667                                 UNLOCK_SLOW_TIMER_LIST();
668                                 if (IS_IN_TIMER_SLOW()){
669                                         /* if somebody tries to shoot himself in the foot,
670                                          * warn him and ignore the delete */
671                                         LOG(L_CRIT, "BUG: timer handle %p (s) tried to delete"
672                                                         " itself\n", tl);
673 #ifdef TIMER_DEBUG
674                                         LOG(timerlog, "WARN: -timer_del-: called from %s(%s):%d\n",
675                                                                         func, file, line);
676                                         LOG(timerlog, "WARN: -timer_del-: added %d times"
677                                                 ", last from: %s(%s):%d, deleted %d times"
678                                                 ", last from: %s(%s):%d, init %d times, expired %d \n",
679                                                 tl->add_calls, tl->add_func, tl->add_file,
680                                                 tl->add_line, tl->del_calls, tl->del_func, 
681                                                 tl->del_file, tl->del_line, tl->init, tl->expires_no);
682 #endif
683                                         return -2; /* do nothing */
684                                 }
685                                 sched_yield(); /* wait for it to complete */
686                                 goto again;
687                         }
688                         if (tl->next!=0){
689                                 _timer_rm_list(tl); /* detach */
690                                 tl->next=tl->prev=0;
691                                 ret=0;
692 #ifdef TIMER_DEBUG
693                                 tl->del_file=file;
694                                 tl->del_func=func;
695                                 tl->del_line=line;
696                                 tl->flags|=F_TIMER_DELETED;
697 #endif
698                         }else{
699 #ifdef TIMER_DEBUG
700                                 LOG(timerlog, "timer_del: (s) timer %p (%p, %p) flags %x "
701                                                         "already detached\n",
702                                                         tl, tl->next, tl->prev, tl->flags);
703                                 LOG(timerlog, "WARN: -timer_del-: @%d tl=%p "
704                                         "{ %p, %p, %d, %d, %p, %p, %04x, -}\n", get_ticks_raw(), 
705                                         tl,  tl->next, tl->prev, tl->expire, tl->initial_timeout,
706                                         tl->data, tl->f, tl->flags);
707                                 LOG(timerlog, "WARN: -timer_del-; called from %s(%s):%d\n",
708                                                 func, file, line);
709                                 LOG(timerlog, "WARN: -timer_del-: added %d times"
710                                                 ", last from: %s(%s):%d, deleted %d times"
711                                                 ", last from: %s(%s):%d, init %d times, expired %d \n",
712                                                 tl->add_calls,
713                                                 tl->add_func, tl->add_file, tl->add_line,
714                                                 tl->del_calls,
715                                                 tl->del_func, tl->del_file, tl->del_line,
716                                                 tl->init, tl->expires_no);
717 #else
718 /*
719                                 DBG("timer_del: (s) timer %p (%p, %p) flags %x "
720                                                         "already detached\n",
721                                                         tl, tl->next, tl->prev, tl->flags);
722 */
723 #endif
724                                 ret=-1;
725                         }
726                         UNLOCK_SLOW_TIMER_LIST();
727                 }else{
728 #endif
729                         LOCK_TIMER_LIST();
730 #ifdef USE_SLOW_TIMER
731                         if (IS_ON_SLOW_LIST(tl) && (tl->slow_idx!=*t_idx)){
732                                 UNLOCK_TIMER_LIST();
733                                 goto again;
734                         }
735 #endif
736                         if (IS_RUNNING(tl)){
737                                 UNLOCK_TIMER_LIST();
738                                 if (IS_IN_TIMER()){
739                                         /* if somebody tries to shoot himself in the foot,
740                                          * warn him and ignore the delete */
741                                         LOG(L_CRIT, "BUG: timer handle %p tried to delete"
742                                                         " itself\n", tl);
743 #ifdef TIMER_DEBUG
744                                         LOG(timerlog, "WARN: -timer_del-: called from %s(%s):%d\n",
745                                                                         func, file, line);
746                                         LOG(timerlog, "WARN: -timer_del-: added %d times"
747                                                 ", last from: %s(%s):%d, deleted %d times"
748                                                 ", last from: %s(%s):%d, init %d times, expired %d \n",
749                                                 tl->add_calls, tl->add_func, tl->add_file,
750                                                 tl->add_line, tl->del_calls, tl->del_func, 
751                                                 tl->del_file, tl->del_line, tl->init, tl->expires_no);
752 #endif
753                                         return -2; /* do nothing */
754                                 }
755                                 sched_yield(); /* wait for it to complete */
756                                 goto again;
757                         }
758                         if ((tl->next!=0)&&(tl->prev!=0)){
759                                 _timer_rm_list(tl); /* detach */
760                                 tl->next=tl->prev=0;
761                                 ret=0;
762 #ifdef TIMER_DEBUG
763                                 tl->del_file=file;
764                                 tl->del_func=func;
765                                 tl->del_line=line;
766                                 tl->flags|=F_TIMER_DELETED;
767 #endif
768                         }else{
769 #ifdef TIMER_DEBUG
770                                 LOG(timerlog, "timer_del: (f) timer %p (%p, %p) flags %x "
771                                                         "already detached\n",
772                                                         tl, tl->next, tl->prev, tl->flags);
773                                 LOG(timerlog, "WARN: -timer_del-: @%d tl=%p "
774                                         "{ %p, %p, %d, %d, %p, %p, %04x, -}\n", get_ticks_raw(), 
775                                         tl,  tl->next, tl->prev, tl->expire, tl->initial_timeout,
776                                         tl->data, tl->f, tl->flags);
777                                 LOG(timerlog, "WARN: -timer_del-; called from %s(%s):%d\n",
778                                                 func, file, line);
779                                 LOG(timerlog, "WARN: -timer_del-: added %d times"
780                                                 ", last from: %s(%s):%d, deleted %d times"
781                                                 ", last from: %s(%s):%d, init %d times, expired %d \n",
782                                                 tl->add_calls,
783                                                 tl->add_func, tl->add_file, tl->add_line,
784                                                 tl->del_calls,
785                                                 tl->del_func, tl->del_file, tl->del_line,
786                                                 tl->init, tl->expires_no);
787 #else
788 /*
789                                 DBG("timer_del: (f) timer %p (%p, %p) flags %x "
790                                                         "already detached\n",
791                                                         tl, tl->next, tl->prev, tl->flags);
792 */
793 #endif
794                                 ret=-1;
795                         }
796                         UNLOCK_TIMER_LIST();
797 #ifdef USE_SLOW_TIMER
798                 }
799 #endif
800 return ret;
801 }
802
803
804
805 /* marks a timer as "to be deleted when the handler ends", usefull when
806  * the timer handler knows it won't prolong the timer anymore (it will 
807  * return 0) and will do some time consuming work. Calling this function
808  * will cause simultaneous timer_dels to return immediately (they won't 
809  * wait anymore for the timer handle to finish). It will also allow 
810  * self-deleting from the timer handle without bug reports.
811  * WARNING: - if you rely on timer_del to know when the timer handle execution
812  *            finishes (e.g. to free resources used in the timer handle), don't
813  *            use this function.
814  *          - this function can be called only from a timer handle (in timer
815  *            context), all other calls will have no effect and will log a
816  *            bug message
817  */
818 void timer_allow_del(void)
819 {
820         if (IS_IN_TIMER() ){
821                         UNSET_RUNNING();
822         }else
823 #ifdef USE_SLOW_TIMER
824         if (IS_IN_TIMER_SLOW()){
825                         UNSET_RUNNING_SLOW();
826         }else 
827 #endif
828                 LOG(L_CRIT, "BUG: timer_allow_del called outside a timer handle\n");
829 }
830
831
832 /* called from timer_handle, must be called with the timer lock held
833  * WARNING: expired one shot timers are _not_ automatically reinit
834  *          (because they could have been already freed from the timer
835  *           handler so a reinit would not be safe!) */
836 inline static void timer_list_expire(ticks_t t, struct timer_head* h
837 #ifdef USE_SLOW_TIMER
838                                                                                 , struct timer_head* slow_l,
839                                                                                 slow_idx_t slow_mark
840 #endif
841                                                                                                                                         )
842 {
843         struct timer_ln * tl;
844         ticks_t ret;
845 #ifdef TIMER_DEBUG
846         struct timer_ln* first;
847         int i=0;
848         
849         first=h->next;
850 #endif
851         
852         /*DBG("timer_list_expire @ ticks = %lu, list =%p\n",
853                         (unsigned long) *ticks, h);
854         */
855         while(h->next!=(struct timer_ln*)h){
856                 tl=h->next;
857 #ifdef TIMER_DEBUG /* FIXME: replace w/ EXTRA_DEBUG */
858                 if (tl==0){
859                         LOG(L_CRIT, "BUG: timer_list_expire: tl=%p, h=%p {%p, %p}\n",
860                                         tl, h, h->next, h->prev);
861                         abort();
862                 }else if((tl->next==0) || (tl->prev==0)){
863                         LOG(L_CRIT, "BUG: timer_list_expire: @%d tl=%p "
864                                         "{ %p, %p, %d, %d, %p, %p, %04x, -},"
865                                         " h=%p {%p, %p}\n", t, 
866                                         tl,  tl->next, tl->prev, tl->expire, tl->initial_timeout,
867                                         tl->data, tl->f, tl->flags, 
868                                         h, h->next, h->prev);
869                         LOG(L_CRIT, "BUG: -timer_list_expire-: cycle %d, first %p,"
870                                                 "running %p\n", i, first, *running_timer);
871                         LOG(L_CRIT, "BUG: -timer_list_expire-: added %d times"
872                                                 ", last from: %s(%s):%d, deleted %d times"
873                                                 ", last from: %s(%s):%d, init %d times, expired %d \n",
874                                                 tl->add_calls,
875                                                 tl->add_func, tl->add_file, tl->add_line,
876                                                 tl->del_calls,
877                                                 tl->del_func, tl->del_file, tl->del_line,
878                                                 tl->init, tl->expires_no);
879                         abort();
880                 }
881                 i++;
882 #endif
883                 _timer_rm_list(tl); /* detach */
884 #ifdef USE_SLOW_TIMER
885                 if (IS_FAST_TIMER(tl)){
886 #endif
887                 /* if fast timer */
888                         SET_RUNNING(tl);
889                         tl->next=tl->prev=0; /* debugging */
890 #ifdef TIMER_DEBUG
891                         tl->expires_no++;
892 #endif
893                         UNLOCK_TIMER_LIST(); /* acts also as write barrier */ 
894                                 ret=tl->f(t, tl, tl->data);
895                                 /* reset the configuration group handles */
896                                 cfg_reset_all();
897                                 if (ret==0){
898                                         UNSET_RUNNING();
899                                         LOCK_TIMER_LIST();
900                                 }else{
901                                         /* not one-shot, re-add it */
902                                         LOCK_TIMER_LIST();
903                                         if (ret!=(ticks_t)-1) /* ! periodic */
904                                                 tl->initial_timeout=ret;
905                                         _timer_add(t, tl);
906                                         UNSET_RUNNING();
907                                 }
908 #ifdef USE_SLOW_TIMER
909                 }else{
910                         /* slow timer */
911                         SET_SLOW_LIST(tl);
912                         tl->slow_idx=slow_mark; /* current index */
913                         /* overflow check in timer_handler*/
914                         _timer_add_list(slow_l, tl);
915                         
916                 }
917 #endif
918         }
919 }
920
921
922
923 /* "main" timer routine
924  * WARNING: it should never be called twice for the same *ticks value
925  * (it could cause too fast expires for long timers), *ticks must be also
926  *  always increasing */
927 static void timer_handler()
928 {
929         ticks_t saved_ticks;
930 #ifdef USE_SLOW_TIMER
931         int run_slow_timer;
932         int i;
933         
934         run_slow_timer=0;
935         i=(slow_idx_t)(*t_idx%SLOW_LISTS_NO);
936 #endif
937         
938         /*DBG("timer_handler: called, ticks=%lu, prev_ticks=%lu\n",
939                         (unsigned long)*ticks, (unsigned long)prev_ticks);
940         */
941         run_timer=0; /* reset run_timer */
942         adjust_ticks();
943         LOCK_TIMER_LIST();
944         do{
945                 saved_ticks=*ticks; /* protect against time running backwards */
946                 if (prev_ticks>=saved_ticks){
947                         LOG(L_CRIT, "BUG: timer_handler: backwards or still time\n");
948                         /* try to continue */
949                         prev_ticks=saved_ticks-1;
950                         break;
951                 }
952                 /* go through all the "missed" ticks, taking a possible overflow
953                  * into account */
954                 for (prev_ticks=prev_ticks+1; prev_ticks!=saved_ticks; prev_ticks++) 
955                         timer_run(prev_ticks);
956                 timer_run(prev_ticks); /* do it for saved_ticks too */
957         }while(saved_ticks!=*ticks); /* in case *ticks changed */
958 #ifdef USE_SLOW_TIMER
959         timer_list_expire(*ticks, &timer_lst->expired, &slow_timer_lists[i],
960                                                 *t_idx);
961 #else
962         timer_list_expire(*ticks, &timer_lst->expired);
963 #endif
964         /* WARNING: add_timer(...,0) must go directly to expired list, since
965          * otherwise there is a race between timer running and adding it
966          * (it could expire it H0_ENTRIES ticks later instead of 'now')*/
967 #ifdef USE_SLOW_TIMER
968         if (slow_timer_lists[i].next!=(struct timer_ln*)&slow_timer_lists[i]){
969                 run_slow_timer=1;
970                 if ((slow_idx_t)(*t_idx-*s_idx) < (SLOW_LISTS_NO-1U))
971                         (*t_idx)++;
972                 else{
973                         LOG(L_ERR, "ERROR: slow timer too slow: overflow (%d - %d = %d)\n",
974                                         *t_idx, *s_idx, *t_idx-*s_idx);
975                         /* trying to continue */
976                 }
977         }
978 #endif
979         UNLOCK_TIMER_LIST();
980 #ifdef USE_SLOW_TIMER
981         /* wake up the "slow" timer */
982         if (run_slow_timer)
983                 kill(slow_timer_pid, SLOW_TIMER_SIG);
984 #endif
985 }
986
987
988
989 /* main timer function, never exists */
990 void timer_main()
991 {
992         in_timer=1; /* mark this process as the fast timer */
993         while(1){
994                 if (run_timer){
995                         /* update the local cfg if needed */
996                         cfg_update();
997
998                         timer_handler();
999                 }
1000                 pause();
1001         }
1002 }
1003
1004
1005
1006 /* generic call back for the old style timer functions */
1007 static ticks_t compat_old_handler(ticks_t ti, struct timer_ln* tl,
1008                                                                         void * data)
1009 {
1010         struct sr_timer* t;
1011         
1012 #ifdef TIMER_DEBUG
1013         DBG("timer: compat_old_handler: calling, ticks=%u/%u, tl=%p, t=%p\n",
1014                         prev_ticks, (unsigned)*ticks, tl, data);
1015 #endif
1016         t=(struct sr_timer*)data;
1017         t->timer_f(TICKS_TO_S(*ticks), t->t_param);
1018         return (ticks_t)-1; /* periodic */
1019 }
1020
1021
1022
1023 /* register a periodic timer;
1024  * compatibility mode.w/ the old timer interface...
1025  * ret: <0 on error
1026  * Hint: if you need it in a module, register it from mod_init or it 
1027  * won't work otherwise*/
1028 int register_timer(timer_function f, void* param, unsigned int interval)
1029 {
1030         struct sr_timer* t;
1031
1032         t=shm_malloc(sizeof(struct sr_timer));
1033         if (t==0){
1034                 LOG(L_ERR, "ERROR: register_timer: out of memory\n");
1035                 goto error;
1036         }
1037         t->id=timer_id++;
1038         t->timer_f=f;
1039         t->t_param=param;
1040         
1041         timer_init(&t->tl, compat_old_handler, t, 0); /* is slow */
1042         if (timer_add(&t->tl, S_TO_TICKS(interval))!=0){
1043                 LOG(L_ERR, "ERROR: register_timer: timer_add failed\n");
1044                 return -1;
1045         }
1046         
1047         return t->id;
1048
1049 error:
1050         return E_OUT_OF_MEM;
1051 }
1052
1053
1054
1055 ticks_t get_ticks_raw()
1056 {
1057 #ifndef SHM_MEM
1058         LOG(L_CRIT, "WARNING: get_ticks: no shared memory support compiled in"
1059                         ", returning 0 (probably wrong)");
1060         return 0;
1061 #endif
1062         return *ticks;
1063 }
1064
1065
1066
1067 /* returns tick in s (for compatibility with the old code) */
1068 ticks_t get_ticks()
1069 {
1070 #ifndef SHM_MEM
1071         LOG(L_CRIT, "WARNING: get_ticks: no shared memory support compiled in"
1072                         ", returning 0 (probably wrong)");
1073         return 0;
1074 #endif
1075         return TICKS_TO_S(*ticks);
1076 }
1077
1078
1079 #ifdef USE_SLOW_TIMER
1080
1081
1082 /* slow timer main function, never exists
1083  * This function is intended to be executed in a special separated process
1084  * (the "slow" timer) which will run the timer handlers of all the registered
1085  * timers not marked as "fast". The ideea is to execute the fast timers in the
1086  * "main" timer process, as accurate as possible and defer the execution of the  * timers marked as "slow" to the "slow" timer.
1087  * Implementation details:
1088  *  - it waits for a signal and then wakes up and processes
1089  *    all the lists in slow_timer_lists from [s_idx, t_idx). It will
1090  *   -it  increments *s_idx (at the end it will be == *t_idx)
1091  *   -all list operations are protected by the "slow" timer lock
1092  */
1093 #ifdef __OS_darwin
1094 extern void sig_usr(int signo);
1095 #endif
1096
1097 void slow_timer_main()
1098 {
1099         int n;
1100         ticks_t ret;
1101         struct timer_ln* tl;
1102         unsigned short i;
1103 #ifdef USE_SIGWAIT
1104         int sig;
1105 #endif
1106         
1107         in_slow_timer=1; /* mark this process as the slow timer */
1108         while(1){
1109 #ifdef USE_SIGWAIT
1110                 n=sigwait(&slow_timer_sset, &sig);
1111 #else
1112                 n=sigwaitinfo(&slow_timer_sset, 0);
1113 #endif
1114                 if (n==-1){
1115                         if (errno==EINTR) continue; /* some other signal, ignore it */
1116                         LOG(L_ERR, "ERROR: slow_timer_main: sigwaitinfo failed: %s [%d]\n",
1117                                         strerror(errno), errno);
1118                         sleep(1);
1119                         /* try to continue */
1120                 }
1121 #ifdef USE_SIGWAIT
1122         if (sig!=SLOW_TIMER_SIG){
1123 #ifdef __OS_darwin
1124                 /* on darwin sigwait is buggy: it will cause extreme slow down
1125                    on signal delivery for the signals it doesn't wait on
1126                    (on darwin 8.8.0, g4 1.5Ghz I've measured a 36s delay!).
1127                   To work arround this bug, we sigwait() on all the signals we
1128                   are interested in ser and manually call the master signal handler 
1129                   if the signal!= slow timer signal -- andrei */
1130                 sig_usr(sig);
1131 #endif
1132                 continue;
1133         }
1134 #endif
1135                 /* update the local cfg if needed */
1136                 cfg_update();
1137                 
1138                 LOCK_SLOW_TIMER_LIST();
1139                 while(*s_idx!=*t_idx){
1140                         i= *s_idx%SLOW_LISTS_NO;
1141                         while(slow_timer_lists[i].next!=
1142                                         (struct timer_ln*)&slow_timer_lists[i]){
1143                                 tl=slow_timer_lists[i].next;
1144                                 _timer_rm_list(tl);
1145                                 tl->next=tl->prev=0;
1146 #ifdef TIMER_DEBUG
1147                                 tl->expires_no++;
1148 #endif
1149                                 SET_RUNNING_SLOW(tl);
1150                                 UNLOCK_SLOW_TIMER_LIST();
1151                                         ret=tl->f(*ticks, tl, tl->data);
1152                                         /* reset the configuration group handles */
1153                                         cfg_reset_all();
1154                                         if (ret==0){
1155                                                 /* one shot */
1156                                                 UNSET_RUNNING_SLOW();
1157                                                 LOCK_SLOW_TIMER_LIST();
1158                                         }else{
1159                                                 /* not one shot, re-add it */
1160                                                 LOCK_TIMER_LIST(); /* add it to the "main"  list */
1161                                                         RESET_SLOW_LIST(tl);
1162                                                         if (ret!=(ticks_t)-1) /* != periodic */
1163                                                                 tl->initial_timeout=ret;
1164                                                         _timer_add(*ticks, tl);
1165                                                 UNLOCK_TIMER_LIST();
1166                                                 LOCK_SLOW_TIMER_LIST();
1167                                                 UNSET_RUNNING_SLOW();
1168                                         }
1169                         }
1170                         (*s_idx)++;
1171                 }
1172                 UNLOCK_SLOW_TIMER_LIST();
1173         }
1174         
1175 }
1176
1177 #endif