Fix race condition breaking low power waits when calling best_effort_wfe_or_timeout() from the non-alarm handler core. (#3039)
When best_effore_wfe_or_timeout is called from the non-alarm core, there is a potential race, since the adding of the alarm is actually asynchronous (since it happens via IRQ on the other core). since the default alarm pool handler never removes a pending WFE when set, we do not need to add again if we are called in a loop. We simply cache the last value set.
diff --git a/src/common/pico_time/time.c b/src/common/pico_time/time.c
index da52800..8215594 100644
--- a/src/common/pico_time/time.c
+++ b/src/common/pico_time/time.c
@@ -476,7 +476,8 @@
//
// Note also, that the use of software spin locks on RP2350 to access state would always cause a SEV
// due to use of LDREX etc., so actually using spin locks to protect the state would be worse.
- if (ta_wakes_up_on_or_before(alarm_pool_get_default()->timer, alarm_pool_get_default()->timer_alarm_num,
+ static uint64_t last_added;
+ if (last_added == to_us_since_boot(timeout_timestamp) || ta_wakes_up_on_or_before(alarm_pool_get_default()->timer, alarm_pool_get_default()->timer_alarm_num,
(int64_t)to_us_since_boot(timeout_timestamp))) {
// we already are waking up at or before when we want to (possibly due to us having been called
// before in a loop), so we can do an actual WFE. Note we rely on the fact that the alarm pool IRQ
@@ -489,6 +490,7 @@
tight_loop_contents();
return time_reached(timeout_timestamp);
} else {
+ last_added = to_us_since_boot(timeout_timestamp);
if (!time_reached(timeout_timestamp)) {
// ^ at the point above the timer hadn't fired, so it is safe
// to wait; the event will happen due to IRQ at some point between