/*
* $Id: dlg_timer.c 1808 2007-03-10 17:36:19Z bogdan_iancu $
*
* Copyright (C) 2006 Voice System SRL
*
* This file is part of openser, a free SIP server.
*
* openser 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
*
* openser 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* History:
* --------
* 2006-04-14 initial version (bogdan)
* 2007-03-06 to avoid races, tests on timer links are done under locks
* (bogdan)
*/
#include "../../mem/shm_mem.h"
#include "../../timer.h"
#include "dlg_timer.h"
struct dlg_timer *d_timer = 0;
dlg_timer_handler timer_hdl = 0;
int init_dlg_timer( dlg_timer_handler hdl )
{
d_timer = (struct dlg_timer*)shm_malloc(sizeof(struct dlg_timer));
if (d_timer==0) {
LOG(L_ERR,"ERROR:dialog:init_dlg_timer: no more shm mem\n");
return -1;
}
memset( d_timer, 0, sizeof(struct dlg_timer) );
d_timer->first.next = d_timer->first.prev = &(d_timer->first);
d_timer->lock = lock_alloc();
if (d_timer->lock==0) {
LOG(L_ERR,"ERROR:dialog:init_dlg_timer: failed to alloc lock\n");
goto error0;
}
if (lock_init(d_timer->lock)==0) {
LOG(L_ERR,"ERROR:dialog:init_dlg_timer: failed to init lock\n");
goto error1;
}
timer_hdl = hdl;
return 0;
error1:
lock_dealloc(d_timer->lock);
error0:
shm_free(d_timer);
d_timer = 0;
return -1;
}
void destroy_dlg_timer()
{
if (d_timer==0)
return;
lock_destroy(d_timer->lock);
lock_dealloc(d_timer->lock);
shm_free(d_timer);
d_timer = 0;
}
static inline void insert_dlg_timer_unsafe(struct dlg_tl *tl)
{
struct dlg_tl* ptr;
for(ptr = d_timer->first.prev; ptr != &d_timer->first ; ptr = ptr->prev) {
if ( ptr->timeout <= tl->timeout )
break;
}
DBG("DEBUG:dialog:insert_tl: inserting %p for %d\n",
tl,tl->timeout);
tl->prev = ptr;
tl->next = ptr->next;
tl->prev->next = tl;
tl->next->prev = tl;
}
int insert_dlg_timer(struct dlg_tl *tl, int interval)
{
lock_get( d_timer->lock);
if (tl->next!=0 || tl->prev!=0) {
lock_release( d_timer->lock);
return -1;
}
tl->timeout = get_ticks()+interval;
insert_dlg_timer_unsafe( tl );
lock_release( d_timer->lock);
return 0;
}
static inline void remove_dlg_timer_unsafe(struct dlg_tl *tl)
{
tl->prev->next = tl->next;
tl->next->prev = tl->prev;
}
int remove_dlg_timer(struct dlg_tl *tl)
{
lock_get( d_timer->lock);
if (tl->prev==0) {
lock_release( d_timer->lock);
return -1;
}
remove_dlg_timer_unsafe(tl);
tl->next = 0;
tl->prev = 0;
tl->timeout = 0;
lock_release( d_timer->lock);
return 0;
}
int update_dlg_timer( struct dlg_tl *tl, int timeout )
{
lock_get( d_timer->lock);
if ( tl->next ) {
if (tl->prev==0) {
lock_release( d_timer->lock);
return -1;
}
remove_dlg_timer_unsafe(tl);
}
tl->timeout = get_ticks()+timeout;
insert_dlg_timer_unsafe( tl );
lock_release( d_timer->lock);
return 0;
}
static inline struct dlg_tl* get_expired_dlgs(unsigned int time)
{
struct dlg_tl *tl , *end, *ret;
if (d_timer->first.next==&(d_timer->first)
|| d_timer->first.next->timeout > time )
return 0;
lock_get( d_timer->lock);
end = &d_timer->first;
tl = d_timer->first.next;
DBG("DEBUG:dialog:insert_tl: start with %p (%d) at %d\n",
tl,tl->timeout,time);
while( tl!=end && tl->timeout <= time) {
DBG("DEBUG:dialog:get_expired_tl: getting %p with %d\n",
tl,tl->timeout);
tl->prev = 0;
tl=tl->next;
}
if (tl==end && d_timer->first.next->prev) {
ret = 0;
} else {
ret = d_timer->first.next;
tl->prev->next = 0;
d_timer->first.next = tl;
tl->prev = &d_timer->first;
}
lock_release( d_timer->lock);
return ret;
}
void dlg_timer_routine(unsigned int ticks , void * attr)
{
struct dlg_tl *tl, *ctl;
tl = get_expired_dlgs( ticks );
while (tl) {
ctl = tl;
tl = tl->next;
ctl->next = (struct dlg_tl *)-1;
DBG("DEBUG:dialog:dlg_timer_routine: tl=%p next=%p\n", ctl, tl);
timer_hdl( ctl );
}
}
syntax highlighted by Code2HTML, v. 0.9.1