dlg_timer.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006 Voice System SRL
00003  *
00004  * This file is part of Kamailio, a free SIP server.
00005  *
00006  * Kamailio is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version
00010  *
00011  * Kamailio is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License 
00017  * along with this program; if not, write to the Free Software 
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  *
00020  * History:
00021  * --------
00022  * 2006-04-14  initial version (bogdan)
00023  * 2007-03-06  to avoid races, tests on timer links are done under locks
00024  *             (bogdan)
00025  */
00026 
00034 #include "../../mem/shm_mem.h"
00035 #include "../../timer.h"
00036 #include "dlg_timer.h"
00037 
00039 struct dlg_timer *d_timer = 0;
00041 dlg_timer_handler timer_hdl = 0;
00042 
00043 
00051 int init_dlg_timer(dlg_timer_handler hdl)
00052 {
00053         d_timer = (struct dlg_timer*)shm_malloc(sizeof(struct dlg_timer));
00054         if (d_timer==0) {
00055                 LM_ERR("no more shm mem\n");
00056                 return -1;
00057         }
00058         memset( d_timer, 0, sizeof(struct dlg_timer) );
00059 
00060         d_timer->first.next = d_timer->first.prev = &(d_timer->first);
00061 
00062         d_timer->lock = lock_alloc();
00063         if (d_timer->lock==0) {
00064                 LM_ERR("failed to alloc lock\n");
00065                 goto error0;
00066         }
00067 
00068         if (lock_init(d_timer->lock)==0) {
00069                 LM_ERR("failed to init lock\n");
00070                 goto error1;
00071         }
00072 
00073         timer_hdl = hdl;
00074         return 0;
00075 error1:
00076         lock_dealloc(d_timer->lock);
00077 error0:
00078         shm_free(d_timer);
00079         d_timer = 0;
00080         return -1;
00081 }
00082 
00083 
00087 void destroy_dlg_timer(void)
00088 {
00089         if (d_timer==0)
00090                 return;
00091 
00092         lock_destroy(d_timer->lock);
00093         lock_dealloc(d_timer->lock);
00094 
00095         shm_free(d_timer);
00096         d_timer = 0;
00097 }
00098 
00099 
00105 static inline void insert_dialog_timer_unsafe(struct dlg_tl *tl)
00106 {
00107         struct dlg_tl* ptr;
00108 
00109         /* insert in sorted order */
00110         for(ptr = d_timer->first.prev; ptr != &d_timer->first ; ptr = ptr->prev) {
00111                 if ( ptr->timeout <= tl->timeout )
00112                         break;
00113         }
00114 
00115         LM_DBG("inserting %p for %d\n", tl,tl->timeout);
00116         tl->prev = ptr;
00117         tl->next = ptr->next;
00118         tl->prev->next = tl;
00119         tl->next->prev = tl;
00120 }
00121 
00122 
00129 int insert_dlg_timer(struct dlg_tl *tl, int interval)
00130 {
00131         lock_get( d_timer->lock);
00132 
00133         if (tl->next!=0 || tl->prev!=0) {
00134                 LM_CRIT("Trying to insert a bogus dlg tl=%p tl->next=%p tl->prev=%p\n",
00135                         tl, tl->next, tl->prev);
00136                 lock_release( d_timer->lock);
00137                 return -1;
00138         }
00139         tl->timeout = get_ticks()+interval;
00140         insert_dialog_timer_unsafe( tl );
00141 
00142         lock_release( d_timer->lock);
00143 
00144         return 0;
00145 }
00146 
00147 
00153 static inline void remove_dialog_timer_unsafe(struct dlg_tl *tl)
00154 {
00155         tl->prev->next = tl->next;
00156         tl->next->prev = tl->prev;
00157 }
00158 
00159 
00166 int remove_dialog_timer(struct dlg_tl *tl)
00167 {
00168         lock_get( d_timer->lock);
00169 
00170         if (tl->prev==NULL && tl->timeout==0) {
00171                 lock_release( d_timer->lock);
00172                 return 1;
00173         }
00174 
00175         if (tl->prev==NULL || tl->next==NULL) {
00176                 LM_CRIT("bogus tl=%p tl->prev=%p tl->next=%p\n",
00177                         tl, tl->prev, tl->next);
00178                 lock_release( d_timer->lock);
00179                 return -1;
00180         }
00181 
00182         remove_dialog_timer_unsafe(tl);
00183         tl->next = NULL;
00184         tl->prev = NULL;
00185         tl->timeout = 0;
00186 
00187         lock_release( d_timer->lock);
00188         return 0;
00189 }
00190 
00191 
00199 int update_dlg_timer(struct dlg_tl *tl, int timeout)
00200 {
00201         lock_get( d_timer->lock);
00202 
00203         if (tl->next==0 || tl->prev==0) {
00204                 LM_CRIT("Trying to update a bogus dlg tl=%p tl->next=%p tl->prev=%p\n",
00205                         tl, tl->next, tl->prev);
00206                 lock_release( d_timer->lock);
00207                 return -1;
00208         }
00209         remove_dialog_timer_unsafe( tl );
00210         tl->timeout = get_ticks()+timeout;
00211         insert_dialog_timer_unsafe( tl );
00212 
00213         lock_release( d_timer->lock);
00214         return 0;
00215 }
00216 
00217 
00223 static inline struct dlg_tl* get_expired_dlgs(unsigned int time)
00224 {
00225         struct dlg_tl *tl , *end, *ret;
00226 
00227         lock_get( d_timer->lock);
00228 
00229         if (d_timer->first.next==&(d_timer->first)
00230         || d_timer->first.next->timeout > time ) {
00231                 lock_release( d_timer->lock);
00232                 return 0;
00233         }
00234 
00235         end = &d_timer->first;
00236         tl = d_timer->first.next;
00237         LM_DBG("start with tl=%p tl->prev=%p tl->next=%p (%d) at %d "
00238                 "and end with end=%p end->prev=%p end->next=%p\n",
00239                 tl,tl->prev,tl->next,tl->timeout,time,
00240                 end,end->prev,end->next);
00241         while( tl!=end && tl->timeout <= time) {
00242                 LM_DBG("getting tl=%p tl->prev=%p tl->next=%p with %d\n",
00243                         tl,tl->prev,tl->next,tl->timeout);
00244                 tl->prev = 0;
00245                 tl->timeout = 0;
00246                 tl=tl->next;
00247         }
00248         LM_DBG("end with tl=%p tl->prev=%p tl->next=%p and d_timer->first.next->prev=%p\n",
00249                 tl,tl->prev,tl->next,d_timer->first.next->prev);
00250 
00251         if (tl==end && d_timer->first.next->prev) {
00252                 ret = 0;
00253         } else {
00254                 ret = d_timer->first.next;
00255                 tl->prev->next = 0;
00256                 d_timer->first.next = tl;
00257                 tl->prev = &d_timer->first;
00258         }
00259 
00260         lock_release( d_timer->lock);
00261 
00262         return ret;
00263 }
00264 
00265 
00272 void dlg_timer_routine(unsigned int ticks , void * attr)
00273 {
00274         struct dlg_tl *tl, *ctl;
00275 
00276         tl = get_expired_dlgs( ticks );
00277 
00278         while (tl) {
00279                 ctl = tl;
00280                 tl = tl->next;
00281                 ctl->next = NULL;
00282                 LM_DBG("tl=%p next=%p\n", ctl, tl);
00283                 timer_hdl( ctl );
00284         }
00285 }