mirror of https://github.com/sipwise/kamailio.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
243 lines
5.5 KiB
243 lines
5.5 KiB
#include "time_event_manager.h"
|
|
#include "../../mem/mem.h"
|
|
#include "../../mem/shm_mem.h"
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "trace.h"
|
|
|
|
typedef struct {
|
|
time_event_manager_t *first;
|
|
time_event_manager_t *last;
|
|
gen_lock_t structure_mutex;
|
|
} tem_info_t;
|
|
|
|
static tem_info_t *tem_info = NULL;
|
|
|
|
static void tem_do_step(time_event_manager_t *tem);
|
|
|
|
static void tem_timer_cb(unsigned int ticks, void *param)
|
|
{
|
|
time_event_manager_t *e, *n;
|
|
|
|
PROF_START(tem_timer_cb)
|
|
if (!tem_info) return;
|
|
|
|
e = tem_info->first;
|
|
while (e) {
|
|
n = e->next;
|
|
if (--e->process_timer_counter == 0) {
|
|
tem_do_step(e);
|
|
e->process_timer_counter = e->atomic_time;
|
|
}
|
|
e = n;
|
|
}
|
|
PROF_STOP(tem_timer_cb)
|
|
}
|
|
|
|
int time_event_management_init()
|
|
{
|
|
if (tem_info) return 0; /* already initialized */
|
|
|
|
tem_info = (tem_info_t *)mem_alloc(sizeof(tem_info_t));
|
|
if (!tem_info) {
|
|
LOG(L_ERR, "time_event_management_init(): can't allocate shared memory\n");
|
|
return -1;
|
|
}
|
|
tem_info->first = NULL;
|
|
tem_info->last = NULL;
|
|
lock_init(&tem_info->structure_mutex);
|
|
|
|
/* register a SER timer */
|
|
if (register_timer(tem_timer_cb, NULL, 1) < 0) {
|
|
LOG(L_ERR, "time_event_management_init(): can't register timer\n");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void time_event_management_destroy()
|
|
{
|
|
time_event_manager_t *e, *n;
|
|
tem_info_t *ti = tem_info;
|
|
|
|
tem_info = NULL;
|
|
/* F I X M E: unregister SER timer ? */
|
|
|
|
if (!ti) return;
|
|
|
|
e = ti->first;
|
|
while (e) {
|
|
n = e->next;
|
|
tem_destroy(n);
|
|
e = n;
|
|
}
|
|
|
|
mem_free(ti);
|
|
}
|
|
|
|
int tem_init(time_event_manager_t *tm, unsigned int atomic_time,
|
|
unsigned int slot_cnt, int enable_delay, gen_lock_t *mutex)
|
|
{
|
|
if (!tm) return -1;
|
|
|
|
tm->tick_counter = 0;
|
|
tm->atomic_time = atomic_time;
|
|
tm->slot_cnt = slot_cnt;
|
|
tm->enable_delay = enable_delay;
|
|
tm->mutex = mutex;
|
|
tm->time_slots = (time_event_slot_t *)mem_alloc(slot_cnt * sizeof(time_event_slot_t));
|
|
if (!tm->time_slots) {
|
|
LOG(L_ERR, "can't initialize time event manager slots\n");
|
|
return -1;
|
|
}
|
|
memset(tm->time_slots, 0, slot_cnt * sizeof(time_event_slot_t));
|
|
|
|
tm->next = NULL;
|
|
tm->process_timer_counter = atomic_time;
|
|
|
|
lock_get(&tem_info->structure_mutex);
|
|
|
|
tm->prev = tem_info->last;
|
|
if (tem_info->last) tem_info->last->next = tm;
|
|
else tem_info->first = tm;
|
|
tem_info->last = tm;
|
|
|
|
lock_release(&tem_info->structure_mutex);
|
|
|
|
return 0;
|
|
}
|
|
|
|
time_event_manager_t *tem_create(unsigned int atomic_time, unsigned int slot_cnt, int enable_delay, gen_lock_t *mutex)
|
|
{
|
|
time_event_manager_t *tm;
|
|
|
|
tm = (time_event_manager_t*)mem_alloc(sizeof(time_event_manager_t));
|
|
if (!tm) {
|
|
LOG(L_ERR, "can't allocate time event manager\n");
|
|
return tm;
|
|
}
|
|
|
|
if (tem_init(tm, atomic_time, slot_cnt, enable_delay, mutex) != 0) {
|
|
mem_free(tm);
|
|
return NULL;
|
|
}
|
|
|
|
return tm;
|
|
}
|
|
|
|
void tem_destroy(time_event_manager_t *tem)
|
|
{
|
|
if (tem) {
|
|
lock_get(&tem_info->structure_mutex);
|
|
|
|
if (tem->prev) tem->prev->next = tem->next;
|
|
else tem_info->first = tem->next;
|
|
if (tem->next) tem->next->prev = tem->prev;
|
|
else tem_info->last = tem->prev;
|
|
|
|
lock_release(&tem_info->structure_mutex);
|
|
|
|
if (tem->time_slots) mem_free(tem->time_slots);
|
|
mem_free(tem);
|
|
}
|
|
}
|
|
|
|
void tem_add_event(time_event_manager_t *tem, unsigned int action_time, time_event_data_t *te)
|
|
{
|
|
if (tem->mutex) lock_get(tem->mutex);
|
|
tem_add_event_nolock(tem, action_time, te);
|
|
if (tem->mutex) lock_release(tem->mutex);
|
|
}
|
|
|
|
void tem_remove_event(time_event_manager_t *tem, time_event_data_t *te)
|
|
{
|
|
if (tem->mutex) lock_get(tem->mutex);
|
|
tem_remove_event_nolock(tem, te);
|
|
if (tem->mutex) lock_release(tem->mutex);
|
|
}
|
|
|
|
void tem_add_event_nolock(time_event_manager_t *tem, unsigned int action_time, time_event_data_t *te)
|
|
{
|
|
unsigned int tick, s;
|
|
|
|
PROF_START(tem_add_event)
|
|
if (!te) return;
|
|
tick = action_time / tem->atomic_time;
|
|
if ((tem->enable_delay) && (action_time % tem->atomic_time > 0)) {
|
|
/* rather call the action later than before */
|
|
tick++;
|
|
}
|
|
if (tick <= 0) tick = 1; /* never add to current slot (? only if not processing ?)*/
|
|
tick += tem->tick_counter;
|
|
s = tick % tem->slot_cnt;
|
|
|
|
te->next = NULL;
|
|
te->prev = tem->time_slots[s].last;
|
|
if (tem->time_slots[s].last)
|
|
tem->time_slots[s].last->next = te;
|
|
else
|
|
tem->time_slots[s].first = te;
|
|
tem->time_slots[s].last = te;
|
|
|
|
te->tick_time = tick;
|
|
PROF_STOP(tem_add_event)
|
|
}
|
|
|
|
void tem_remove_event_nolock(time_event_manager_t *tem, time_event_data_t *te)
|
|
{
|
|
time_event_slot_t *slot;
|
|
|
|
PROF_START(tem_remove_event)
|
|
if (!te) return;
|
|
|
|
slot = &tem->time_slots[te->tick_time % tem->slot_cnt];
|
|
|
|
if (te->prev) te->prev->next = te->next;
|
|
else slot->first = te->next;
|
|
if (te->next) te->next->prev = te->prev;
|
|
else slot->last = te->prev;
|
|
te->next = NULL;
|
|
te->prev = NULL;
|
|
PROF_STOP(tem_remove_event)
|
|
}
|
|
|
|
static void tem_do_step(time_event_manager_t *tem)
|
|
{
|
|
time_event_data_t *e, *n, *unprocessed_first, *unprocessed_last;
|
|
time_event_slot_t *slot;
|
|
|
|
PROF_START(tem_do_step)
|
|
if (tem->mutex) lock_get(tem->mutex);
|
|
|
|
unprocessed_first = NULL;
|
|
unprocessed_last = NULL;
|
|
slot = &tem->time_slots[tem->tick_counter % tem->slot_cnt];
|
|
e = slot->first;
|
|
while (e) {
|
|
n = e->next;
|
|
if (e->tick_time == tem->tick_counter) {
|
|
if (e->cb) e->cb(e);
|
|
/* the pointer to this element is forgotten - it MUST be
|
|
* freed in the callback function */
|
|
}
|
|
else {
|
|
/* it is not the right time => give it into unprocessed events */
|
|
e->prev = unprocessed_last;
|
|
e->next = NULL;
|
|
if (unprocessed_last) unprocessed_last->next = e;
|
|
else unprocessed_first = e;
|
|
unprocessed_last = e;
|
|
}
|
|
e = n;
|
|
}
|
|
|
|
slot->first = unprocessed_first;
|
|
slot->last = unprocessed_last;
|
|
tem->tick_counter++;
|
|
|
|
if (tem->mutex) lock_release(tem->mutex);
|
|
PROF_STOP(tem_do_step)
|
|
}
|
|
|