dlg_timer.c

Go to the documentation of this file.
00001 /*
00002  * $Id: dlg_timer.c 5785 2009-04-02 18:24:17Z henningw $
00003  *
00004  * Copyright (C) 2006 Voice System SRL
00005  *
00006  * This file is part of Kamailio, a free SIP server.
00007  *
00008  * Kamailio 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  * Kamailio is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License 
00019  * along with this program; if not, write to the Free Software 
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  * History:
00023  * --------
00024  * 2006-04-14  initial version (bogdan)
00025  * 2007-03-06  to avoid races, tests on timer links are done under locks
00026  *             (bogdan)
00027  */
00028 
00029 /*!
00030  * \file
00031  * \brief Timer related functions for the dialog module
00032  * \ingroup dialog
00033  * Module: \ref dialog
00034  */
00035 
00036 #include "../../mem/shm_mem.h"
00037 #include "../../timer.h"
00038 #include "dlg_timer.h"
00039 
00040 /*! global dialog timer */
00041 struct dlg_timer *d_timer = 0;
00042 /*! global dialog timer handler */
00043 dlg_timer_handler timer_hdl = 0;
00044 
00045 
00046 /*!
00047  * \brief Initialize the dialog timer handler
00048  * Initialize the dialog timer handler, allocate the lock and a global
00049  * timer in shared memory. The global timer handler will be set on success.
00050  * \param hdl dialog timer handler
00051  * \return 0 on success, -1 on failure
00052  */
00053 int init_dlg_timer(dlg_timer_handler hdl)
00054 {
00055    d_timer = (struct dlg_timer*)shm_malloc(sizeof(struct dlg_timer));
00056    if (d_timer==0) {
00057       LM_ERR("no more shm mem\n");
00058       return -1;
00059    }
00060    memset( d_timer, 0, sizeof(struct dlg_timer) );
00061 
00062    d_timer->first.next = d_timer->first.prev = &(d_timer->first);
00063 
00064    d_timer->lock = lock_alloc();
00065    if (d_timer->lock==0) {
00066       LM_ERR("failed to alloc lock\n");
00067       goto error0;
00068    }
00069 
00070    if (lock_init(d_timer->lock)==0) {
00071       LM_ERR("failed to init lock\n");
00072       goto error1;
00073    }
00074 
00075    timer_hdl = hdl;
00076    return 0;
00077 error1:
00078    lock_dealloc(d_timer->lock);
00079 error0:
00080    shm_free(d_timer);
00081    d_timer = 0;
00082    return -1;
00083 }
00084 
00085 
00086 /*!
00087  * \brief Destroy global dialog timer
00088  */
00089 void destroy_dlg_timer(void)
00090 {
00091    if (d_timer==0)
00092       return;
00093 
00094    lock_destroy(d_timer->lock);
00095    lock_dealloc(d_timer->lock);
00096 
00097    shm_free(d_timer);
00098    d_timer = 0;
00099 }
00100 
00101 
00102 /*!
00103  * \brief Helper function for insert_dialog_timer
00104  * \see insert_dialog_timer
00105  * \param tl dialog timer list
00106  */
00107 static inline void insert_dialog_timer_unsafe(struct dlg_tl *tl)
00108 {
00109    struct dlg_tl* ptr;
00110 
00111    /* insert in sorted order */
00112    for(ptr = d_timer->first.prev; ptr != &d_timer->first ; ptr = ptr->prev) {
00113       if ( ptr->timeout <= tl->timeout )
00114          break;
00115    }
00116 
00117    LM_DBG("inserting %p for %d\n", tl,tl->timeout);
00118    tl->prev = ptr;
00119    tl->next = ptr->next;
00120    tl->prev->next = tl;
00121    tl->next->prev = tl;
00122 }
00123 
00124 
00125 /*!
00126  * \brief Insert a dialog timer to the list
00127  * \param tl dialog timer list
00128  * \param interval timeout value in seconds
00129  * \return 0 on success, -1 when the input timer list is invalid
00130  */
00131 int insert_dlg_timer(struct dlg_tl *tl, int interval)
00132 {
00133    lock_get( d_timer->lock);
00134 
00135    if (tl->next!=0 || tl->prev!=0) {
00136       lock_release( d_timer->lock);
00137       LM_CRIT("Trying to insert a bogus dlg tl=%p tl->next=%p tl->prev=%p\n",
00138          tl, tl->next, tl->prev);
00139       return -1;
00140    }
00141    tl->timeout = get_ticks()+interval;
00142    insert_dialog_timer_unsafe( tl );
00143 
00144    lock_release( d_timer->lock);
00145 
00146    return 0;
00147 }
00148 
00149 
00150 /*!
00151  * \brief Helper function for remove_dialog_timer
00152  * \param tl dialog timer list
00153  * \see remove_dialog_timer
00154  */
00155 static inline void remove_dialog_timer_unsafe(struct dlg_tl *tl)
00156 {
00157    tl->prev->next = tl->next;
00158    tl->next->prev = tl->prev;
00159 }
00160 
00161 
00162 /*!
00163  * \brief Remove a dialog timer from the list
00164  * \param tl dialog timer that should be removed
00165  * \return 1 when the input timer is empty, 0 when the timer was removed,
00166  * -1 when the input timer list is invalid
00167  */
00168 int remove_dialog_timer(struct dlg_tl *tl)
00169 {
00170    lock_get( d_timer->lock);
00171 
00172    if (tl->prev==NULL && tl->timeout==0) {
00173       lock_release( d_timer->lock);
00174       return 1;
00175    }
00176 
00177    if (tl->prev==NULL || tl->next==NULL) {
00178       LM_CRIT("bogus tl=%p tl->prev=%p tl->next=%p\n",
00179          tl, tl->prev, tl->next);
00180       lock_release( d_timer->lock);
00181       return -1;
00182    }
00183 
00184    remove_dialog_timer_unsafe(tl);
00185    tl->next = NULL;
00186    tl->prev = NULL;
00187    tl->timeout = 0;
00188 
00189    lock_release( d_timer->lock);
00190    return 0;
00191 }
00192 
00193 
00194 /*!
00195  * \brief Update a dialog timer on the list
00196  * \param tl dialog timer
00197  * \param timeout new timeout value in seconds
00198  * \return 0 on success, -1 when the input list is invalid
00199  * \note the update is implemented as a remove, insert
00200  */
00201 int update_dlg_timer(struct dlg_tl *tl, int timeout)
00202 {
00203    lock_get( d_timer->lock);
00204 
00205    if ( tl->next ) {
00206       if (tl->prev==0) {
00207          lock_release( d_timer->lock);
00208          return -1;
00209       }
00210       remove_dialog_timer_unsafe(tl);
00211    }
00212 
00213    tl->timeout = get_ticks()+timeout;
00214    insert_dialog_timer_unsafe( tl );
00215 
00216    lock_release( d_timer->lock);
00217    return 0;
00218 }
00219 
00220 
00221 /*!
00222  * \brief Helper function for dlg_timer_routine
00223  * \param time time for expiration check
00224  * \return list of expired dialogs on success, 0 on failure
00225  */
00226 static inline struct dlg_tl* get_expired_dlgs(unsigned int time)
00227 {
00228    struct dlg_tl *tl , *end, *ret;
00229 
00230    lock_get( d_timer->lock);
00231 
00232    if (d_timer->first.next==&(d_timer->first)
00233    || d_timer->first.next->timeout > time ) {
00234       lock_release( d_timer->lock);
00235       return 0;
00236    }
00237 
00238    end = &d_timer->first;
00239    tl = d_timer->first.next;
00240    LM_WARN("start with tl=%p tl->prev=%p tl->next=%p (%d) at %d "
00241       "and end with end=%p end->prev=%p end->next=%p\n",
00242       tl,tl->prev,tl->next,tl->timeout,time,
00243       end,end->prev,end->next);
00244    while( tl!=end && tl->timeout <= time) {
00245       LM_WARN("getting tl=%p tl->prev=%p tl->next=%p with %d\n",
00246          tl,tl->prev,tl->next,tl->timeout);
00247       tl->prev = 0;
00248       tl->timeout = 0;
00249       tl=tl->next;
00250    }
00251    LM_WARN("end with tl=%p tl->prev=%p tl->next=%p and d_timer->first.next->prev=%p\n",
00252       tl,tl->prev,tl->next,d_timer->first.next->prev);
00253 
00254    if (tl==end && d_timer->first.next->prev) {
00255       ret = 0;
00256    } else {
00257       ret = d_timer->first.next;
00258       tl->prev->next = 0;
00259       d_timer->first.next = tl;
00260       tl->prev = &d_timer->first;
00261    }
00262 
00263    lock_release( d_timer->lock);
00264 
00265    return ret;
00266 }
00267 
00268 
00269 /*!
00270  * \brief Timer routine for expiration of dialogs
00271  * Timer handler for expiration of dialogs, runs the global timer handler on them.
00272  * \param time for expiration checks
00273  * \param attr unused
00274  */
00275 void dlg_timer_routine(unsigned int ticks , void * attr)
00276 {
00277    struct dlg_tl *tl, *ctl;
00278 
00279    tl = get_expired_dlgs( ticks );
00280 
00281    while (tl) {
00282       ctl = tl;
00283       tl = tl->next;
00284       ctl->next = NULL;
00285       LM_DBG("tl=%p next=%p\n", ctl, tl);
00286       timer_hdl( ctl );
00287    }
00288 }

Generated on Tue May 22 16:00:27 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6