Rework lock_core / timers (#378)
- Add recursive_mutex - Make all locking primitives and sleep use common overridable wait/notify support to allow RTOS implementations to replace WFE/SEV with something more appropriate - Add busy_wait_ms
This commit is contained in:
@ -10,7 +10,7 @@
|
||||
#include "pico.h"
|
||||
#include "pico/time.h"
|
||||
#include "pico/util/pheap.h"
|
||||
#include "hardware/sync.h"
|
||||
#include "pico/sync.h"
|
||||
|
||||
const absolute_time_t ABSOLUTE_TIME_INITIALIZED_VAR(nil_time, 0);
|
||||
const absolute_time_t ABSOLUTE_TIME_INITIALIZED_VAR(at_the_end_of_time, INT64_MAX);
|
||||
@ -37,6 +37,7 @@ typedef struct alarm_pool {
|
||||
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 lock_core_t sleep_notifier;
|
||||
|
||||
static alarm_pool_t default_alarm_pool = {
|
||||
.heap = &default_alarm_pool_heap,
|
||||
@ -81,6 +82,7 @@ void alarm_pool_init_default() {
|
||||
alarm_pool_post_alloc_init(&default_alarm_pool,
|
||||
PICO_TIME_DEFAULT_ALARM_POOL_HARDWARE_ALARM_NUM);
|
||||
}
|
||||
lock_init(&sleep_notifier, PICO_SPINLOCK_ID_TIMER);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -318,8 +320,9 @@ void alarm_pool_dump(alarm_pool_t *pool) {
|
||||
}
|
||||
|
||||
#if !PICO_TIME_DEFAULT_ALARM_POOL_DISABLED
|
||||
static int64_t sev_callback(__unused alarm_id_t id, __unused void *user_data) {
|
||||
__sev();
|
||||
static int64_t sleep_until_callback(__unused alarm_id_t id, __unused void *user_data) {
|
||||
uint32_t save = spin_lock_blocking(sleep_notifier.spin_lock);
|
||||
lock_internal_spin_unlock_with_notify(&sleep_notifier, save);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@ -338,13 +341,17 @@ void sleep_until(absolute_time_t t) {
|
||||
absolute_time_t t_before;
|
||||
update_us_since_boot(&t_before, t_before_us);
|
||||
if (absolute_time_diff_us(get_absolute_time(), t_before) > 0) {
|
||||
if (add_alarm_at(t_before, sev_callback, NULL, false) >= 0) {
|
||||
if (add_alarm_at(t_before, sleep_until_callback, NULL, false) >= 0) {
|
||||
// able to add alarm for just before the time
|
||||
while (!time_reached(t_before)) {
|
||||
__wfe();
|
||||
uint32_t save = spin_lock_blocking(sleep_notifier.spin_lock);
|
||||
lock_internal_spin_unlock_with_wait(&sleep_notifier, save);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
// hook in case we're in RTOS; note we assume using the alarm pool is better always if available.
|
||||
sync_internal_yield_until_before(t);
|
||||
#endif
|
||||
// now wait until the exact time
|
||||
busy_wait_until(t);
|
||||
@ -354,13 +361,17 @@ void sleep_us(uint64_t us) {
|
||||
#if !PICO_TIME_DEFAULT_ALARM_POOL_DISABLED
|
||||
sleep_until(make_timeout_time_us(us));
|
||||
#else
|
||||
if (us >> 32u) {
|
||||
busy_wait_until(make_timeout_time_us(us));
|
||||
if (us < PICO_TIME_SLEEP_OVERHEAD_ADJUST_US) {
|
||||
busy_wait_us(us);
|
||||
} else {
|
||||
busy_wait_us_32(us);
|
||||
// hook in case we're in RTOS; note we assume using the alarm pool is better always if available.
|
||||
absolute_time_t t = make_timeout_time_us(us - PICO_TIME_SLEEP_OVERHEAD_ADJUST_US);
|
||||
sync_internal_yield_until_before(t);
|
||||
|
||||
// then wait the rest of thw way
|
||||
busy_wait_until(t);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void sleep_ms(uint32_t ms) {
|
||||
@ -370,7 +381,7 @@ void sleep_ms(uint32_t ms) {
|
||||
bool best_effort_wfe_or_timeout(absolute_time_t timeout_timestamp) {
|
||||
#if !PICO_TIME_DEFAULT_ALARM_POOL_DISABLED
|
||||
alarm_id_t id;
|
||||
id = add_alarm_at(timeout_timestamp, sev_callback, NULL, false);
|
||||
id = add_alarm_at(timeout_timestamp, sleep_until_callback, NULL, false);
|
||||
if (id <= 0) {
|
||||
tight_loop_contents();
|
||||
return time_reached(timeout_timestamp);
|
||||
|
Reference in New Issue
Block a user