@@ -139,7 +139,9 @@ static void alarm_pool_irq_handler(void);
139139
140140// marker which we can use in place of handler function to indicate we are a repeating timer
141141
142- #define repeating_timer_marker ((alarm_callback_t)alarm_pool_irq_handler)
142+ #define repeating_timer_marker ((alarm_callback_t)(uintptr_t)2)
143+ #define deleted_timer_marker ((alarm_callback_t)(uintptr_t)4)
144+
143145#include "hardware/gpio.h"
144146static void alarm_pool_irq_handler (void ) {
145147 // This IRQ handler does the main work, as it always (assuming the IRQ hasn't been enabled on both cores
@@ -168,23 +170,23 @@ static void alarm_pool_irq_handler(void) {
168170 if (earliest_index >= 0 ) {
169171 alarm_pool_entry_t * earliest_entry = & pool -> entries [earliest_index ];
170172 earliest_target = earliest_entry -> target ;
171- if (((int64_t )ta_time_us_64 (timer ) - earliest_target ) >= 0 ) {
172- // time to call the callback now (or in the past)
173- // note that an entry->target of < 0 means the entry has been canceled (not this is set
174- // by this function, in response to the entry having been queued by the cancel_alarm API
175- // meaning that we don't need to worry about tearing of the 64 bit value)
173+ // delete_timer flag is set by this function, and then the item is moved to the front
174+ // of the queue for deletion now
175+ bool delete_timer = earliest_entry -> callback == deleted_timer_marker ;
176+ if (delete_timer || ((int64_t )ta_time_us_64 (timer ) - earliest_target ) >= 0 ) {
176177 int64_t delta ;
177- if (earliest_target >= 0 ) {
178- // special case repeating timer without making another function call which adds overhead
178+ if (! delete_timer ) {
179+ // time to call the callback now (or in the past)
179180 if (earliest_entry -> callback == repeating_timer_marker ) {
181+ // special case repeating timer without making another function call which adds overhead
180182 repeating_timer_t * rpt = (repeating_timer_t * )earliest_entry -> user_data ;
181183 delta = rpt -> callback (rpt ) ? rpt -> delay_us : 0 ;
182184 } else {
183185 alarm_id_t id = make_alarm_id (pool -> ordered_head , earliest_entry -> sequence );
184186 delta = earliest_entry -> callback (id , earliest_entry -> user_data );
185187 }
186188 } else {
187- // negative target means cancel alarm
189+ // cancel alarm
188190 delta = 0 ;
189191 }
190192 if (delta ) {
@@ -243,6 +245,19 @@ static void alarm_pool_irq_handler(void) {
243245 new_entry -> next = next ;
244246 }
245247 }
248+ earliest_index = pool -> ordered_head ;
249+ if (earliest_index < 0 ) break ;
250+ alarm_pool_entry_t * earliest_entry = & pool -> entries [earliest_index ];
251+ //printf("NOW EARLIEST INDEX %d timeout %lld\n", earliest_index, earliest_entry->target);
252+ earliest_target = earliest_entry -> target ;
253+ if (earliest_entry -> callback != deleted_timer_marker ) {
254+ // we are leaving a timeout every 2^32 microseconds anyway if there is no valid target, so we can choose any value.
255+ // best_effort_wfe_or_timeout now relies on it being the last value set, and arguably this is the
256+ // best value anyway, as it is the furthest away from the last fire.
257+ //printf("SET TIMEOUT %lld\n", earliest_target);
258+ ta_set_timeout (timer , timer_alarm_num , earliest_target );
259+ }
260+
246261 // if we have any canceled alarms, then mark them for removal by setting their due time to -1 (which will
247262 // cause them to be handled the next time round and removed)
248263 if (pool -> has_pending_cancellations ) {
@@ -255,7 +270,7 @@ static void alarm_pool_irq_handler(void) {
255270 int16_t next = entry -> next ;
256271 if ((int16_t )entry -> sequence < 0 ) {
257272 // mark for deletion
258- entry -> target = -1 ;
273+ entry -> callback = deleted_timer_marker ;
259274 if (index != pool -> ordered_head ) {
260275 // move to start of queue
261276 * prev = entry -> next ;
@@ -268,17 +283,6 @@ static void alarm_pool_irq_handler(void) {
268283 index = next ;
269284 }
270285 }
271- earliest_index = pool -> ordered_head ;
272- if (earliest_index < 0 ) break ;
273- // need to wait
274- alarm_pool_entry_t * earliest_entry = & pool -> entries [earliest_index ];
275- earliest_target = earliest_entry -> target ;
276- // we are leaving a timeout every 2^32 microseconds anyway if there is no valid target, so we can choose any value.
277- // best_effort_wfe_or_timeout now relies on it being the last value set, and arguably this is the
278- // best value anyway, as it is the furthest away from the last fire.
279- if (earliest_target != -1 ) { // cancelled alarm has target of -1
280- ta_set_timeout (timer , timer_alarm_num , earliest_target );
281- }
282286 // check we haven't now passed the target time; if not we don't want to loop again
283287 } while ((earliest_target - (int64_t )ta_time_us_64 (timer )) <= 0 );
284288 // We always want the timer IRQ to wake a WFE so that best_effort_wfe_or_timeout() will wake up. It will wake
0 commit comments