diff options
author | William Wilgus <me.theuser@yahoo.com> | 2019-10-09 17:22:48 -0500 |
---|---|---|
committer | William Wilgus <me.theuser@yahoo.com> | 2019-10-17 21:19:00 +0200 |
commit | 1da2708a7c48c144605d84da94d0184209713683 (patch) | |
tree | 976a29826def7be4cc2bd24141064ed2cd6209ce | |
parent | 3d6d90382ea368135544ebae875de99df73986ee (diff) | |
download | rockbox-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
-rw-r--r-- | firmware/export/timer.h | 5 | ||||
-rw-r--r-- | firmware/target/hosted/kernel-unix.c | 16 | ||||
-rw-r--r-- | firmware/timer.c | 4 |
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() */ | ||
33 | bool timer_register(int reg_prio, void (*unregister_callback)(void), | 34 | bool 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 |
38 | void timers_adjust_prescale(int multiplier, bool enable_irq); | 39 | void 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() */ | ||
40 | void timer_unregister(void); | 45 | void 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 | ||
114 | static void timer_cb(union sigval arg) | 114 | static 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() */ | ||
56 | void timer_unregister(void) | 60 | void timer_unregister(void) |
57 | { | 61 | { |
58 | timer_stop(); | 62 | timer_stop(); |