1 /*
2  * Copyright (C) 2007 iptelorg GmbH
3  *
4  * This file is part of Kamailio, a free SIP server.
5  *
6  * Kamailio is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version
10  *
11  * Kamailio is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20 
21 /*!
22  * \file
23  * \brief Kamailio core :: local, per process timer routines
24  * WARNING: this should be used only within the same process, the timers
25  *  are not multi-process safe or multi-thread safe
26  *  (there are no locks)
27  * \ingroup core
28  * Module: \ref core
29  */
30 
31 
32 #include "timer.h"
33 #include "timer_funcs.h"
34 #include "dprint.h"
35 #include "tcp_conn.h"
36 #include "mem/mem.h"
37 #include "compiler_opt.h"
38 
39 #include "local_timer.h"
40 
41 
42 
43 /** init a local_timer handle
44  * returns 0 on success, -1 on error */
init_local_timer(struct local_timer * t,ticks_t crt_ticks)45 int init_local_timer(struct local_timer *t, ticks_t crt_ticks)
46 {
47 	int r;
48 
49 	/* initial values */
50 	memset(t, 0, sizeof(*t));
51 	t->prev_ticks=crt_ticks;
52 	/* init timer structures */
53 	for (r=0; r<H0_ENTRIES; r++)
54 		_timer_init_list(&t->timer_lst.h0[r]);
55 	for (r=0; r<H1_ENTRIES; r++)
56 		_timer_init_list(&t->timer_lst.h1[r]);
57 	for (r=0; r<H2_ENTRIES; r++)
58 		_timer_init_list(&t->timer_lst.h2[r]);
59 	_timer_init_list(&t->timer_lst.expired);
60 	LM_DBG("timer_list between %p and %p\n",
61 			&t->timer_lst.h0[0], &t->timer_lst.h2[H2_ENTRIES]);
62 	return 0;
63 }
64 
65 
66 
destroy_local_timer(struct local_timer * lt)67 void destroy_local_timer(struct local_timer* lt)
68 {
69 }
70 
71 
72 
73 /** generic add timer entry to the timer lists function (see _timer_add)
74  * tl->expire must be set previously, delta is the difference in ticks
75  * from current time to the timer desired expire (should be tl->expire-*tick)
76  * If you don't know delta, you probably want to call _timer_add instead.
77  */
_local_timer_dist_tl(struct local_timer * h,struct timer_ln * tl,ticks_t delta)78 static inline int _local_timer_dist_tl(struct local_timer* h,
79 										struct timer_ln* tl, ticks_t delta)
80 {
81 	if (likely(delta<H0_ENTRIES)){
82 		if (unlikely(delta==0)){
83 			LM_WARN("0 expire timer added\n");
84 			_timer_add_list(&h->timer_lst.expired, tl);
85 		}else{
86 			_timer_add_list( &h->timer_lst.h0[tl->expire & H0_MASK], tl);
87 		}
88 	}else if (likely(delta<(H0_ENTRIES*H1_ENTRIES))){
89 		_timer_add_list(&h->timer_lst.h1[(tl->expire & H1_H0_MASK)>>H0_BITS],
90 							tl);
91 	}else{
92 		_timer_add_list(&h->timer_lst.h2[tl->expire>>(H1_BITS+H0_BITS)], tl);
93 	}
94 	return 0;
95 }
96 
97 
98 
local_timer_redist(struct local_timer * l,ticks_t t,struct timer_head * h)99 static inline void local_timer_redist(struct local_timer* l,
100 										ticks_t t, struct timer_head *h)
101 {
102 	struct timer_ln* tl;
103 	struct timer_ln* tmp;
104 
105 	timer_foreach_safe(tl, tmp, h){
106 		_local_timer_dist_tl(l, tl, tl->expire-t);
107 	}
108 	/* clear the current list */
109 	_timer_init_list(h);
110 }
111 
112 
113 
114 /** local timer add function (no lock, not multithread or multiprocess safe,
115  * designed for local process use only)
116  * t = current ticks
117  * tl must be filled (the intial_timeout and flags must be set)
118  * returns -1 on error, 0 on success */
_local_timer_add(struct local_timer * h,ticks_t t,struct timer_ln * tl)119 static inline int _local_timer_add(struct local_timer *h, ticks_t t,
120 									struct timer_ln* tl)
121 {
122 	ticks_t delta;
123 
124 	delta=tl->initial_timeout;
125 	tl->expire=t+delta;
126 	return _local_timer_dist_tl(h, tl, delta);
127 }
128 
129 
130 
131 /** "public", safe timer add functions (local process use only)
132  * adds a timer at delta ticks from the current time
133  * returns -1 on error, 0 on success
134  * WARNING: to re-add a deleted or expired timer you must call
135  *          timer_reinit(tl) prior to timer_add
136  *          The default behaviour allows timer_add to add a timer only if it
137  *          has never been added before.*/
local_timer_add(struct local_timer * h,struct timer_ln * tl,ticks_t delta,ticks_t crt_ticks)138 int local_timer_add(struct local_timer* h, struct timer_ln* tl, ticks_t delta,
139 						ticks_t crt_ticks)
140 {
141 	int ret;
142 
143 	if (unlikely(tl->flags & F_TIMER_ACTIVE)){
144 		LM_DBG("called on an active timer %p (%p, %p), flags %x\n",
145 				tl, tl->next, tl->prev, tl->flags);
146 		ret=-1; /* refusing to add active or non-reinit. timer */
147 		goto error;
148 	}
149 	tl->initial_timeout=delta;
150 	if (unlikely((tl->next!=0) || (tl->prev!=0))){
151 		LM_CRIT("called with linked timer: %p (%p, %p)\n", tl, tl->next, tl->prev);
152 		ret=-1;
153 		goto error;
154 	}
155 	tl->flags|=F_TIMER_ACTIVE;
156 	ret=_local_timer_add(h, crt_ticks, tl);
157 error:
158 	return ret;
159 }
160 
161 
162 
163 /** safe timer delete
164  * deletes tl and inits the list pointer to 0
165  * WARNING: to be able to reuse a deleted timer you must call
166  *          timer_reinit(tl) on it
167  *
168  */
local_timer_del(struct local_timer * h,struct timer_ln * tl)169 void local_timer_del(struct local_timer* h, struct timer_ln* tl)
170 {
171 	/* quick exit if timer inactive */
172 	if (unlikely(!(tl->flags & F_TIMER_ACTIVE))){
173 		LM_DBG("called on an inactive timer %p (%p, %p), flags %x\n",
174 				tl, tl->next, tl->prev, tl->flags);
175 		return;
176 	}
177 	if (likely((tl->next!=0)&&(tl->prev!=0))){
178 		_timer_rm_list(tl); /* detach */
179 		tl->next=tl->prev=0;
180 	}else{
181 		LM_DBG("(f) timer %p (%p, %p) flags %x already detached\n",
182 			tl, tl->next, tl->prev, tl->flags);
183 	}
184 }
185 
186 
187 
188 /** called from timer_handle*/
local_timer_list_expire(struct local_timer * l,ticks_t t,struct timer_head * h)189 inline static void local_timer_list_expire(struct local_timer* l,
190 											ticks_t t, struct timer_head* h)
191 {
192 	struct timer_ln * tl;
193 	ticks_t ret;
194 
195 	/*LM_DBG("@ ticks = %lu, list =%p\n", (unsigned long) *ticks, h); */
196 	while(h->next!=(struct timer_ln*)h){
197 		tl=h->next;
198 		_timer_rm_list(tl); /* detach */
199 			tl->next=tl->prev=0; /* debugging */
200 				/*FIXME: process tcpconn */
201 				ret=tl->f(t, tl, tl->data);
202 				if (ret!=0){
203 					/* not one-shot, re-add it */
204 					if (ret!=(ticks_t)-1) /* ! periodic */
205 						tl->initial_timeout=ret;
206 					_local_timer_add(l, t, tl);
207 				}
208 	}
209 }
210 
211 
212 
213 /** run all the handler that expire at t ticks */
local_timer_expire(struct local_timer * h,ticks_t t)214 static inline void local_timer_expire(struct local_timer* h, ticks_t t)
215 {
216 	/* trust the compiler for optimizing */
217 	if (unlikely((t & H0_MASK)==0)){              /*r1*/
218 		if (unlikely((t & H1_H0_MASK)==0)){        /*r2*/
219 			local_timer_redist(h, t, &h->timer_lst.h2[t>>(H0_BITS+H1_BITS)]);
220 		}
221 
222 		local_timer_redist(h, t, &h->timer_lst.h1[(t & H1_H0_MASK)>>H0_BITS]);
223 															/*r2 >> H0*/
224 	}
225 	/* run handler immediately, no need to move it to the expired list
226 	 * (since no locks are used) */
227 	local_timer_list_expire(h, t, &h->timer_lst.h0[t & H0_MASK]);
228 }
229 
230 
231 
232 /** "main" local timer routine, should be called with a proper ticks value
233  * WARNING: it should never be called twice for the same ticks value
234  * (it could cause too fast expires for long timers), ticks must be also
235  *  always increasing */
local_timer_run(struct local_timer * lt,ticks_t saved_ticks)236 void local_timer_run(struct local_timer* lt, ticks_t saved_ticks)
237 {
238 
239 		/* protect against time running backwards */
240 		if (unlikely(lt->prev_ticks>=saved_ticks)){
241 			LM_CRIT("backwards or still time\n");
242 			/* try to continue */
243 			lt->prev_ticks=saved_ticks-1;
244 			return;
245 		}
246 		/* go through all the "missed" ticks, taking a possible overflow
247 		 * into account */
248 		for (lt->prev_ticks=lt->prev_ticks+1; lt->prev_ticks!=saved_ticks;
249 															lt->prev_ticks++)
250 			local_timer_expire(lt, lt->prev_ticks);
251 		local_timer_expire(lt, lt->prev_ticks); /* do it for saved_ticks too */
252 	local_timer_list_expire(lt, saved_ticks, &lt->timer_lst.expired);
253 	/* WARNING: add_timer(...,0) must go directly to expired list, since
254 	 * otherwise there is a race between timer running and adding it
255 	 * (it could expire it H0_ENTRIES ticks later instead of 'now')*/
256 }
257 
258