Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

local_timer.c

Go to the documentation of this file.
00001 /*
00002  * $Id: local_timer.c,v 1.1 2007/11/22 13:43:09 andrei Exp $
00003  *
00004  * Copyright (C) 2007 iptelorg GmbH
00005  *
00006  * This file is part of ser, a free SIP server.
00007  *
00008  * ser is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * For a license to use the ser software under conditions
00014  * other than those described here, or to purchase support for this
00015  * software, please contact iptel.org by e-mail at the following addresses:
00016  *    info@iptel.org
00017  *
00018  * ser is distributed in the hope that it will be useful,
00019  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00021  * GNU General Public License for more details.
00022  *
00023  * You should have received a copy of the GNU General Public License 
00024  * along with this program; if not, write to the Free Software 
00025  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00026  */
00027 /* local, per process timer routines
00028  * WARNING: this should be used only within the same process, the timers
00029  *  are not multi-process safe or multi-thread safe
00030  *  (there are no locks)
00031  *
00032  * History:
00033  * --------
00034  *  2006-02-03  created by andrei
00035  */
00036 
00037 
00038 #include "timer.h"
00039 #include "timer_funcs.h"
00040 #include "dprint.h"
00041 #include "tcp_conn.h"
00042 #include "mem/mem.h"
00043 #include "compiler_opt.h"
00044 
00045 #include "local_timer.h"
00046 
00047 
00048 
00049 /* init a local_timer handle
00050  * returns 0 on success, -1 on error */
00051 int init_local_timer(struct local_timer *t, ticks_t crt_ticks)
00052 {
00053         int r;
00054         
00055         /* initial values */
00056         memset(t, 0, sizeof(*t));
00057         t->prev_ticks=crt_ticks;
00058         /* init timer structures */
00059         for (r=0; r<H0_ENTRIES; r++)
00060                 _timer_init_list(&t->timer_lst.h0[r]);
00061         for (r=0; r<H1_ENTRIES; r++)
00062                 _timer_init_list(&t->timer_lst.h1[r]);
00063         for (r=0; r<H2_ENTRIES; r++)
00064                 _timer_init_list(&t->timer_lst.h2[r]);
00065         _timer_init_list(&t->timer_lst.expired);
00066         DBG("init_local_timer: timer_list between %p and %p\n",
00067                         &t->timer_lst.h0[0], &t->timer_lst.h2[H2_ENTRIES]);
00068         return 0;
00069 }
00070 
00071 
00072 
00073 void destroy_local_timer(struct local_timer* lt)
00074 {
00075 }
00076 
00077 
00078 
00079 /* generic add timer entry to the timer lists function (see _timer_add)
00080  * tl->expire must be set previously, delta is the difference in ticks
00081  * from current time to the timer desired expire (should be tl->expire-*tick)
00082  * If you don't know delta, you probably want to call _timer_add instead.
00083  */
00084 static inline int _local_timer_dist_tl(struct local_timer* h, 
00085                                                                                 struct timer_ln* tl, ticks_t delta)
00086 {
00087         if (likely(delta<H0_ENTRIES)){
00088                 if (unlikely(delta==0)){
00089                         LOG(L_WARN, "WARNING: local_timer: add_timeout: 0 expire timer"
00090                                                 " added\n");
00091                         _timer_add_list(&h->timer_lst.expired, tl);
00092                 }else{
00093                         _timer_add_list( &h->timer_lst.h0[tl->expire & H0_MASK], tl);
00094                 }
00095         }else if (likely(delta<(H0_ENTRIES*H1_ENTRIES))){
00096                 _timer_add_list(&h->timer_lst.h1[(tl->expire & H1_H0_MASK)>>H0_BITS],
00097                                                         tl);
00098         }else{
00099                 _timer_add_list(&h->timer_lst.h2[tl->expire>>(H1_BITS+H0_BITS)], tl);
00100         }
00101         return 0;
00102 }
00103 
00104 
00105 
00106 static inline void local_timer_redist(struct local_timer* l,
00107                                                                                 ticks_t t, struct timer_head *h)
00108 {
00109         struct timer_ln* tl;
00110         struct timer_ln* tmp;
00111         
00112         timer_foreach_safe(tl, tmp, h){
00113                 _local_timer_dist_tl(l, tl, tl->expire-t);
00114         }
00115         /* clear the current list */
00116         _timer_init_list(h);
00117 }
00118 
00119 
00120 
00121 /* local timer add function (no lock, not multithread or multiprocess safe,
00122  * designed for local process use only)
00123  * t = current ticks
00124  * tl must be filled (the intial_timeout and flags must be set)
00125  * returns -1 on error, 0 on success */
00126 static inline int _local_timer_add(struct local_timer *h, ticks_t t,
00127                                                                         struct timer_ln* tl)
00128 {
00129         ticks_t delta;
00130         
00131         delta=tl->initial_timeout;
00132         tl->expire=t+delta;
00133         return _local_timer_dist_tl(h, tl, delta);
00134 }
00135 
00136 
00137 
00138 /* "public", safe timer add functions (local process use only)
00139  * adds a timer at delta ticks from the current time
00140  * returns -1 on error, 0 on success
00141  * WARNING: to re-add a deleted or expired timer you must call
00142  *          timer_reinit(tl) prior to timer_add
00143  *          The default behaviour allows timer_add to add a timer only if it
00144  *          has never been added before.*/
00145 int local_timer_add(struct local_timer* h, struct timer_ln* tl, ticks_t delta,
00146                                                 ticks_t crt_ticks)
00147 {
00148         int ret;
00149         
00150         if (unlikely(tl->flags & F_TIMER_ACTIVE)){
00151                 DBG("timer_add called on an active timer %p (%p, %p),"
00152                                         " flags %x\n", tl, tl->next, tl->prev, tl->flags);
00153                 ret=-1; /* refusing to add active or non-reinit. timer */
00154                 goto error;
00155         }
00156         tl->initial_timeout=delta;
00157         if (unlikely((tl->next!=0) || (tl->prev!=0))){
00158                 LOG(L_CRIT, "BUG: tcp_timer_add: called with linked timer:"
00159                                 " %p (%p, %p)\n", tl, tl->next, tl->prev);
00160                 ret=-1;
00161                 goto error;
00162         }
00163         tl->flags|=F_TIMER_ACTIVE;
00164         ret=_local_timer_add(h, crt_ticks, tl);
00165 error:
00166         return ret;
00167 }
00168 
00169 
00170 
00171 /* safe timer delete
00172  * deletes tl and inits the list pointer to 0
00173  * WARNING: to be able to reuse a deleted timer you must call
00174  *          timer_reinit(tl) on it
00175  * 
00176  */
00177 void local_timer_del(struct local_timer* h, struct timer_ln* tl)
00178 {
00179         /* quick exit if timer inactive */
00180         if (unlikely(!(tl->flags & F_TIMER_ACTIVE))){
00181                 DBG("timer_del called on an inactive timer %p (%p, %p),"
00182                                         " flags %x\n", tl, tl->next, tl->prev, tl->flags);
00183                 return;
00184         }
00185         if (likely((tl->next!=0)&&(tl->prev!=0))){
00186                 _timer_rm_list(tl); /* detach */
00187                 tl->next=tl->prev=0;
00188         }else{
00189                 DBG("timer_del: (f) timer %p (%p, %p) flags %x "
00190                         "already detached\n",
00191                         tl, tl->next, tl->prev, tl->flags);
00192         }
00193 }
00194 
00195 
00196 
00197 /* called from timer_handle*/
00198 inline static void local_timer_list_expire(struct local_timer* l, 
00199                                                                                         ticks_t t, struct timer_head* h)
00200 {
00201         struct timer_ln * tl;
00202         ticks_t ret;
00203         
00204         /*DBG("timer_list_expire @ ticks = %lu, list =%p\n",
00205                         (unsigned long) *ticks, h);
00206         */
00207         while(h->next!=(struct timer_ln*)h){
00208                 tl=h->next;
00209                 _timer_rm_list(tl); /* detach */
00210                         tl->next=tl->prev=0; /* debugging */
00211                                 /*FIXME: process tcpconn */
00212                                 ret=tl->f(t, tl, tl->data);
00213                                 if (ret!=0){
00214                                         /* not one-shot, re-add it */
00215                                         if (ret!=(ticks_t)-1) /* ! periodic */
00216                                                 tl->initial_timeout=ret;
00217                                         _local_timer_add(l, t, tl);
00218                                 }
00219         }
00220 }
00221 
00222 
00223 
00224 /* run all the handler that expire at t ticks */
00225 static inline void local_timer_expire(struct local_timer* h, ticks_t t)
00226 {
00227         /* trust the compiler for optimizing */
00228         if (unlikely((t & H0_MASK)==0)){              /*r1*/
00229                 if (unlikely((t & H1_H0_MASK)==0)){        /*r2*/
00230                         local_timer_redist(h, t, &h->timer_lst.h2[t>>(H0_BITS+H1_BITS)]);
00231                 }
00232                 
00233                 local_timer_redist(h, t, &h->timer_lst.h1[(t & H1_H0_MASK)>>H0_BITS]);
00234                                                                                                                         /*r2 >> H0*/
00235         }
00236         /* run handler immediately, no need to move it to the expired list
00237          * (since no locks are used) */
00238         local_timer_list_expire(h, t, &h->timer_lst.h0[t & H0_MASK]);
00239 }
00240 
00241 
00242 
00243 /* "main" local timer routine, should be called with a proper ticks value
00244  * WARNING: it should never be called twice for the same ticks value
00245  * (it could cause too fast expires for long timers), ticks must be also
00246  *  always increasing */
00247 void local_timer_run(struct local_timer* lt, ticks_t saved_ticks)
00248 {
00249         
00250                 /* protect against time running backwards */
00251                 if (unlikely(lt->prev_ticks>=saved_ticks)){
00252                         LOG(L_CRIT, "BUG: local_timer: backwards or still time\n");
00253                         /* try to continue */
00254                         lt->prev_ticks=saved_ticks-1;
00255                         return;
00256                 }
00257                 /* go through all the "missed" ticks, taking a possible overflow
00258                  * into account */
00259                 for (lt->prev_ticks=lt->prev_ticks+1; lt->prev_ticks!=saved_ticks; 
00260                                                                                                                         lt->prev_ticks++)
00261                         local_timer_expire(lt, lt->prev_ticks);
00262                 local_timer_expire(lt, lt->prev_ticks); /* do it for saved_ticks too */
00263         local_timer_list_expire(lt, saved_ticks, &lt->timer_lst.expired);
00264         /* WARNING: add_timer(...,0) must go directly to expired list, since
00265          * otherwise there is a race between timer running and adding it
00266          * (it could expire it H0_ENTRIES ticks later instead of 'now')*/
00267 }
00268 

Generated on Thu Sep 9 04:15:44 2010 for SIPExpressRouter by  doxygen 1.3.9.1