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