A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd

Fix timer Agptek Rocker (other hosted players)

on timer_unregister callbacks are not removed

It seems (at least on the Rocker) timers continue to fire (for a bit??)

Now we store the registered callback in the sigev structure and check
that the callback matches the one registered when the timer is created.

This should stop the possible case of a new timer getting spurious callbacks
We also now NULL the callbacks on un-register which should stop the segfaults

Added some notes to timer.c and timer.h

Change-Id: Ia155c3a4e4af89f474d55ed845560ccc1fab85aa

+21 -4
+5
firmware/export/timer.h
··· 30 #define TIMER_FREQ 1000000 31 #endif 32 33 bool timer_register(int reg_prio, void (*unregister_callback)(void), 34 long cycles, void (*timer_callback)(void) 35 IF_COP(,int core)); ··· 37 #ifdef CPU_COLDFIRE 38 void timers_adjust_prescale(int multiplier, bool enable_irq); 39 #endif 40 void timer_unregister(void); 41 42 /* target-specific interface */
··· 30 #define TIMER_FREQ 1000000 31 #endif 32 33 + /* NOTE: if unreg cb is defined you are in charge of calling timer_unregister() */ 34 bool timer_register(int reg_prio, void (*unregister_callback)(void), 35 long cycles, void (*timer_callback)(void) 36 IF_COP(,int core)); ··· 38 #ifdef CPU_COLDFIRE 39 void timers_adjust_prescale(int multiplier, bool enable_irq); 40 #endif 41 + 42 + /* NOTE: unregister callbacks are not called by timer_unregister() 43 + * the unregister_callback only gets called when your timer gets 44 + * overwritten by a lower priority timer using timer_register() */ 45 void timer_unregister(void); 46 47 /* target-specific interface */
+12 -4
firmware/target/hosted/kernel-unix.c
··· 113 114 static void timer_cb(union sigval arg) 115 { 116 - (void)arg; 117 - if (global_timer_callback) 118 global_timer_callback(); 119 } 120 ··· 129 if (reg_prio <= timer_prio || in_us <= 0) 130 return false; 131 132 - if (timer_prio >= 0 && global_unreg_callback) 133 - global_unreg_callback(); 134 135 memset(&sigev, 0, sizeof(sigevent_t)); 136 sigev.sigev_notify = SIGEV_THREAD, 137 sigev.sigev_notify_function = timer_cb; 138 139 div_t q = div(in_us, 1000000); 140 ts.it_value.tv_sec = ts.it_interval.tv_sec = q.quot; ··· 166 { 167 timer_delete(timer_tid); 168 timer_prio = -1; 169 }
··· 113 114 static void timer_cb(union sigval arg) 115 { 116 + /* check for spurious callbacks [arg.sival_ptr] */ 117 + if (global_timer_callback && global_timer_callback == arg.sival_ptr) 118 global_timer_callback(); 119 } 120 ··· 129 if (reg_prio <= timer_prio || in_us <= 0) 130 return false; 131 132 + if(timer_prio >= 0) 133 + { 134 + if (global_unreg_callback) /* timer has callback user needs to unreg */ 135 + global_unreg_callback(); 136 + else /* no callback -- delete timer */ 137 + timer_delete(timer_tid); 138 + } 139 140 memset(&sigev, 0, sizeof(sigevent_t)); 141 sigev.sigev_notify = SIGEV_THREAD, 142 sigev.sigev_notify_function = timer_cb; 143 + sigev.sigev_value.sival_ptr = timer_callback; /* store cb to check later */ 144 145 div_t q = div(in_us, 1000000); 146 ts.it_value.tv_sec = ts.it_interval.tv_sec = q.quot; ··· 172 { 173 timer_delete(timer_tid); 174 timer_prio = -1; 175 + global_unreg_callback = NULL; 176 + global_timer_callback = NULL; 177 }
+4
firmware/timer.c
··· 42 return false; 43 44 pfn_timer = timer_callback; 45 pfn_unregister = unregister_callback; 46 timer_prio = reg_prio; 47 ··· 53 return timer_set(cycles, false); 54 } 55 56 void timer_unregister(void) 57 { 58 timer_stop();
··· 42 return false; 43 44 pfn_timer = timer_callback; 45 + /* NOTE: if unreg cb is defined you are in charge of calling timer_unregister() */ 46 pfn_unregister = unregister_callback; 47 timer_prio = reg_prio; 48 ··· 54 return timer_set(cycles, false); 55 } 56 57 + /* NOTE: unregister callbacks are not called by timer_unregister() 58 + * the unregister_callback only gets called when your timer gets 59 + * overwritten by a lower priority timer using timer_register() */ 60 void timer_unregister(void) 61 { 62 timer_stop();