Skip to content

Commit

Permalink
Fix reload of timer routes
Browse files Browse the repository at this point in the history
Use a separate, dynamic list of timer tasks that can be update by other proc than the timer itself (which has no info on the script).
The proc doing the reload, upon success, re-generates the list of timer tasks corresponding to the new set of timer routes.
NOTE: a more complex logic is needed when purging the old set of timer tasks, as they may still be under execution - we use here a pending list where we wait their completion.
  • Loading branch information
bogdan-iancu committed May 16, 2023
1 parent 01b49f1 commit fce0eae
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 31 deletions.
2 changes: 2 additions & 0 deletions cfg_reload.c
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,8 @@ int reload_routing_script(void)

send_cmd_to_all_procs( routes_switch_per_proc );

register_route_timers();

/* ready for a new reload :) */
reset_script_reload_ctx();

Expand Down
146 changes: 115 additions & 31 deletions timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
* special defines enabled (mainly sys/types.h) */
#include "reactor.h"
#include "pt_load.h"
#include "locking.h"

#include <unistd.h>
#include <fcntl.h>
Expand Down Expand Up @@ -81,6 +82,10 @@ static unsigned short timer_id=0;
static int timer_pipe[2];
static struct scaling_profile *s_profile=NULL;

static gen_lock_t *tr_list_lock = NULL;
static struct os_timer **tr_timer_list = NULL;
static struct os_timer **tr_timer_pending = NULL;

int timer_fd_out = -1 ;
char *timer_auto_scaling_profile = NULL;
int timer_workers_no = 1;
Expand Down Expand Up @@ -160,6 +165,33 @@ int init_timer(void)
auto_scaling_enabled = 1;
}

/* lock to protect the list of timer task for timer routes */
tr_list_lock = lock_alloc();
if (tr_list_lock==0) {
LM_ERR("failed to alloc lock\n");
return E_UNSPEC;
}

if (lock_init(tr_list_lock)==0) {
LM_ERR("failed to init lock\n");
return E_UNSPEC;
}

tr_timer_list = (struct os_timer**)shm_malloc(sizeof(struct os_timer*));
if (tr_timer_list==NULL) {
LM_ERR("failed to alloc timer holder\n");
return E_UNSPEC;
}
*tr_timer_list = NULL;

tr_timer_pending = (struct os_timer**)shm_malloc(sizeof(struct os_timer*));
if (tr_timer_pending==NULL) {
LM_ERR("failed to alloc timer pending holder\n");
return E_UNSPEC;
}
*tr_timer_pending = NULL;


return 0;
}

Expand Down Expand Up @@ -238,15 +270,29 @@ int register_utimer(char *label, utimer_function f, void* param,
}


struct timer_route_param {
unsigned int idx;
unsigned int version;
};

void route_timer_f(unsigned int ticks, void* param)
{
struct script_timer_route *tr = (struct script_timer_route *)param;
struct script_route sr = {tr->name, tr->a};
struct timer_route_param *tr=(struct timer_route_param *)param;
struct script_route sr;
struct sip_msg *req;
int old_route_type;

if (tr->version!=sroutes->version) {
LM_WARN("timer route triggering received for an old cfg version "
"%d<>%d\n",tr->version, sroutes->version);
return;
}

sr.name = sroutes->timer[tr->idx].name;
sr.a = sroutes->timer[tr->idx].a;

if(sr.a == NULL) {
LM_ERR("NULL actions for timer_route '%s'\n", sr.name);
LM_ERR("NULL actions for timer_route '%s'/%d\n", sr.name, tr->idx);
return;
}

Expand All @@ -268,29 +314,71 @@ void route_timer_f(unsigned int ticks, void* param)
}


