No malloc for default alarm pool an pheap docs/cleanup (#143)

* Statically allocate the default timer pool (to avoid pulling in malloc); doxygen for pheap (and some function name changes)

* fix comments
This commit is contained in:
Graham Sanderson
2021-02-25 08:40:03 -06:00
committed by graham sanderson
parent 0a22f704a6
commit e730e03e7f
3 changed files with 225 additions and 57 deletions

View File

@ -33,26 +33,25 @@ typedef struct alarm_pool {
} alarm_pool_t;
#if !PICO_TIME_DEFAULT_ALARM_POOL_DISABLED
static alarm_pool_t *default_alarm_pool;
// To avoid bringing in calloc, we statically allocate the arrays and the heap
PHEAP_DEFINE_STATIC(default_alarm_pool_heap, PICO_TIME_DEFAULT_ALARM_POOL_MAX_TIMERS);
static alarm_pool_entry_t default_alarm_pool_entries[PICO_TIME_DEFAULT_ALARM_POOL_MAX_TIMERS];
static uint8_t default_alarm_pool_entry_ids_high[PICO_TIME_DEFAULT_ALARM_POOL_MAX_TIMERS];
static alarm_pool_t default_alarm_pool = {
.heap = &default_alarm_pool_heap,
.entries = default_alarm_pool_entries,
.entry_ids_high = default_alarm_pool_entry_ids_high,
};
static inline bool default_alarm_pool_initialized(void) {
return default_alarm_pool.lock != NULL;
}
#endif
static alarm_pool_t *pools[NUM_TIMERS];
static void alarm_pool_post_alloc_init(alarm_pool_t *pool, uint hardware_alarm_num);
void alarm_pool_init_default() {
#if !PICO_TIME_DEFAULT_ALARM_POOL_DISABLED
// allow multiple calls for ease of use from host tests
if (!default_alarm_pool) {
default_alarm_pool = alarm_pool_create(PICO_TIME_DEFAULT_ALARM_POOL_HARDWARE_ALARM_NUM,
PICO_TIME_DEFAULT_ALARM_POOL_MAX_TIMERS);
}
#endif
}
#if !PICO_TIME_DEFAULT_ALARM_POOL_DISABLED
alarm_pool_t *alarm_pool_get_default() {
assert(default_alarm_pool);
return default_alarm_pool;
}
#endif
static inline alarm_pool_entry_t *get_entry(alarm_pool_t *pool, pheap_node_id_t id) {
assert(id && id <= pool->heap->max_nodes);
@ -73,11 +72,30 @@ static inline alarm_id_t make_public_id(uint8_t id_high, pheap_node_id_t id) {
return (alarm_id_t)(((uint)id_high << 8u * sizeof(id)) | id);
}
void alarm_pool_init_default() {
#if !PICO_TIME_DEFAULT_ALARM_POOL_DISABLED
// allow multiple calls for ease of use from host tests
if (!default_alarm_pool_initialized()) {
ph_post_alloc_init(default_alarm_pool.heap, PICO_TIME_DEFAULT_ALARM_POOL_MAX_TIMERS,
timer_pool_entry_comparator, &default_alarm_pool);
alarm_pool_post_alloc_init(&default_alarm_pool,
PICO_TIME_DEFAULT_ALARM_POOL_HARDWARE_ALARM_NUM);
}
#endif
}
#if !PICO_TIME_DEFAULT_ALARM_POOL_DISABLED
alarm_pool_t *alarm_pool_get_default() {
assert(default_alarm_pool_initialized());
return &default_alarm_pool;
}
#endif
static pheap_node_id_t add_alarm_under_lock(alarm_pool_t *pool, absolute_time_t time, alarm_callback_t callback,
void *user_data, pheap_node_id_t reuse_id, bool create_if_past, bool *missed) {
pheap_node_id_t id;
if (reuse_id) {
assert(!ph_contains(pool->heap, reuse_id));
assert(!ph_contains_node(pool->heap, reuse_id));
id = reuse_id;
} else {
id = ph_new_node(pool->heap);
@ -87,10 +105,10 @@ static pheap_node_id_t add_alarm_under_lock(alarm_pool_t *pool, absolute_time_t
entry->target = time;
entry->callback = callback;
entry->user_data = user_data;
if (id == ph_insert(pool->heap, id)) {
if (id == ph_insert_node(pool->heap, id)) {
bool is_missed = hardware_alarm_set_target(pool->hardware_alarm_num, time);
if (is_missed && !create_if_past) {
ph_delete(pool->heap, id);
ph_remove_and_free_node(pool->heap, id);
}
if (missed) *missed = is_missed;
}
@ -114,8 +132,8 @@ static void alarm_pool_alarm_callback(uint alarm_num) {
if (next_id) {
alarm_pool_entry_t *entry = get_entry(pool, next_id);
if (absolute_time_diff_us(now, entry->target) <= 0) {
// we reserve the id in case we need to re-add the timer
pheap_node_id_t __unused removed_id = ph_remove_head_reserve(pool->heap, true);
// we don't free the id in case we need to re-add the timer
pheap_node_id_t __unused removed_id = ph_remove_head(pool->heap, false);
assert(removed_id == next_id); // will be true under lock
target = entry->target;
callback = entry->callback;
@ -143,7 +161,7 @@ static void alarm_pool_alarm_callback(uint alarm_num) {
true, NULL);
} else {
// need to return the id to the heap
ph_add_to_free_list(pool->heap, next_id);
ph_free_node(pool->heap, next_id);
(*get_entry_id_high(pool, next_id))++; // we bump it for next use of id
}
pool->alarm_in_progress = 0;
@ -155,20 +173,30 @@ static void alarm_pool_alarm_callback(uint alarm_num) {
// note the timer is create with IRQs on this core
alarm_pool_t *alarm_pool_create(uint hardware_alarm_num, uint max_timers) {
hardware_alarm_claim(hardware_alarm_num);
hardware_alarm_cancel(hardware_alarm_num);
hardware_alarm_set_callback(hardware_alarm_num, alarm_pool_alarm_callback);
alarm_pool_t *pool = (alarm_pool_t *)malloc(sizeof(alarm_pool_t));
pool->lock = spin_lock_instance(next_striped_spin_lock_num());
alarm_pool_t *pool = (alarm_pool_t *) malloc(sizeof(alarm_pool_t));
pool->heap = ph_create(max_timers, timer_pool_entry_comparator, pool);
pool->entries = (alarm_pool_entry_t *)calloc(max_timers, sizeof(alarm_pool_entry_t));
pool->entry_ids_high = (uint8_t *)calloc(max_timers, sizeof(uint8_t));
pool->hardware_alarm_num = (uint8_t)hardware_alarm_num;
pools[hardware_alarm_num] = pool;
alarm_pool_post_alloc_init(pool, hardware_alarm_num);
return pool;
}
void alarm_pool_post_alloc_init(alarm_pool_t *pool, uint hardware_alarm_num) {
hardware_alarm_claim(hardware_alarm_num);
hardware_alarm_cancel(hardware_alarm_num);
hardware_alarm_set_callback(hardware_alarm_num, alarm_pool_alarm_callback);
pool->lock = spin_lock_instance(next_striped_spin_lock_num());
pool->hardware_alarm_num = (uint8_t) hardware_alarm_num;
pools[hardware_alarm_num] = pool;
}
void alarm_pool_destroy(alarm_pool_t *pool) {
#if !PICO_TIME_DEFAULT_ALARM_POOL_DISABLED
if (pool == &default_alarm_pool) {
assert(false); // attempt to delete default alarm pool
return;
}
#endif
assert(pools[pool->hardware_alarm_num] == pool);
pools[pool->hardware_alarm_num] = NULL;
// todo clear out timers
@ -219,12 +247,12 @@ bool alarm_pool_cancel_alarm(alarm_pool_t *pool, alarm_id_t alarm_id) {
bool rc = false;
uint32_t save = spin_lock_blocking(pool->lock);
pheap_node_id_t id = (pheap_node_id_t) alarm_id;
if (ph_contains(pool->heap, id)) {
if (ph_contains_node(pool->heap, id)) {
assert(alarm_id != pool->alarm_in_progress); // it shouldn't be in the heap if it is in progress
// check we have the right high value
uint8_t id_high = (uint8_t)((uint)alarm_id >> 8u * sizeof(pheap_node_id_t));
if (id_high == *get_entry_id_high(pool, id)) {
rc = ph_delete(pool->heap, id);
rc = ph_remove_and_free_node(pool->heap, id);
// note we don't bother to remove the actual hardware alarm timeout...
// it will either do callbacks or not depending on other alarms, and reset the next timeout itself
assert(rc);