jpeg pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=c0514d948a1cf56d5fc933ee6502eccf08c0a131
commit c0514d948a1cf56d5fc933ee6502eccf08c0a131 Author: Jean-Philippe Andre <jp.an...@samsung.com> Date: Mon Sep 4 19:08:02 2017 +0900 filters: Safety++ This is an attempt at fixing crashes in empc. Test scenario: ELM_ACCEL="" elementary_test -to "Gfx Filters" And mouse scroll like crazy in the spinner. @fix --- src/lib/evas/canvas/evas_filter_mixin.c | 25 +++++++------ src/lib/evas/canvas/evas_object_textblock.c | 26 ++++++++++---- src/lib/evas/filters/evas_filter.c | 54 ++++++++++++++++++----------- src/lib/evas/filters/evas_filter_private.h | 4 +-- src/lib/evas/include/evas_filter.h | 4 +-- 5 files changed, 73 insertions(+), 40 deletions(-) diff --git a/src/lib/evas/canvas/evas_filter_mixin.c b/src/lib/evas/canvas/evas_filter_mixin.c index 64574b3fd2..2cf3017dce 100644 --- a/src/lib/evas/canvas/evas_filter_mixin.c +++ b/src/lib/evas/canvas/evas_filter_mixin.c @@ -120,13 +120,13 @@ _filter_end_sync(Evas_Filter_Context *ctx, Evas_Object_Protected_Data *obj, if (previous) ENFN->image_free(ENC, previous); - if (destroy) + if (destroy && (ctx == pd->data->context)) { - evas_filter_context_destroy(ctx); - ctx = NULL; + evas_filter_context_unref(ctx); // local ref + FCOW_WRITE(pd, context, NULL); } - FCOW_WRITE(pd, context, ctx); + evas_filter_context_unref(ctx); // run ref efl_unref(eo_obj); } @@ -379,7 +379,7 @@ evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj, if ((!pd->data->reuse) || (was_async != do_async) || (prev_w != W) || (prev_h != H)) { - evas_filter_context_destroy(filter); + evas_filter_context_unref(filter); FCOW_WRITE(pd, context, NULL); filter = NULL; } @@ -390,7 +390,7 @@ evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj, ok = evas_filter_context_program_use(engine, output, filter, pd->data->chain, EINA_TRUE, X, Y); if (!ok) { - evas_filter_context_destroy(filter); + evas_filter_context_unref(filter); FCOW_WRITE(pd, context, NULL); filter = NULL; } @@ -405,8 +405,9 @@ evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj, if (!filter || !ok) { ERR("Parsing failed?"); - evas_filter_context_destroy(filter); + evas_filter_context_unref(filter); FCOW_WRITE(pd, invalid, EINA_TRUE); + FCOW_WRITE(pd, context, NULL); return EINA_FALSE; } } @@ -474,8 +475,8 @@ _efl_canvas_filter_internal_efl_gfx_filter_filter_program_set(Eo *eo_obj, Evas_F { fcow->obj = obj; - if (fcow->context) - evas_filter_context_destroy(fcow->context); + evas_filter_context_unref(fcow->context); + fcow->context = NULL; // Parse filter program evas_filter_program_del(fcow->chain); @@ -710,6 +711,7 @@ EOLIAN static void _efl_canvas_filter_internal_efl_object_destructor(Eo *eo_obj, Evas_Filter_Data *pd) { Evas_Object_Protected_Data *obj; + Evas_Object_Filter_Data *fcow; Evas_Filter_Data_Binding *db; Evas_Public_Data *e; Eina_Inlist *il; @@ -721,7 +723,10 @@ _efl_canvas_filter_internal_efl_object_destructor(Eo *eo_obj, Evas_Filter_Data * e = obj->layer->evas; if (pd->data->context) - evas_filter_context_destroy(pd->data->context); + { + evas_filter_context_unref(pd->data->context); + FCOW_WRITE(pd, context, NULL); + } if (pd->data->output) { diff --git a/src/lib/evas/canvas/evas_object_textblock.c b/src/lib/evas/canvas/evas_object_textblock.c index 57d54bc2ea..b649ad7230 100644 --- a/src/lib/evas/canvas/evas_object_textblock.c +++ b/src/lib/evas/canvas/evas_object_textblock.c @@ -1043,7 +1043,11 @@ _item_free(Evas_Public_Data *evas, ti->gfx_filter = NULL; } else - ti->gfx_filter->ti = NULL; + { + evas_filter_context_unref(ti->gfx_filter->ctx); + ti->gfx_filter->ctx = NULL; + ti->gfx_filter->ti = NULL; + } } } else @@ -12958,6 +12962,7 @@ evas_object_textblock_free(Evas_Object *eo_obj) EINA_INLIST_FREE(o->gfx_filter.programs, prg) { EINA_INLIST_REMOVE(o->gfx_filter.programs, prg); + evas_filter_program_del(prg->pgm); eina_stringshare_del(prg->name); eina_stringshare_del(prg->code); free(prg); @@ -13035,13 +13040,20 @@ _filter_sync_end(Evas_Filter_Context *ctx, Eina_Bool success) if (filter->ti->parent.format->gfx_filter) filter->ti->parent.format->gfx_filter->invalid = !success; // else just avoid sigsegv - filter->ctx = NULL; + if (filter->ctx == ctx) + { + // release local ref + evas_filter_context_unref(ctx); + filter->ctx = NULL; + } } else { free(filter); } - evas_filter_context_destroy(ctx); + + // release run ref + evas_filter_context_unref(ctx); } static void @@ -13158,7 +13170,7 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED, Eina_List *shadows = NULL; Eina_List *glows = NULL; Eina_List *outlines = NULL; - Eina_List *gfx_filters = NULL, *li; + Eina_List *gfx_filters = NULL; void *context_save = context; int strikethrough_thickness, underline_thickness, underline_position; int i, j; @@ -13448,7 +13460,7 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED, * in "_text_item_update_sizes" should not modify one without the other. */ /* gfx filters preparation */ - EINA_LIST_FOREACH(gfx_filters, li, itr) + EINA_LIST_FREE(gfx_filters, itr) { Efl_Canvas_Filter_State state = EFL_CANVAS_FILTER_STATE_DEFAULT; Evas_Object_Textblock_Text_Item *ti = _ITEM_TEXT(itr); @@ -13509,7 +13521,7 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED, ok = evas_filter_context_program_use(engine, output, ctx, pgm, EINA_FALSE, 0, 0); if (!ok) { - evas_filter_context_destroy(ctx); + evas_filter_context_unref(ctx); filter->invalid = EINA_TRUE; continue; } @@ -13524,6 +13536,8 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED, evas_filter_context_proxy_render_all(ctx, eo_obj, output, EINA_FALSE); evas_filter_context_buffers_allocate_all(ctx); evas_filter_target_set(ctx, context, surface, target.x, target.y, NULL); + if (ti->gfx_filter->ctx) + evas_filter_context_unref(ti->gfx_filter->ctx); ti->gfx_filter->ctx = ctx; ti->gfx_filter->do_async = do_async; diff --git a/src/lib/evas/filters/evas_filter.c b/src/lib/evas/filters/evas_filter.c index 0f0a835df7..c83b5e35b0 100644 --- a/src/lib/evas/filters/evas_filter.c +++ b/src/lib/evas/filters/evas_filter.c @@ -38,6 +38,9 @@ static void _filter_buffer_unlock_all(Evas_Filter_Context *ctx); /* Main functions */ +#define _free(ptr) free(ptr) +//eina_freeq_ptr_main_add(ptr, NULL, sizeof(*ptr)) + Evas_Filter_Context * evas_filter_context_new(Evas_Public_Data *evas, Eina_Bool async, void *user_data) { @@ -55,6 +58,7 @@ evas_filter_context_new(Evas_Public_Data *evas, Eina_Bool async, void *user_data ctx->user_data = user_data; ctx->buffer_scaled_get = &evas_filter_buffer_scaled_get; ctx->gl = (ENFN->gl_surface_read_pixels != NULL); + ctx->refcount = 1; return ctx; } @@ -205,26 +209,39 @@ _context_destroy(void *data) { Evas_Filter_Context *ctx = data; + EINA_SAFETY_ON_FALSE_RETURN(ctx->refcount == 0); evas_filter_context_clear(ctx, EINA_FALSE); - free(ctx); + _free(ctx); +} + +int +evas_filter_context_ref(Evas_Filter_Context *ctx) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, -1); + +#ifdef FILTERS_DEBUG + EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_main_loop_is(), -1); + EINA_SAFETY_ON_FALSE_RETURN_VAL(ctx->refcount > 0, -1); +#endif + + return (++ctx->refcount); } void -evas_filter_context_destroy(Evas_Filter_Context *ctx) +evas_filter_context_unref(Evas_Filter_Context *ctx) { if (!ctx) return; #ifdef FILTERS_DEBUG EINA_SAFETY_ON_FALSE_RETURN(eina_main_loop_is()); + EINA_SAFETY_ON_FALSE_RETURN(ctx->refcount > 0); #endif - if (ctx->delete_me) return; - ctx->delete_me = EINA_TRUE; + if ((--ctx->refcount) != 0) return; - if (ctx->running) - evas_post_render_job_add(ctx->evas, _context_destroy, ctx); - else + if (!ctx->running) _context_destroy(ctx); + // else: post_run_cb will be called } void @@ -509,7 +526,7 @@ _buffer_alloc_new(Evas_Filter_Context *ctx, int w, int h, Eina_Bool alpha_only, if (!fb->buffer) { ERR("Failed to create ector buffer!"); - free(fb); + _free(fb); return NULL; } @@ -523,7 +540,7 @@ _buffer_free(Evas_Filter_Buffer *fb) _filter_buffer_backing_free(fb); eina_stringshare_del(fb->source_name); efl_unref(fb->source); - free(fb); + _free(fb); } Evas_Filter_Buffer * @@ -627,10 +644,10 @@ _command_del(Evas_Filter_Context *ctx, Evas_Filter_Command *cmd) ctx->commands = eina_inlist_remove(ctx->commands, EINA_INLIST_GET(cmd)); switch (cmd->mode) { - case EVAS_FILTER_MODE_CURVE: free(cmd->curve.data); break; + case EVAS_FILTER_MODE_CURVE: _free(cmd->curve.data); break; default: break; } - free(cmd); + _free(cmd); } Evas_Filter_Buffer * @@ -1334,7 +1351,7 @@ evas_filter_command_curve_add(Evas_Filter_Context *ctx, cmd = _command_new(ctx, EVAS_FILTER_MODE_CURVE, in, NULL, out); if (!cmd) { - free(copy); + _free(copy); return NULL; } @@ -1559,7 +1576,7 @@ evas_filter_target_set(Evas_Filter_Context *ctx, void *draw_context, ctx->target.color_use = EINA_FALSE; ctx->target.rop = ENFN->context_render_op_get(ENC, draw_context); - free(ctx->target.map); + _free(ctx->target.map); if (!map) ctx->target.map = NULL; else { @@ -1820,9 +1837,7 @@ end: ctx->running = EINA_FALSE; DEBUG_TIME_END(); - if (ctx->post_run.cb) - ctx->post_run.cb(ctx, ctx->post_run.data, ok); - + ctx->post_run.cb(ctx, ctx->post_run.data, ok); return ok; } @@ -1840,7 +1855,7 @@ _filter_thread_run_cb(void *data) Filter_Thread_Data *ftd = data; _filter_chain_run(ftd->engine, ftd->output, ftd->ctx); - free(ftd); + _free(ftd); } static void @@ -1895,6 +1910,7 @@ _filter_obscured_region_calc(Evas_Filter_Context *ctx) Eina_Bool evas_filter_context_run(void *engine, void *output, Evas_Filter_Context *ctx) { + evas_filter_context_ref(ctx); _filter_obscured_region_calc(ctx); ctx->run_count++; @@ -1903,9 +1919,7 @@ evas_filter_context_run(void *engine, void *output, Evas_Filter_Context *ctx) { Filter_Thread_Data *ftd; - ftd = calloc(1, sizeof (Filter_Thread_Data)); - if (!ftd) return EINA_FALSE; - + ftd = calloc(1, sizeof(*ftd)); ftd->engine = engine; ftd->output = output; ftd->ctx = ctx; diff --git a/src/lib/evas/filters/evas_filter_private.h b/src/lib/evas/filters/evas_filter_private.h index 074fdbde2e..698b034b59 100644 --- a/src/lib/evas/filters/evas_filter_private.h +++ b/src/lib/evas/filters/evas_filter_private.h @@ -160,10 +160,10 @@ struct _Evas_Filter_Context Eina_Bool color_use : 1; } target; - int run_count; + short run_count; + short refcount; Eina_Bool running : 1; - Eina_Bool delete_me : 1; Eina_Bool async : 1; Eina_Bool has_proxies : 1; Eina_Bool gl : 1; diff --git a/src/lib/evas/include/evas_filter.h b/src/lib/evas/include/evas_filter.h index 00b9bbf08c..82b3ed6ce7 100644 --- a/src/lib/evas/include/evas_filter.h +++ b/src/lib/evas/include/evas_filter.h @@ -150,11 +150,11 @@ Evas_Filter_Context *evas_filter_context_new(Evas_Public_Data *evas, Eina_Bo void *evas_filter_context_data_get(Evas_Filter_Context *ctx); Eina_Bool evas_filter_context_async_get(Evas_Filter_Context *ctx); void evas_filter_context_size_get(Evas_Filter_Context *ctx, int *w, int *H); -void evas_filter_context_destroy(Evas_Filter_Context *ctx); +int evas_filter_context_ref(Evas_Filter_Context *ctx); +void evas_filter_context_unref(Evas_Filter_Context *ctx); Eina_Bool evas_filter_context_program_use(void *engine, void *output, Evas_Filter_Context *ctx, Evas_Filter_Program *pgm, Eina_Bool reuse, int object_x, int object_y); void evas_filter_context_proxy_render_all(Evas_Filter_Context *ctx, Eo *eo_obj, void *output, Eina_Bool do_async); void evas_filter_context_post_run_callback_set(Evas_Filter_Context *ctx, Evas_Filter_Cb cb, void *data); -#define evas_filter_context_autodestroy(ctx) evas_filter_context_post_run_callback_set(ctx, ((Evas_Filter_Cb) evas_filter_context_destroy), ctx) Eina_Bool evas_filter_context_buffers_allocate_all(Evas_Filter_Context *ctx); void evas_filter_context_obscured_region_set(Evas_Filter_Context *ctx, Eina_Rectangle rect); --