parser: some more const-correctness for the other functions in msg_parser.[c,h]
[sip-router] / local_timer.c
1 /*
2  * $Id$
3  *
4  * Copyright (C) 2007 iptelorg GmbH
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 /* local, per process timer routines
28  * WARNING: this should be used only within the same process, the timers
29  *  are not multi-process safe or multi-thread safe
30  *  (there are no locks)
31  *
32  * History:
33  * --------
34  *  2006-02-03  created by andrei
35  */
36
37 /*!
38  * \file
39  * \brief SIP-router core :: 
40  * \ingroup core
41  * Module: \ref core
42  */
43
44
45 #include "timer.h"
46 #include "timer_funcs.h"
47 #include "dprint.h"
48 #include "tcp_conn.h"
49 #include "mem/mem.h"
50 #include "compiler_opt.h"
51
52 #include "local_timer.h"
53
54
55
56 /* init a local_timer handle
57  * returns 0 on success, -1 on error */
58 int init_local_timer(struct local_timer *t, ticks_t crt_ticks)
59 {
60         int r;
61         
62         /* initial values */
63         memset(t, 0, sizeof(*t));
64         t->prev_ticks=crt_ticks;
65         /* init timer structures */
66         for (r=0; r<H0_ENTRIES; r++)
67                 _timer_init_list(&t->timer_lst.h0[r]);
68         for (r=0; r<H1_ENTRIES; r++)
69                 _timer_init_list(&t->timer_lst.h1[r]);
70         for (r=0; r<H2_ENTRIES; r++)
71                 _timer_init_list(&t->timer_lst.h2[r]);
72         _timer_init_list(&t->timer_lst.expired);
73         DBG("init_local_timer: timer_list between %p and %p\n",
74                         &t->timer_lst.h0[0], &t->timer_lst.h2[H2_ENTRIES]);
75         return 0;
76 }
77
78
79
80 void destroy_local_timer(struct local_timer* lt)
81 {
82 }
83
84
85
86 /* generic add timer entry to the timer lists function (see _timer_add)
87  * tl->expire must be set previously, delta is the difference in ticks
88  * from current time to the timer desired expire (should be tl->expire-*tick)
89  * If you don't know delta, you probably want to call _timer_add instead.
90  */
91 static inline int _local_timer_dist_tl(struct local_timer* h, 
92                                                                                 struct timer_ln* tl, ticks_t delta)
93 {
94         if (likely(delta<H0_ENTRIES)){
95                 if (unlikely(delta==0)){
96                         LOG(L_WARN, "WARNING: local_timer: add_timeout: 0 expire timer"
97                                                 " added\n");
98                         _timer_add_list(&h->timer_lst.expired, tl);
99                 }else{
100                         _timer_add_list( &h->timer_lst.h0[tl->expire & H0_MASK], tl);
101                 }
102         }else if (likely(delta<(H0_ENTRIES*H1_ENTRIES))){
103                 _timer_add_list(&h->timer_lst.h1[(tl->expire & H1_H0_MASK)>>H0_BITS],
104                                                         tl);
105         }else{
106                 _timer_add_list(&h->timer_lst.h2[tl->expire>>(H1_BITS+H0_BITS)], tl);
107         }
108         return 0;
109 }
110
111
112
113 static inline void local_timer_redist(struct local_timer* l,
114                                                                                 ticks_t t, struct timer_head *h)
115 {
116         struct timer_ln* tl;
117         struct timer_ln* tmp;
118         
119         timer_foreach_safe(tl, tmp, h){
120                 _local_timer_dist_tl(l, tl, tl->expire-t);
121         }
122         /* clear the current list */
123         _timer_init_list(h);
124 }
125
126
127
128 /* local timer add function (no lock, not multithread or multiprocess safe,
129  * designed for local process use only)
130  * t = current ticks
131  * tl must be filled (the intial_timeout and flags must be set)
132  * returns -1 on error, 0 on success */
133 static inline int _local_timer_add(struct local_timer *h, ticks_t t,
134                                                                         struct timer_ln* tl)
135 {
136         ticks_t delta;
137         
138         delta=tl->initial_timeout;
139         tl->expire=t+delta;
140         return _local_timer_dist_tl(h, tl, delta);
141 }
142
143
144
145 /* "public", safe timer add functions (local process use only)
146  * adds a timer at delta ticks from the current time
147  * returns -1 on error, 0 on success
148  * WARNING: to re-add a deleted or expired timer you must call
149  *          timer_reinit(tl) prior to timer_add
150  *          The default behaviour allows timer_add to add a timer only if it
151  *          has never been added before.*/
152 int local_timer_add(struct local_timer* h, struct timer_ln* tl, ticks_t delta,
153                                                 ticks_t crt_ticks)
154 {
155         int ret;
156         
157         if (unlikely(tl->flags & F_TIMER_ACTIVE)){
158                 DBG("timer_add called on an active timer %p (%p, %p),"
159                                         " flags %x\n", tl, tl->next, tl->prev, tl->flags);
160                 ret=-1; /* refusing to add active or non-reinit. timer */
161                 goto error;
162         }
163         tl->initial_timeout=delta;
164         if (unlikely((tl->next!=0) || (tl->prev!=0))){
165                 LOG(L_CRIT, "BUG: tcp_timer_add: called with linked timer:"
166                                 " %p (%p, %p)\n", tl, tl->next, tl->prev);
167                 ret=-1;
168                 goto error;
169         }
170         tl->flags|=F_TIMER_ACTIVE;
171         ret=_local_timer_add(h, crt_ticks, tl);
172 error:
173         return ret;
174 }
175
176
177
178 /* safe timer delete
179  * deletes tl and inits the list pointer to 0
180  * WARNING: to be able to reuse a deleted timer you must call
181  *          timer_reinit(tl) on it
182  * 
183  */
184 void local_timer_del(struct local_timer* h, struct timer_ln* tl)
185 {
186         /* quick exit if timer inactive */
187         if (unlikely(!(tl->flags & F_TIMER_ACTIVE))){
188                 DBG("timer_del called on an inactive timer %p (%p, %p),"
189                                         " flags %x\n", tl, tl->next, tl->prev, tl->flags);
190                 return;
191         }
192         if (likely((tl->next!=0)&&(tl->prev!=0))){
193                 _timer_rm_list(tl); /* detach */
194                 tl->next=tl->prev=0;
195         }else{
196                 DBG("timer_del: (f) timer %p (%p, %p) flags %x "
197                         "already detached\n",
198                         tl, tl->next, tl->prev, tl->flags);
199         }
200 }
201
202
203
204 /* called from timer_handle*/
205 inline static void local_timer_list_expire(struct local_timer* l, 
206                                                                                         ticks_t t, struct timer_head* h)
207 {
208         struct timer_ln * tl;
209         ticks_t ret;
210         
211         /*DBG("timer_list_expire @ ticks = %lu, list =%p\n",
212                         (unsigned long) *ticks, h);
213         */
214         while(h->next!=(struct timer_ln*)h){
215                 tl=h->next;
216                 _timer_rm_list(tl); /* detach */
217                         tl->next=tl->prev=0; /* debugging */
218                                 /*FIXME: process tcpconn */
219                                 ret=tl->f(t, tl, tl->data);
220                                 if (ret!=0){
221                                         /* not one-shot, re-add it */
222                                         if (ret!=(ticks_t)-1) /* ! periodic */
223                                                 tl->initial_timeout=ret;
224                                         _local_timer_add(l, t, tl);
225                                 }
226         }
227 }
228
229
230
231 /* run all the handler that expire at t ticks */
232 static inline void local_timer_expire(struct local_timer* h, ticks_t t)
233 {
234         /* trust the compiler for optimizing */
235         if (unlikely((t & H0_MASK)==0)){              /*r1*/
236                 if (unlikely((t & H1_H0_MASK)==0)){        /*r2*/
237                         local_timer_redist(h, t, &h->timer_lst.h2[t>>(H0_BITS+H1_BITS)]);
238                 }
239                 
240                 local_timer_redist(h, t, &h->timer_lst.h1[(t & H1_H0_MASK)>>H0_BITS]);
241                                                                                                                         /*r2 >> H0*/
242         }
243         /* run handler immediately, no need to move it to the expired list
244          * (since no locks are used) */
245         local_timer_list_expire(h, t, &h->timer_lst.h0[t & H0_MASK]);
246 }
247
248
249
250 /* "main" local timer routine, should be called with a proper ticks value
251  * WARNING: it should never be called twice for the same ticks value
252  * (it could cause too fast expires for long timers), ticks must be also
253  *  always increasing */
254 void local_timer_run(struct local_timer* lt, ticks_t saved_ticks)
255 {
256         
257                 /* protect against time running backwards */
258                 if (unlikely(lt->prev_ticks>=saved_ticks)){
259                         LOG(L_CRIT, "BUG: local_timer: backwards or still time\n");
260                         /* try to continue */
261                         lt->prev_ticks=saved_ticks-1;
262                         return;
263                 }
264                 /* go through all the "missed" ticks, taking a possible overflow
265                  * into account */
266                 for (lt->prev_ticks=lt->prev_ticks+1; lt->prev_ticks!=saved_ticks; 
267                                                                                                                         lt->prev_ticks++)
268                         local_timer_expire(lt, lt->prev_ticks);
269                 local_timer_expire(lt, lt->prev_ticks); /* do it for saved_ticks too */
270         local_timer_list_expire(lt, saved_ticks, &lt->timer_lst.expired);
271         /* WARNING: add_timer(...,0) must go directly to expired list, since
272          * otherwise there is a race between timer running and adding it
273          * (it could expire it H0_ENTRIES ticks later instead of 'now')*/
274 }
275