#include "time_event_manager.h" #include "../../mem/mem.h" #include "../../mem/shm_mem.h" #include #include #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) }