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