summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Blumenkrantz <zmike@samsung.com>2019-10-28 14:59:11 -0400
committerMike Blumenkrantz <zmike@samsung.com>2019-10-31 09:58:46 -0400
commitb1fe7f99b5347d3f037be1803193b5f54f734a6a (patch)
tree4e3031944fd96e11eec0f7bad9bd84c0f2ae250e
parent45edca0f6dd027eb8fb25f30cbdbf72a1dda5f61 (diff)
ecore/timer: correctly handle recursive deletion of legacy timers
if a legacy timer callback returns false, the timer is deleted. in the case where the legacy timer is deleted inside the callback while the same timer is ticking recursively, however, the deletion must be deferred until the outer-most frame of the timer's callstack has returned from the callback in order to avoid improperly handling the timer @fix Reviewed-by: Cedric BAIL <cedric.bail@free.fr> Differential Revision: https://phab.enlightenment.org/D10545
-rw-r--r--src/lib/ecore/ecore_timer.c42
1 files changed, 27 insertions, 15 deletions
diff --git a/src/lib/ecore/ecore_timer.c b/src/lib/ecore/ecore_timer.c
index 518d06c06a..e07aa9f666 100644
--- a/src/lib/ecore/ecore_timer.c
+++ b/src/lib/ecore/ecore_timer.c
@@ -24,7 +24,7 @@ struct _Ecore_Timer_Legacy
24 Eina_Bool inside_call : 1; 24 Eina_Bool inside_call : 1;
25 Eina_Bool delete_me : 1; 25 Eina_Bool delete_me : 1;
26}; 26};
27 27typedef struct _Ecore_Timer_Legacy Ecore_Timer_Legacy;
28struct _Efl_Loop_Timer_Data 28struct _Efl_Loop_Timer_Data
29{ 29{
30 EINA_INLIST; 30 EINA_INLIST;
@@ -32,6 +32,7 @@ struct _Efl_Loop_Timer_Data
32 Eo *object; 32 Eo *object;
33 Eo *loop; 33 Eo *loop;
34 Efl_Loop_Data *loop_data; 34 Efl_Loop_Data *loop_data;
35 Ecore_Timer_Legacy *legacy;
35 36
36 double in; 37 double in;
37 double at; 38 double at;
@@ -47,8 +48,6 @@ struct _Efl_Loop_Timer_Data
47 Eina_Bool finalized : 1; 48 Eina_Bool finalized : 1;
48}; 49};
49 50
50typedef struct _Ecore_Timer_Legacy Ecore_Timer_Legacy;
51
52static void _efl_loop_timer_util_delay(Efl_Loop_Timer_Data *timer, double add); 51static void _efl_loop_timer_util_delay(Efl_Loop_Timer_Data *timer, double add);
53static void _efl_loop_timer_util_instanciate(Efl_Loop_Data *loop, Efl_Loop_Timer_Data *timer); 52static void _efl_loop_timer_util_instanciate(Efl_Loop_Data *loop, Efl_Loop_Timer_Data *timer);
54static void _efl_loop_timer_set(Efl_Loop_Timer_Data *timer, double at, double in); 53static void _efl_loop_timer_set(Efl_Loop_Timer_Data *timer, double at, double in);
@@ -156,12 +155,19 @@ static void
156_ecore_timer_legacy_tick(void *data, const Efl_Event *event) 155_ecore_timer_legacy_tick(void *data, const Efl_Event *event)
157{ 156{
158 Ecore_Timer_Legacy *legacy = data; 157 Ecore_Timer_Legacy *legacy = data;
158 Eina_Bool inside_call = legacy->inside_call;
159 159
160 legacy->inside_call = 1; 160 legacy->inside_call = 1;
161 if (!_ecore_call_task_cb(legacy->func, (void *)legacy->data) || 161 if (!_ecore_call_task_cb(legacy->func, (void *)legacy->data) || legacy->delete_me)
162 legacy->delete_me) 162 {
163 efl_del(event->object); 163 legacy->delete_me = EINA_TRUE;
164 else legacy->inside_call = 0; 164 /* cannot destroy timer if recursing */
165 if (!inside_call)
166 efl_del(event->object);
167 }
168 /* only unset flag if not currently recursing */
169 else if (!inside_call)
170 legacy->inside_call = 0;
165} 171}
166 172
167EFL_CALLBACKS_ARRAY_DEFINE(legacy_timer, 173EFL_CALLBACKS_ARRAY_DEFINE(legacy_timer,
@@ -172,6 +178,7 @@ EAPI Ecore_Timer *
172ecore_timer_add(double in, Ecore_Task_Cb func, const void *data) 178ecore_timer_add(double in, Ecore_Task_Cb func, const void *data)
173{ 179{
174 Ecore_Timer_Legacy *legacy; 180 Ecore_Timer_Legacy *legacy;
181 Efl_Loop_Timer_Data *td;
175 Eo *timer; 182 Eo *timer;
176 183
177 EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); 184 EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
@@ -186,8 +193,9 @@ ecore_timer_add(double in, Ecore_Task_Cb func, const void *data)
186 legacy->data = data; 193 legacy->data = data;
187 timer = efl_add(MY_CLASS, efl_main_loop_get(), 194 timer = efl_add(MY_CLASS, efl_main_loop_get(),
188 efl_event_callback_array_add(efl_added, legacy_timer(), legacy), 195 efl_event_callback_array_add(efl_added, legacy_timer(), legacy),
189 efl_key_data_set(efl_added, "_legacy", legacy),
190 efl_loop_timer_interval_set(efl_added, in)); 196 efl_loop_timer_interval_set(efl_added, in));
197 td = efl_data_scope_get(timer, MY_CLASS);
198 td->legacy = legacy;
191 return timer; 199 return timer;
192} 200}
193 201
@@ -195,6 +203,7 @@ EAPI Ecore_Timer *
195ecore_timer_loop_add(double in, Ecore_Task_Cb func, const void *data) 203ecore_timer_loop_add(double in, Ecore_Task_Cb func, const void *data)
196{ 204{
197 Ecore_Timer_Legacy *legacy; 205 Ecore_Timer_Legacy *legacy;
206 Efl_Loop_Timer_Data *td;
198 Eo *timer; 207 Eo *timer;
199 208
200 EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); 209 EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
@@ -209,24 +218,26 @@ ecore_timer_loop_add(double in, Ecore_Task_Cb func, const void *data)
209 legacy->data = data; 218 legacy->data = data;
210 timer = efl_add(MY_CLASS, efl_main_loop_get(), 219 timer = efl_add(MY_CLASS, efl_main_loop_get(),
211 efl_event_callback_array_add(efl_added, legacy_timer(), legacy), 220 efl_event_callback_array_add(efl_added, legacy_timer(), legacy),
212 efl_key_data_set(efl_added, "_legacy", legacy),
213 efl_loop_timer_loop_reset(efl_added), 221 efl_loop_timer_loop_reset(efl_added),
214 efl_loop_timer_interval_set(efl_added, in)); 222 efl_loop_timer_interval_set(efl_added, in));
223 td = efl_data_scope_get(timer, MY_CLASS);
224 td->legacy = legacy;
215 return timer; 225 return timer;
216} 226}
217 227
218EAPI void * 228EAPI void *
219ecore_timer_del(Ecore_Timer *timer) 229ecore_timer_del(Ecore_Timer *timer)
220{ 230{
221 Ecore_Timer_Legacy *legacy; 231 Efl_Loop_Timer_Data *td;
222 void *data; 232 void *data;
223 233
224 if (!timer) return NULL; 234 if (!timer) return NULL;
225 EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); 235 EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
226 236
227 legacy = efl_key_data_get(timer, "_legacy"); 237
238 td = efl_data_scope_safe_get(timer, MY_CLASS);
228 // If legacy == NULL, this means double free or something 239 // If legacy == NULL, this means double free or something
229 if (legacy == NULL) 240 if ((!td) || (!td->legacy))
230 { 241 {
231 // Just in case it is an Eo timer, but not a legacy one. 242 // Just in case it is an Eo timer, but not a legacy one.
232 ERR("You are trying to destroy a timer which seems dead already."); 243 ERR("You are trying to destroy a timer which seems dead already.");
@@ -234,8 +245,8 @@ ecore_timer_del(Ecore_Timer *timer)
234 return NULL; 245 return NULL;
235 } 246 }
236 247
237 data = (void *)legacy->data; 248 data = (void *)td->legacy->data;
238 if (legacy->inside_call) legacy->delete_me = EINA_TRUE; 249 if (td->legacy->inside_call) td->legacy->delete_me = EINA_TRUE;
239 else efl_del(timer); 250 else efl_del(timer);
240 return data; 251 return data;
241} 252}
@@ -570,7 +581,8 @@ _efl_loop_timer_next_get(Eo *obj, Efl_Loop_Data *pd)
570static inline void 581static inline void
571_efl_loop_timer_reschedule(Efl_Loop_Timer_Data *timer, double when) 582_efl_loop_timer_reschedule(Efl_Loop_Timer_Data *timer, double when)
572{ 583{
573 if (timer->frozen || efl_invalidated_get(timer->object)) return; 584 if (timer->frozen || efl_invalidated_get(timer->object) ||
585 (timer->legacy && timer->legacy->delete_me)) return;
574 586
575 if (timer->loop_data && 587 if (timer->loop_data &&
576 (EINA_INLIST_GET(timer)->next || EINA_INLIST_GET(timer)->prev)) 588 (EINA_INLIST_GET(timer)->next || EINA_INLIST_GET(timer)->prev))