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);
 

-- 


Reply via email to