/* the function will check the timer routes from the current process,
* so be carefull where you are running it from */
int register_route_timers(void)
{
struct os_timer* t;
struct timer_route_param *tr_param;
struct os_timer *t, *p;
int i;

if(sroutes->timer[0].a == NULL)
return 0;
#define move_to_pending( _t) \
while(_t) { \
p = (_t)->next; \
if ((_t)->trigger_time) { \
(_t)->next = *tr_timer_pending; \
*tr_timer_pending = (_t); \
} else { \
shm_free( (_t)->t_param ); \
shm_free( (_t) ); \
} \
(_t) = p; \
}

lock_get(tr_list_lock);

/* handle the pending list, remove whatever already finished,
* otherwise put back into pending */
t = *tr_timer_pending;
*tr_timer_pending = NULL;
move_to_pending( t);

/* handle the existing list -> free if done or move to pending if
* the job is still under execution (for sure triggering cannot be
* done anymore as the have the lock here) */
t = *tr_timer_list;
move_to_pending( t);
*tr_timer_list = NULL;

/* register the routes */
for(i = 0; i< TIMER_RT_NO; i++)
/* convert timer routes to jobs */
for(i = 0; i<TIMER_RT_NO && sroutes->timer[i].a ; i++)
{
if(sroutes->timer[i].a == NULL)
return 0;
t = new_os_timer( "timer_route", 0, route_timer_f, &sroutes->timer[i],
LM_DBG("registering timer route [%s] at %d secs\n",
sroutes->timer[i].name, sroutes->timer[i].interval);

tr_param = (struct timer_route_param*)
shm_malloc( sizeof(struct timer_route_param) );
if (tr_param==NULL) {
LM_ERR("no more mem, skipping route timer [%s]\n",
sroutes->timer[i].name);
} else {
tr_param->idx = i;
tr_param->version = sroutes->version;
t = new_os_timer( "timer_route", 0, route_timer_f, (void*)tr_param,
sroutes->timer[i].interval);
if (t==NULL)
return E_OUT_OF_MEM;

/* insert it into the list*/
t->next = timer_list;
timer_list = t;
if (t==NULL) {
LM_ERR("no more mem, skipping route timer [%s]\n",
sroutes->timer[i].name);
} else {
/* insert it into the list*/
t->next = *tr_timer_list;
*tr_timer_list = t;
}
}
}

lock_release(tr_list_lock);

return 1;
}

Expand Down Expand Up @@ -468,21 +556,11 @@ static void run_timer_process( void )
compute_wait_with_drift(comp_tv);
tv = comp_tv;
select( 0, 0, 0, 0, &tv);
timer_ticker( timer_list);

drift += ((utime_t)comp_tv.tv_sec*1000000+comp_tv.tv_usec > (*ijiffies-ij)) ?
0 : *ijiffies-ij - ((utime_t)comp_tv.tv_sec*1000000+comp_tv.tv_usec);
}

} else
if (timer_list==NULL) {
/* only UTIMERs, ticking at UTIMER_TICK */
for( ; ; ) {
ij = *ijiffies;
compute_wait_with_drift(comp_tv);
tv = comp_tv;
select( 0, 0, 0, 0, &tv);
utimer_ticker( utimer_list);
timer_ticker( timer_list);
lock_get(tr_list_lock);
timer_ticker( *tr_timer_list);
lock_release(tr_list_lock);

drift += ((utime_t)comp_tv.tv_sec*1000000+comp_tv.tv_usec > (*ijiffies-ij)) ?
0 : *ijiffies-ij - ((utime_t)comp_tv.tv_sec*1000000+comp_tv.tv_usec);
Expand All @@ -497,6 +575,9 @@ static void run_timer_process( void )
tv = comp_tv;
select( 0, 0, 0, 0, &tv);
timer_ticker( timer_list);
lock_get(tr_list_lock);
timer_ticker( *tr_timer_list);
lock_release(tr_list_lock);
utimer_ticker( utimer_list);

drift += ((utime_t)comp_tv.tv_sec*1000000+comp_tv.tv_usec > (*ijiffies-ij)) ?
Expand All @@ -513,6 +594,9 @@ static void run_timer_process( void )
utimer_ticker(utimer_list);
if (cnt==multiple) {
timer_ticker(timer_list);
lock_get(tr_list_lock);
timer_ticker( *tr_timer_list);
lock_release(tr_list_lock);
cnt = 0;
}

Expand Down

0 comments on commit fce0eae

Please sign in to comment.