summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
authorWilliam Wilgus <me.theuser@yahoo.com>2019-10-09 17:22:48 -0500
committerWilliam Wilgus <me.theuser@yahoo.com>2019-10-17 21:19:00 +0200
commit1da2708a7c48c144605d84da94d0184209713683 (patch)
tree976a29826def7be4cc2bd24141064ed2cd6209ce /firmware
parent3d6d90382ea368135544ebae875de99df73986ee (diff)
downloadrockbox-1da2708a7c48c144605d84da94d0184209713683.tar.gz
rockbox-1da2708a7c48c144605d84da94d0184209713683.zip
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
Diffstat (limited to 'firmware')
-rw-r--r--firmware/export/timer.h5
-rw-r--r--firmware/target/hosted/kernel-unix.c16
-rw-r--r--firmware/timer.c4
3 files changed, 21 insertions, 4 deletions
diff --git a/firmware/export/timer.h b/firmware/export/timer.h
index b12ec55881..92b26db216 100644
--- a/firmware/export/timer.h
+++ b/firmware/export/timer.h
@@ -30,6 +30,7 @@
30#define TIMER_FREQ 1000000 30#define TIMER_FREQ 1000000
31#endif 31#endif
32 32
33/* NOTE: if unreg cb is defined you are in charge of calling timer_unregister() */
33bool timer_register(int reg_prio, void (*unregister_callback)(void), 34bool timer_register(int reg_prio, void (*unregister_callback)(void),
34 long cycles, void (*timer_callback)(void) 35 long cycles, void (*timer_callback)(void)
35 IF_COP(,int core)); 36 IF_COP(,int core));
@@ -37,6 +38,10 @@ bool timer_set_period(long cycles);
37#ifdef CPU_COLDFIRE 38#ifdef CPU_COLDFIRE
38void timers_adjust_prescale(int multiplier, bool enable_irq); 39void timers_adjust_prescale(int multiplier, bool enable_irq);
39#endif 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() */
40void timer_unregister(void); 45void timer_unregister(void);
41 46
42/* target-specific interface */ 47/* target-specific interface */
diff --git a/firmware/target/hosted/kernel-unix.c b/firmware/target/hosted/kernel-unix.c
index e3c492a8cc..ed1f83cd8c 100644
--- a/firmware/target/hosted/kernel-unix.c
+++ b/firmware/target/hosted/kernel-unix.c
@@ -113,8 +113,8 @@ void (*global_timer_callback)(void);
113 113
114static void timer_cb(union sigval arg) 114static void timer_cb(union sigval arg)
115{ 115{
116 (void)arg; 116 /* check for spurious callbacks [arg.sival_ptr] */
117 if (global_timer_callback) 117 if (global_timer_callback && global_timer_callback == arg.sival_ptr)
118 global_timer_callback(); 118 global_timer_callback();
119} 119}
120 120
@@ -129,12 +129,18 @@ bool timer_register(int reg_prio, void (*unregister_callback)(void),
129 if (reg_prio <= timer_prio || in_us <= 0) 129 if (reg_prio <= timer_prio || in_us <= 0)
130 return false; 130 return false;
131 131
132 if (timer_prio >= 0 && global_unreg_callback) 132 if(timer_prio >= 0)
133 global_unreg_callback(); 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 memset(&sigev, 0, sizeof(sigevent_t)); 140 memset(&sigev, 0, sizeof(sigevent_t));
136 sigev.sigev_notify = SIGEV_THREAD, 141 sigev.sigev_notify = SIGEV_THREAD,
137 sigev.sigev_notify_function = timer_cb; 142 sigev.sigev_notify_function = timer_cb;
143 sigev.sigev_value.sival_ptr = timer_callback; /* store cb to check later */
138 144
139 div_t q = div(in_us, 1000000); 145 div_t q = div(in_us, 1000000);
140 ts.it_value.tv_sec = ts.it_interval.tv_sec = q.quot; 146 ts.it_value.tv_sec = ts.it_interval.tv_sec = q.quot;
@@ -166,4 +172,6 @@ void timer_unregister(void)
166{ 172{
167 timer_delete(timer_tid); 173 timer_delete(timer_tid);
168 timer_prio = -1; 174 timer_prio = -1;
175 global_unreg_callback = NULL;
176 global_timer_callback = NULL;
169} 177}
diff --git a/firmware/timer.c b/firmware/timer.c
index a923290a94..c618f72e02 100644
--- a/firmware/timer.c
+++ b/firmware/timer.c
@@ -42,6 +42,7 @@ bool timer_register(int reg_prio, void (*unregister_callback)(void),
42 return false; 42 return false;
43 43
44 pfn_timer = timer_callback; 44 pfn_timer = timer_callback;
45 /* NOTE: if unreg cb is defined you are in charge of calling timer_unregister() */
45 pfn_unregister = unregister_callback; 46 pfn_unregister = unregister_callback;
46 timer_prio = reg_prio; 47 timer_prio = reg_prio;
47 48
@@ -53,6 +54,9 @@ bool timer_set_period(long cycles)
53 return timer_set(cycles, false); 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() */
56void timer_unregister(void) 60void timer_unregister(void)
57{ 61{
58 timer_stop(); 62 timer_stop();