1 /*
2  * Copyright (C) 2009 iptelorg GmbH
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /**
18  * @file
19  * @brief Kamailio core ::  timer - separate process timers
20  *
21  *  (unrelated to the main fast and slow timers)
22  *
23  * @ingroup core
24  * Module: @ref core
25  */
26 
27 #include "timer_proc.h"
28 #include "cfg/cfg_struct.h"
29 #include "pt.h"
30 #include "ut.h"
31 #include "mem/shm_mem.h"
32 
33 #include <unistd.h>
34 
35 
36 /**
37  * \brief update internal counters for running new basic sec. timers
38  * @param timers number of basic timer processes
39  * @return 0 on success; -1 on error
40  */
register_basic_timers(int timers)41 int register_basic_timers(int timers)
42 {
43 	if(register_procs(timers)<0)
44 		return -1;
45 	cfg_register_child(timers);
46 	return 0;
47 }
48 
49 /**
50  * \brief Forks a separate simple sleep() periodic timer
51  *
52  * Forks a very basic periodic timer process, that just sleep()s for
53  * the specified interval and then calls the timer function.
54  * The new "basic timer" process execution start immediately, the sleep()
55  * is called first (so the first call to the timer function will happen
56  * \<interval\> seconds after the call to fork_basic_timer)
57  * @param child_id  @see fork_process()
58  * @param desc      @see fork_process()
59  * @param make_sock @see fork_process()
60  * @param f         timer function/callback
61  * @param param     parameter passed to the timer function
62  * @param interval  interval in seconds.
63  * @return pid of the new process on success, -1 on error
64  * (doesn't return anything in the child process)
65  */
fork_basic_timer(int child_id,char * desc,int make_sock,timer_function * f,void * param,int interval)66 int fork_basic_timer(int child_id, char* desc, int make_sock,
67 						timer_function* f, void* param, int interval)
68 {
69 	int pid;
70 
71 	pid=fork_process(child_id, desc, make_sock);
72 	if (pid<0) return -1;
73 	if (pid==0){
74 		/* child */
75 		if (cfg_child_init()) return -1;
76 		for(;;){
77 			sleep(interval);
78 			cfg_update();
79 			f(get_ticks(), param); /* ticks in s for compatibility with old
80 									* timers */
81 		}
82 	}
83 	/* parent */
84 	return pid;
85 }
86 
fork_basic_timer_w(int child_id,char * desc,int make_sock,timer_function_w * f,int worker,void * param,int interval)87 int fork_basic_timer_w(int child_id, char* desc, int make_sock,
88 						timer_function_w* f, int worker, void* param, int interval)
89 {
90 	int pid;
91 
92 	pid=fork_process(child_id, desc, make_sock);
93 	if (pid<0) return -1;
94 	if (pid==0){
95 		/* child */
96 		if (cfg_child_init()) return -1;
97 		for(;;){
98 			sleep(interval);
99 			cfg_update();
100 			f(get_ticks(), worker, param); /* ticks in s for compatibility with old
101 									* timers */
102 		}
103 	}
104 	/* parent */
105 	return pid;
106 }
107 
108 /**
109  * \brief Forks a separate simple microsecond-sleep() periodic timer
110  *
111  * Forks a very basic periodic timer process, that just us-sleep()s for
112  * the specified interval and then calls the timer function.
113  * The new "basic timer" process execution start immediately, the us-sleep()
114  * is called first (so the first call to the timer function will happen
115  * \<interval\> microseconds after the call to fork_basic_utimer)
116  * @param child_id  @see fork_process()
117  * @param desc      @see fork_process()
118  * @param make_sock @see fork_process()
119  * @param f         timer function/callback
120  * @param param     parameter passed to the timer function
121  * @param uinterval  interval in micro-seconds.
122  * @return pid of the new process on success, -1 on error
123  * (doesn't return anything in the child process)
124  */
fork_basic_utimer(int child_id,char * desc,int make_sock,utimer_function * f,void * param,int uinterval)125 int fork_basic_utimer(int child_id, char* desc, int make_sock,
126 						utimer_function* f, void* param, int uinterval)
127 {
128 	int pid;
129 	ticks_t ts;
130 
131 	pid=fork_process(child_id, desc, make_sock);
132 	if (pid<0) return -1;
133 	if (pid==0){
134 		/* child */
135 		if (cfg_child_init()) return -1;
136 		for(;;){
137 			sleep_us(uinterval);
138 			cfg_update();
139 			ts = get_ticks_raw();
140 			f(TICKS_TO_MS(ts), param); /* ticks in mili-seconds */
141 		}
142 	}
143 	/* parent */
144 	return pid;
145 }
146 
fork_basic_utimer_w(int child_id,char * desc,int make_sock,utimer_function_w * f,int worker,void * param,int uinterval)147 int fork_basic_utimer_w(int child_id, char* desc, int make_sock,
148 						utimer_function_w* f, int worker, void* param, int uinterval)
149 {
150 	int pid;
151 	ticks_t ts;
152 
153 	pid=fork_process(child_id, desc, make_sock);
154 	if (pid<0) return -1;
155 	if (pid==0){
156 		/* child */
157 		if (cfg_child_init()) return -1;
158 		for(;;){
159 			sleep_us(uinterval);
160 			cfg_update();
161 			ts = get_ticks_raw();
162 			f(TICKS_TO_MS(ts), worker, param); /* ticks in mili-seconds */
163 		}
164 	}
165 	/* parent */
166 	return pid;
167 }
168 
169 
170 /**
171  * \brief Forks a timer process based on the local timer
172  *
173  * Forks a separate timer process running a local_timer.h type of timer
174  * A pointer to the local_timer handle (allocated in shared memory) is
175  * returned in lt_h. It can be used to add/delete more timers at runtime
176  * (via local_timer_add()/local_timer_del() a.s.o).
177  * If timers are added from separate processes, some form of locking must be
178  * used (all the calls to local_timer* must be enclosed by locks if it
179  * cannot be guaranteed that they cannot execute in the same time)
180  * The timer "engine" must be run manually from the child process. For
181  * example a very simple local timer process that just runs a single
182  * periodic timer can be started in the following way:
183  * struct local_timer* lt_h;
184  *
185  * pid=fork_local_timer_process(...., &lt_h);
186  * if (pid==0){
187  *          timer_init(&my_timer, my_timer_f, 0, 0);
188  *          local_timer_add(&lt_h, &my_timer, S_TO_TICKS(10), get_ticks_raw());
189  *          while(1) { sleep(1); local_timer_run(lt, get_ticks_raw()); }
190  * }
191  *
192  * @param child_id  @see fork_process()
193  * @param desc      @see fork_process()
194  * @param make_sock @see fork_process()
195  * @param lt_h      local_timer handler
196  * @return pid to the parent, 0 to the child, -1 if error.
197  */
fork_local_timer_process(int child_id,char * desc,int make_sock,struct local_timer ** lt_h)198 int fork_local_timer_process(int child_id, char* desc, int make_sock,
199 						struct local_timer** lt_h)
200 {
201 	int pid;
202 	struct local_timer* lt;
203 
204 	lt=shm_malloc(sizeof(*lt));
205 	if (lt==0) goto error;
206 	if (init_local_timer(lt, get_ticks_raw())<0) goto error;
207 	pid=fork_process(child_id, desc, make_sock);
208 	if (pid<0) goto error;
209 	*lt_h=lt;
210 	return pid;
211 error:
212 	if (lt) shm_free(lt);
213 	return -1;
214 }
215 
216 /**
217  * \brief update internal counters for running new sync sec. timers
218  * @param timers number of basic timer processes
219  * @return 0 on success; -1 on error
220  */
register_sync_timers(int timers)221 int register_sync_timers(int timers)
222 {
223 	if(register_procs(timers)<0)
224 		return -1;
225 	cfg_register_child(timers);
226 	return 0;
227 }
228 
229 /**
230  * \brief Forks a separate simple sleep() -&- sync periodic timer
231  *
232  * Forks a very basic periodic timer process, that just sleep()s for
233  * the specified interval and then calls the timer function.
234  * The new "sync timer" process execution start immediately, the sleep()
235  * is called first (so the first call to the timer function will happen
236  * \<interval\> seconds after the call to fork_sync_timer)
237  * @param child_id  @see fork_process()
238  * @param desc      @see fork_process()
239  * @param make_sock @see fork_process()
240  * @param f         timer function/callback
241  * @param param     parameter passed to the timer function
242  * @param interval  interval in seconds.
243  * @return pid of the new process on success, -1 on error
244  * (doesn't return anything in the child process)
245  */
fork_sync_timer(int child_id,char * desc,int make_sock,timer_function * f,void * param,int interval)246 int fork_sync_timer(int child_id, char* desc, int make_sock,
247 						timer_function* f, void* param, int interval)
248 {
249 	int pid;
250 	ticks_t ts1 = 0;
251 	ticks_t ts2 = 0;
252 
253 	pid=fork_process(child_id, desc, make_sock);
254 	if (pid<0) return -1;
255 	if (pid==0){
256 		/* child */
257 		interval *= 1000;  /* miliseconds */
258 		ts2 = interval;
259 		if (cfg_child_init()) return -1;
260 		for(;;){
261 			if (ts2>interval)
262 				sleep_us(1000);    /* 1 milisecond sleep to catch up */
263 			else
264 				sleep_us(ts2*1000); /* microseconds sleep */
265 			ts1 = get_ticks_raw();
266 			cfg_update();
267 			f(TICKS_TO_S(ts1), param); /* ticks in sec for compatibility with old
268 										* timers */
269 			/* adjust the next sleep duration */
270 			ts2 = interval - TICKS_TO_MS(get_ticks_raw()) + TICKS_TO_MS(ts1);
271 		}
272 	}
273 	/* parent */
274 	return pid;
275 }
276 
277 
278 /**
279  * \brief Forks a separate simple microsecond-sleep() -&- sync periodic timer
280  *
281  * Forks a very basic periodic timer process, that just us-sleep()s for
282  * the specified interval and then calls the timer function.
283  * The new "sync timer" process execution start immediately, the us-sleep()
284  * is called first (so the first call to the timer function will happen
285  * \<interval\> microseconds after the call to fork_basic_utimer)
286  * @param child_id  @see fork_process()
287  * @param desc      @see fork_process()
288  * @param make_sock @see fork_process()
289  * @param f         timer function/callback
290  * @param param     parameter passed to the timer function
291  * @param uinterval  interval in micro-seconds.
292  * @return pid of the new process on success, -1 on error
293  * (doesn't return anything in the child process)
294  */
fork_sync_utimer(int child_id,char * desc,int make_sock,utimer_function * f,void * param,int uinterval)295 int fork_sync_utimer(int child_id, char* desc, int make_sock,
296 						utimer_function* f, void* param, int uinterval)
297 {
298 	int pid;
299 	ticks_t ts1 = 0;
300 	ticks_t ts2 = 0;
301 
302 	pid=fork_process(child_id, desc, make_sock);
303 	if (pid<0) return -1;
304 	if (pid==0){
305 		/* child */
306 		ts2 = uinterval;
307 		if (cfg_child_init()) return -1;
308 		for(;;){
309 			if(ts2>uinterval)
310 				sleep_us(1);
311 			else
312 				sleep_us(ts2);
313 			ts1 = get_ticks_raw();
314 			cfg_update();
315 			f(TICKS_TO_MS(ts1), param); /* ticks in mili-seconds */
316 			ts2 = uinterval - get_ticks_raw() + ts1;
317 		}
318 	}
319 	/* parent */
320 	return pid;
321 }
322 
323 
324 /* number of slots in the wheel timer */
325 #define SR_WTIMER_SIZE	16
326 
327 typedef struct sr_wtimer_node {
328 	struct sr_wtimer_node *next;
329 	uint32_t interval;  /* frequency of execution (secs) */
330 	uint32_t steps;     /* init: interval = loops * SR_WTIMER_SIZE + steps */
331 	uint32_t loops;
332 	uint32_t eloop;
333 	timer_function* f;
334 	void* param;
335 } sr_wtimer_node_t;
336 
337 typedef struct sr_wtimer {
338 	uint32_t itimer;
339 	sr_wtimer_node_t *wlist[SR_WTIMER_SIZE];
340 } sr_wtimer_t;
341 
342 static sr_wtimer_t *_sr_wtimer = NULL;;
343 
344 /**
345  *
346  */
sr_wtimer_init(void)347 int sr_wtimer_init(void)
348 {
349 	if(_sr_wtimer!=NULL)
350 		return 0;
351 	_sr_wtimer = (sr_wtimer_t *)pkg_malloc(sizeof(sr_wtimer_t));
352 	if(_sr_wtimer==NULL) {
353 		PKG_MEM_ERROR;
354 		return -1;
355 	}
356 
357 	memset(_sr_wtimer, 0, sizeof(sr_wtimer_t));
358 	register_sync_timers(1);
359 	return 0;
360 }
361 
362 /**
363  *
364  */
sr_wtimer_add(timer_function * f,void * param,int interval)365 int sr_wtimer_add(timer_function* f, void* param, int interval)
366 {
367 	sr_wtimer_node_t *wt;
368 	if(_sr_wtimer==NULL) {
369 		LM_ERR("wtimer not initialized\n");
370 		return -1;
371 	}
372 
373 	wt = (sr_wtimer_node_t*)pkg_malloc(sizeof(sr_wtimer_node_t));
374 	if(wt==NULL) {
375 		PKG_MEM_ERROR;
376 		return -1;
377 	}
378 	memset(wt, 0, sizeof(sr_wtimer_node_t));
379 	wt->f = f;
380 	wt->param = param;
381 	wt->interval = interval;
382 	wt->steps = interval % SR_WTIMER_SIZE;
383 	wt->loops = interval / SR_WTIMER_SIZE;
384 	wt->eloop = wt->loops;
385 	wt->next = _sr_wtimer->wlist[wt->steps];
386 	_sr_wtimer->wlist[wt->steps] = wt;
387 
388 	return 0;
389 }
390 
391 /**
392  *
393  */
sr_wtimer_reinsert(uint32_t cs,sr_wtimer_node_t * wt)394 int sr_wtimer_reinsert(uint32_t cs, sr_wtimer_node_t *wt)
395 {
396 	uint32_t ts;
397 
398 	ts = (cs + wt->interval) % SR_WTIMER_SIZE;
399 	wt->eloop = wt->interval / SR_WTIMER_SIZE;
400 	wt->next = _sr_wtimer->wlist[ts];
401 	_sr_wtimer->wlist[ts] = wt;
402 
403 	return 0;
404 }
405 
406 /**
407  *
408  */
sr_wtimer_exec(unsigned int ticks,void * param)409 void sr_wtimer_exec(unsigned int ticks, void *param)
410 {
411 	sr_wtimer_node_t *wt;
412 	sr_wtimer_node_t *wn;
413 	sr_wtimer_node_t *wp;
414 	uint32_t cs;
415 
416 	if(_sr_wtimer==NULL) {
417 		LM_ERR("wtimer not initialized\n");
418 		return;
419 	}
420 
421 	_sr_wtimer->itimer++;
422 	cs = _sr_wtimer->itimer % SR_WTIMER_SIZE;
423 	/* uint32_t cl;
424 	cl = _sr_wtimer->itimer / SR_WTIMER_SIZE;
425 	LM_DBG("wtimer - loop: %u - slot: %u\n", cl, cs); */
426 
427 	wp = NULL;
428 	wt=_sr_wtimer->wlist[cs];
429 	while(wt) {
430 		wn = wt->next;
431 		if(wt->eloop==0) {
432 			/* execute timer callback function */
433 			wt->f(ticks, wt->param);
434 			/* extract and reinsert timer item */
435 			if(wp==NULL) {
436 				_sr_wtimer->wlist[cs] = wn;
437 			} else {
438 				wp->next = wn;
439 			}
440 			sr_wtimer_reinsert(cs, wt);
441 		} else {
442 			wt->eloop--;
443 			wp = wt;
444 		}
445 		wt = wn;
446 	}
447 }
448 
449 /**
450  *
451  */
sr_wtimer_start(void)452 int sr_wtimer_start(void)
453 {
454 	if(_sr_wtimer==NULL) {
455 		LM_ERR("wtimer not initialized\n");
456 		return -1;
457 	}
458 
459 	if(fork_sync_timer(-1 /*PROC_TIMER*/, "secondary timer", 1,
460 				sr_wtimer_exec, NULL, 1)<0) {
461 		LM_ERR("wtimer starting failed\n");
462 		return -1;
463 	}
464 
465 	return 0;
466 }
467 
468 /* vi: set ts=4 sw=4 tw=79:ai:cindent: */
469