123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- /*
- * $Id$
- *
- * Copyright (C) 2007 iptelorg GmbH
- *
- * This file is part of ser, a free SIP server.
- *
- * ser is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * For a license to use the ser software under conditions
- * other than those described here, or to purchase support for this
- * software, please contact iptel.org by e-mail at the following addresses:
- * [email protected]
- *
- * ser is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
- /* local, per process timer routines
- * WARNING: this should be used only within the same process, the timers
- * are not multi-process safe or multi-thread safe
- * (there are no locks)
- *
- * History:
- * --------
- * 2006-02-03 created by andrei
- */
- /*!
- * \file
- * \brief SIP-router core ::
- * \ingroup core
- * Module: \ref core
- */
- #include "timer.h"
- #include "timer_funcs.h"
- #include "dprint.h"
- #include "tcp_conn.h"
- #include "mem/mem.h"
- #include "compiler_opt.h"
- #include "local_timer.h"
- /* init a local_timer handle
- * returns 0 on success, -1 on error */
- int init_local_timer(struct local_timer *t, ticks_t crt_ticks)
- {
- int r;
-
- /* initial values */
- memset(t, 0, sizeof(*t));
- t->prev_ticks=crt_ticks;
- /* init timer structures */
- for (r=0; r<H0_ENTRIES; r++)
- _timer_init_list(&t->timer_lst.h0[r]);
- for (r=0; r<H1_ENTRIES; r++)
- _timer_init_list(&t->timer_lst.h1[r]);
- for (r=0; r<H2_ENTRIES; r++)
- _timer_init_list(&t->timer_lst.h2[r]);
- _timer_init_list(&t->timer_lst.expired);
- DBG("init_local_timer: timer_list between %p and %p\n",
- &t->timer_lst.h0[0], &t->timer_lst.h2[H2_ENTRIES]);
- return 0;
- }
- void destroy_local_timer(struct local_timer* lt)
- {
- }
- /* generic add timer entry to the timer lists function (see _timer_add)
- * tl->expire must be set previously, delta is the difference in ticks
- * from current time to the timer desired expire (should be tl->expire-*tick)
- * If you don't know delta, you probably want to call _timer_add instead.
- */
- static inline int _local_timer_dist_tl(struct local_timer* h,
- struct timer_ln* tl, ticks_t delta)
- {
- if (likely(delta<H0_ENTRIES)){
- if (unlikely(delta==0)){
- LM_WARN("0 expire timer added\n");
- _timer_add_list(&h->timer_lst.expired, tl);
- }else{
- _timer_add_list( &h->timer_lst.h0[tl->expire & H0_MASK], tl);
- }
- }else if (likely(delta<(H0_ENTRIES*H1_ENTRIES))){
- _timer_add_list(&h->timer_lst.h1[(tl->expire & H1_H0_MASK)>>H0_BITS],
- tl);
- }else{
- _timer_add_list(&h->timer_lst.h2[tl->expire>>(H1_BITS+H0_BITS)], tl);
- }
- return 0;
- }
- static inline void local_timer_redist(struct local_timer* l,
- ticks_t t, struct timer_head *h)
- {
- struct timer_ln* tl;
- struct timer_ln* tmp;
-
- timer_foreach_safe(tl, tmp, h){
- _local_timer_dist_tl(l, tl, tl->expire-t);
- }
- /* clear the current list */
- _timer_init_list(h);
- }
- /* local timer add function (no lock, not multithread or multiprocess safe,
- * designed for local process use only)
- * t = current ticks
- * tl must be filled (the intial_timeout and flags must be set)
- * returns -1 on error, 0 on success */
- static inline int _local_timer_add(struct local_timer *h, ticks_t t,
- struct timer_ln* tl)
- {
- ticks_t delta;
-
- delta=tl->initial_timeout;
- tl->expire=t+delta;
- return _local_timer_dist_tl(h, tl, delta);
- }
- /* "public", safe timer add functions (local process use only)
- * adds a timer at delta ticks from the current time
- * returns -1 on error, 0 on success
- * WARNING: to re-add a deleted or expired timer you must call
- * timer_reinit(tl) prior to timer_add
- * The default behaviour allows timer_add to add a timer only if it
- * has never been added before.*/
- int local_timer_add(struct local_timer* h, struct timer_ln* tl, ticks_t delta,
- ticks_t crt_ticks)
- {
- int ret;
-
- if (unlikely(tl->flags & F_TIMER_ACTIVE)){
- DBG("timer_add called on an active timer %p (%p, %p),"
- " flags %x\n", tl, tl->next, tl->prev, tl->flags);
- ret=-1; /* refusing to add active or non-reinit. timer */
- goto error;
- }
- tl->initial_timeout=delta;
- if (unlikely((tl->next!=0) || (tl->prev!=0))){
- LM_CRIT("called with linked timer: %p (%p, %p)\n", tl, tl->next, tl->prev);
- ret=-1;
- goto error;
- }
- tl->flags|=F_TIMER_ACTIVE;
- ret=_local_timer_add(h, crt_ticks, tl);
- error:
- return ret;
- }
- /* safe timer delete
- * deletes tl and inits the list pointer to 0
- * WARNING: to be able to reuse a deleted timer you must call
- * timer_reinit(tl) on it
- *
- */
- void local_timer_del(struct local_timer* h, struct timer_ln* tl)
- {
- /* quick exit if timer inactive */
- if (unlikely(!(tl->flags & F_TIMER_ACTIVE))){
- DBG("timer_del called on an inactive timer %p (%p, %p),"
- " flags %x\n", tl, tl->next, tl->prev, tl->flags);
- return;
- }
- if (likely((tl->next!=0)&&(tl->prev!=0))){
- _timer_rm_list(tl); /* detach */
- tl->next=tl->prev=0;
- }else{
- DBG("timer_del: (f) timer %p (%p, %p) flags %x "
- "already detached\n",
- tl, tl->next, tl->prev, tl->flags);
- }
- }
- /* called from timer_handle*/
- inline static void local_timer_list_expire(struct local_timer* l,
- ticks_t t, struct timer_head* h)
- {
- struct timer_ln * tl;
- ticks_t ret;
-
- /*DBG("timer_list_expire @ ticks = %lu, list =%p\n",
- (unsigned long) *ticks, h);
- */
- while(h->next!=(struct timer_ln*)h){
- tl=h->next;
- _timer_rm_list(tl); /* detach */
- tl->next=tl->prev=0; /* debugging */
- /*FIXME: process tcpconn */
- ret=tl->f(t, tl, tl->data);
- if (ret!=0){
- /* not one-shot, re-add it */
- if (ret!=(ticks_t)-1) /* ! periodic */
- tl->initial_timeout=ret;
- _local_timer_add(l, t, tl);
- }
- }
- }
- /* run all the handler that expire at t ticks */
- static inline void local_timer_expire(struct local_timer* h, ticks_t t)
- {
- /* trust the compiler for optimizing */
- if (unlikely((t & H0_MASK)==0)){ /*r1*/
- if (unlikely((t & H1_H0_MASK)==0)){ /*r2*/
- local_timer_redist(h, t, &h->timer_lst.h2[t>>(H0_BITS+H1_BITS)]);
- }
-
- local_timer_redist(h, t, &h->timer_lst.h1[(t & H1_H0_MASK)>>H0_BITS]);
- /*r2 >> H0*/
- }
- /* run handler immediately, no need to move it to the expired list
- * (since no locks are used) */
- local_timer_list_expire(h, t, &h->timer_lst.h0[t & H0_MASK]);
- }
- /* "main" local timer routine, should be called with a proper ticks value
- * WARNING: it should never be called twice for the same ticks value
- * (it could cause too fast expires for long timers), ticks must be also
- * always increasing */
- void local_timer_run(struct local_timer* lt, ticks_t saved_ticks)
- {
-
- /* protect against time running backwards */
- if (unlikely(lt->prev_ticks>=saved_ticks)){
- LM_CRIT("backwards or still time\n");
- /* try to continue */
- lt->prev_ticks=saved_ticks-1;
- return;
- }
- /* go through all the "missed" ticks, taking a possible overflow
- * into account */
- for (lt->prev_ticks=lt->prev_ticks+1; lt->prev_ticks!=saved_ticks;
- lt->prev_ticks++)
- local_timer_expire(lt, lt->prev_ticks);
- local_timer_expire(lt, lt->prev_ticks); /* do it for saved_ticks too */
- local_timer_list_expire(lt, saved_ticks, <->timer_lst.expired);
- /* WARNING: add_timer(...,0) must go directly to expired list, since
- * otherwise there is a race between timer running and adding it
- * (it could expire it H0_ENTRIES ticks later instead of 'now')*/
- }
|