evas image cache - add lots more locking to try stamp out any thread bug
authorCarsten Haitzler (Rasterman) <raster@rasterman.com>
Thu, 9 Mar 2017 02:18:32 +0000 (11:18 +0900)
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>
Thu, 9 Mar 2017 02:21:19 +0000 (11:21 +0900)
this definitely fixes T5223 because it adds an engine lock around the
code segemtnt that does compare time stamps... and hopefulyl a few
more things too.

@fix

src/lib/evas/cache/evas_cache_image.c

index a404fad..ff95858 100644 (file)
@@ -109,18 +109,14 @@ _evas_cache_image_lru_add(Image_Entry *im)
    if (im->flags.lru) return;
    _evas_cache_image_dirty_del(im);
    _evas_cache_image_activ_del(im);
-   _evas_cache_image_lru_nodata_del(im); 
+   _evas_cache_image_lru_nodata_del(im);
    if (!im->cache_key) return;
    im->flags.lru = 1;
    im->flags.cached = 1;
    if (im->flags.given_mmap)
-     {
-        eina_hash_direct_add(im->cache->mmap_inactiv, im->cache_key, im);
-     }
+     eina_hash_direct_add(im->cache->mmap_inactiv, im->cache_key, im);
    else
-     {
-        eina_hash_direct_add(im->cache->inactiv, im->cache_key, im);
-     }
+     eina_hash_direct_add(im->cache->inactiv, im->cache_key, im);
    im->cache->lru = eina_inlist_prepend(im->cache->lru, EINA_INLIST_GET(im));
    im->cache->usage += im->cache->func.mem_size_get(im);
 }
@@ -133,13 +129,9 @@ _evas_cache_image_lru_del(Image_Entry *im)
    im->flags.lru = 0;
    im->flags.cached = 0;
    if (im->flags.given_mmap)
-     {
-        eina_hash_del(im->cache->mmap_inactiv, im->cache_key, im);
-     }
+     eina_hash_del(im->cache->mmap_inactiv, im->cache_key, im);
    else
-     {
-        eina_hash_del(im->cache->inactiv, im->cache_key, im);
-     }
+     eina_hash_del(im->cache->inactiv, im->cache_key, im);
    im->cache->lru = eina_inlist_remove(im->cache->lru, EINA_INLIST_GET(im));
    im->cache->usage -= im->cache->func.mem_size_get(im);
 }
@@ -171,6 +163,8 @@ _evas_cache_image_entry_delete(Evas_Cache_Image *cache, Image_Entry *ie)
    Image_Entry_Task *task;
 
    if (!ie) return;
+////   SLKL(ie->lock);
+////   SLKU(ie->lock);
    if ((cache) && (cache->func.debug)) cache->func.debug("deleting", ie);
    if (ie->flags.delete_me == 1) return;
    if (ie->preload)
@@ -328,8 +322,12 @@ static Eina_Bool
 evas_cache_image_cancelled(void *data)
 {
    Image_Entry *current = data;
+   Eina_Bool ret;
 
-   return evas_preload_thread_cancelled_is(current->preload);
+   evas_cache_image_ref(current);
+   ret = evas_preload_thread_cancelled_is(current->preload);
+   evas_cache_image_drop(current);
+   return ret;
 }
 
 static void
@@ -402,6 +400,7 @@ _evas_cache_image_async_end(void *data)
    Image_Entry_Task *task;
    Evas_Cache_Target *tmp;
 
+   evas_cache_image_ref(ie);
    ie->cache->preload = eina_list_remove(ie->cache->preload, ie);
    ie->cache->pending = eina_list_remove(ie->cache->pending, ie);
    ie->preload = NULL;
@@ -410,7 +409,6 @@ _evas_cache_image_async_end(void *data)
 
    ie->flags.preload_pending = 0;
 
-   evas_cache_image_ref(ie);
    while ((tmp = ie->targets))
      {
         ie->targets = (Evas_Cache_Target *)
@@ -441,6 +439,7 @@ _evas_cache_image_async_cancel(void *data)
    Evas_Cache_Image *cache = NULL;
    Image_Entry *ie = (Image_Entry *)data;
 
+   evas_cache_image_ref(ie);
    ie->preload = NULL;
    ie->cache->pending = eina_list_remove(ie->cache->pending, ie);
 
@@ -449,7 +448,10 @@ _evas_cache_image_async_cancel(void *data)
    if ((ie->flags.delete_me) || (ie->flags.dirty))
      {
         ie->flags.delete_me = 0;
+        evas_cache_image_drop(ie);
+        SLKL(engine_lock);
         _evas_cache_image_entry_delete(ie->cache, ie);
+        SLKU(engine_lock);
         return;
      }
    SLKL(ie->lock_task);
@@ -466,10 +468,13 @@ _evas_cache_image_async_cancel(void *data)
    SLKU(ie->lock_task);
    if (ie->references == 0)
      {
+        SLKL(engine_lock);
         _evas_cache_image_lru_add(ie);
+        SLKU(engine_lock);
         cache = ie->cache;
      }
    if (ie->flags.loaded) _evas_cache_image_async_end(ie);
+   evas_cache_image_drop(ie);
    if (cache) evas_cache_image_flush(cache);
 }
 
@@ -482,7 +487,12 @@ _evas_cache_image_entry_preload_add(Image_Entry *ie, const Eo *target,
    Evas_Cache_Target *tg;
    Image_Entry_Task *task;
 
-   if (ie->flags.preload_done) return 0;
+   evas_cache_image_ref(ie);
+   if (ie->flags.preload_done)
+     {
+        evas_cache_image_drop(ie);
+        return 0;
+     }
 
    tg = calloc(1, sizeof(Evas_Cache_Target));
    if (!tg) return 0;
@@ -521,6 +531,7 @@ _evas_cache_image_entry_preload_add(Image_Entry *ie, const Eo *target,
                                               _evas_cache_image_async_cancel,
                                               ie);
      }
+   evas_cache_image_drop(ie);
    return 1;
 }
 
@@ -531,6 +542,7 @@ _evas_cache_image_entry_preload_remove(Image_Entry *ie, const Eo *target)
    Eina_List *l;
    Image_Entry_Task *task;
 
+//   evas_cache_image_ref(ie);
    if (target)
      {
         SLKL(ie->lock_task);
@@ -579,6 +591,7 @@ _evas_cache_image_entry_preload_remove(Image_Entry *ie, const Eo *target)
         ie->flags.pending = 1;
         evas_preload_thread_cancel(ie->preload);
      }
+//   evas_cache_image_drop(ie);
 }
 
 EAPI int
@@ -653,6 +666,7 @@ evas_cache_image_shutdown(Evas_Cache_Image *cache)
      }
    evas_async_events_process();
 
+   SLKL(engine_lock);
    EINA_INLIST_FREE(cache->lru, im)
      _evas_cache_image_entry_delete(cache, im);
    EINA_INLIST_FREE(cache->lru_nodata, im)
@@ -665,6 +679,7 @@ evas_cache_image_shutdown(Evas_Cache_Image *cache)
         _evas_cache_image_entry_delete(cache, im);
      }
    delete_list = NULL;
+
    eina_hash_foreach(cache->activ, _evas_cache_image_free_cb, &delete_list);
    eina_hash_foreach(cache->mmap_activ, _evas_cache_image_free_cb, &delete_list);
    while (delete_list)
@@ -672,6 +687,7 @@ evas_cache_image_shutdown(Evas_Cache_Image *cache)
         _evas_cache_image_entry_delete(cache, eina_list_data_get(delete_list));
         delete_list = eina_list_remove_list(delete_list, delete_list);
      }
+   SLKU(engine_lock);
 
    /* Now wait for all pending image to die */
    while (cache->pending)
@@ -822,6 +838,7 @@ evas_cache_image_mmap_request(Evas_Cache_Image *cache,
 
 
    /* find image by key in active mmap hash */
+   SLKL(engine_lock);
    im = eina_hash_find(cache->mmap_activ, hkey);
    if ((im) && (!im->load_failed)) goto on_ok;
    else if ((im) && (im->load_failed))
@@ -848,11 +865,18 @@ evas_cache_image_mmap_request(Evas_Cache_Image *cache,
      }
 
    im = _evas_cache_image_entry_new(cache, hkey, NULL, f, NULL, key, lo, error);
-   if (!im) return NULL;
+   if (!im)
+     {
+        SLKU(engine_lock);
+        return NULL;
+     }
 
  on_ok:
    *error = EVAS_LOAD_ERROR_NONE;
+////   SLKL(im->lock);
    im->references++;
+////   SLKU(im->lock);
+   SLKU(engine_lock);
    return im;
 }
 
@@ -896,6 +920,7 @@ evas_cache_image_request(Evas_Cache_Image *cache, const char *file,
    tlo.skip_head = skip;
 
    /* find image by key in active hash */
+   SLKL(engine_lock);
    im = eina_hash_find(cache->activ, hkey);
    if ((im) && (!im->load_failed))
      {
@@ -990,7 +1015,10 @@ evas_cache_image_request(Evas_Cache_Image *cache, const char *file,
 
 on_ok:
    *error = EVAS_LOAD_ERROR_NONE;
+////   SLKL(im->lock);
    im->references++;
+////   SLKU(im->lock);
+   SLKU(engine_lock);
    return im;
 
 on_stat_error:
@@ -1012,13 +1040,18 @@ on_stat_error:
      else
        *error = EVAS_LOAD_ERROR_GENERIC;
 
+   SLKU(engine_lock);
    return NULL;
 }
 
 EAPI void
 evas_cache_image_ref(Image_Entry *im)
 {
+   SLKL(engine_lock);
+////   SLKL(im->lock);
    im->references++;
+////   SLKU(im->lock);
+   SLKU(engine_lock);
 }
 
 EAPI void
@@ -1027,9 +1060,13 @@ evas_cache_image_drop(Image_Entry *im)
    Evas_Cache_Image *cache;
    int references;
 
+   SLKL(engine_lock);
+////   SLKL(im->lock);
    im->references--;
    if (im->references < 0) im->references = 0;
    references = im->references;
+////   SLKU(im->lock);
+   SLKU(engine_lock);
 
    cache = im->cache;
 
@@ -1042,12 +1079,16 @@ evas_cache_image_drop(Image_Entry *im)
           }
         if ((im->flags.dirty) || (im->load_failed))
           {
+             SLKL(engine_lock);
              _evas_cache_image_entry_delete(cache, im);
+             SLKU(engine_lock);
              return;
           }
         if (cache)
           {
+             SLKL(engine_lock);
              _evas_cache_image_lru_add(im);
+             SLKU(engine_lock);
              evas_cache_image_flush(cache);
           }
      }
@@ -1061,7 +1102,9 @@ evas_cache_image_data_not_needed(Image_Entry *im)
    references = im->references;
    if (references > 1) return;
    if ((im->flags.dirty) || (!im->flags.need_data)) return;
+   SLKL(engine_lock);
    _evas_cache_image_lru_nodata_add(im);
+   SLKU(engine_lock);
 }
 
 EAPI Image_Entry *
@@ -1087,7 +1130,9 @@ evas_cache_image_dirty(Image_Entry *im, unsigned int x, unsigned int y, unsigned
              im_dirty->references = 1;
              evas_cache_image_drop(im);
           }
+        SLKL(engine_lock);
         _evas_cache_image_dirty_add(im_dirty);
+        SLKU(engine_lock);
      }
 
    if (cache->func.debug) cache->func.debug("dirty-region", im_dirty);
@@ -1112,7 +1157,9 @@ evas_cache_image_alone(Image_Entry *im)
 
    if (references <= 1)
      {
+        SLKL(engine_lock);
         if (!im->flags.dirty) _evas_cache_image_dirty_add(im);
+        SLKU(engine_lock);
      }
    else
      {
@@ -1148,14 +1195,18 @@ evas_cache_image_copied_data(Evas_Cache_Image *cache,
        (cspace == EVAS_COLORSPACE_YCBCR422601_PL))
      w &= ~0x1;
 
+   SLKL(engine_lock);
    im = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL, &err);
+   SLKU(engine_lock);
    if (!im) return NULL;
    im->space = cspace;
    im->flags.alpha = alpha;
    _evas_cache_image_entry_surface_alloc(cache, im, w, h);
    if (cache->func.copied_data(im, w, h, image_data, alpha, cspace) != 0)
      {
+        SLKL(engine_lock);
         _evas_cache_image_entry_delete(cache, im);
+        SLKU(engine_lock);
         return NULL;
      }
    im->references = 1;
@@ -1176,14 +1227,18 @@ evas_cache_image_data(Evas_Cache_Image *cache, unsigned int w, unsigned int h,
        (cspace == EVAS_COLORSPACE_YCBCR422601_PL))
      w &= ~0x1;
 
+   SLKL(engine_lock);
    im = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL, &err);
+   SLKU(engine_lock);
    if (!im) return NULL;
    im->w = w;
    im->h = h;
    im->flags.alpha = alpha;
    if (cache->func.data(im, w, h, image_data, alpha, cspace) != 0)
      {
+        SLKL(engine_lock);
         _evas_cache_image_entry_delete(cache, im);
+        SLKU(engine_lock);
         return NULL;
      }
    im->references = 1;
@@ -1213,14 +1268,21 @@ evas_cache_image_size_set(Image_Entry *im, unsigned int w, unsigned int h)
    Image_Entry *im2 = NULL;
    int error;
 
+   evas_cache_image_ref(im);
    if ((im->space == EVAS_COLORSPACE_YCBCR422P601_PL) ||
        (im->space == EVAS_COLORSPACE_YCBCR422P709_PL) ||
        (im->space == EVAS_COLORSPACE_YCBCR422601_PL))
      w &= ~0x1;
-   if ((im->w == w) && (im->h == h)) return im;
+   if ((im->w == w) && (im->h == h))
+     {
+        evas_cache_image_drop(im);
+        return im;
+     }
 
    cache = im->cache;
+   SLKL(engine_lock);
    im2 = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL, &error);
+   SLKU(engine_lock);
    if (!im2) goto on_error;
 
    im2->flags.alpha = im->flags.alpha;
@@ -1233,10 +1295,14 @@ evas_cache_image_size_set(Image_Entry *im, unsigned int w, unsigned int h)
    im2->flags.loaded = EINA_TRUE;
    evas_cache_image_drop(im);
    if (cache->func.debug) cache->func.debug("size_set", im2);
+   evas_cache_image_drop(im);
    return im2;
 
 on_error:
+   SLKL(engine_lock);
    if (im2) _evas_cache_image_entry_delete(cache, im2);
+   SLKU(engine_lock);
+   evas_cache_image_drop(im);
    evas_cache_image_drop(im);
    return NULL;
 }
@@ -1247,7 +1313,12 @@ evas_cache_image_load_data(Image_Entry *im)
    Eina_Bool preload = EINA_FALSE;
    int error = EVAS_LOAD_ERROR_NONE;
 
-   if ((im->flags.loaded) && (!im->animated.animated)) return error;
+   evas_cache_image_ref(im);
+   if ((im->flags.loaded) && (!im->animated.animated))
+     {
+        evas_cache_image_drop(im);
+        return error;
+     }
    evas_common_rgba_pending_unloads_remove(im);
    if (im->preload)
      {
@@ -1269,7 +1340,11 @@ evas_cache_image_load_data(Image_Entry *im)
           }
      }
 
-   if ((im->flags.loaded) && (!im->animated.animated)) return error;
+   if ((im->flags.loaded) && (!im->animated.animated))
+     {
+        evas_cache_image_drop(im);
+        return error;
+     }
 
    SLKL(im->lock);
    im->flags.in_progress = EINA_TRUE;
@@ -1285,20 +1360,27 @@ evas_cache_image_load_data(Image_Entry *im)
         im->flags.loaded = 0;
      }
    if (preload) _evas_cache_image_async_end(im);
+   evas_cache_image_drop(im);
    return error;
 }
 
 EAPI void
 evas_cache_image_unload_data(Image_Entry *im)
 {
-   if (im->flags.in_progress) return;
+   evas_cache_image_ref(im);
+   if (im->flags.in_progress)
+     {
+        evas_cache_image_drop(im);
+        return;
+     }
    evas_cache_image_preload_cancel(im, NULL);
-   
+
    if (SLKT(im->lock) == EINA_FALSE) /* can't get image lock - busy async load */
      {
         SLKL(im->lock_cancel);
         im->flags.unload_cancel = EINA_TRUE;
         SLKU(im->lock_cancel);
+        evas_cache_image_drop(im);
         return;
      }
 
@@ -1308,11 +1390,13 @@ evas_cache_image_unload_data(Image_Entry *im)
      {
         SLKU(im->lock_cancel);
         SLKU(im->lock);
+        evas_cache_image_drop(im);
         return;
      }
    SLKU(im->lock_cancel);
    im->cache->func.destructor(im);
    SLKU(im->lock);
+   evas_cache_image_drop(im);
    //FIXME: imagedataunload - inform owners
 }
 
@@ -1328,10 +1412,14 @@ evas_cache_image_unload_all(Evas_Cache_Image *cache)
 {
    Image_Entry *im;
 
+// _evas_cache_image_unload_cb -> evas_cache_image_unload_data -> evas_cache_image_ref
+//  deadlock
+//////   SLKL(engine_lock);
    EINA_INLIST_FOREACH(cache->lru, im) evas_cache_image_unload_data(im);
    EINA_INLIST_FOREACH(cache->lru_nodata, im) evas_cache_image_unload_data(im);
    eina_hash_foreach(cache->activ, _evas_cache_image_unload_cb, NULL);
    eina_hash_foreach(cache->inactiv, _evas_cache_image_unload_cb, NULL);
+//////   SLKU(engine_lock);
 }
 
 static int async_frozen = 0;
@@ -1367,6 +1455,7 @@ evas_cache_image_preload_data(Image_Entry *im, const Eo *target,
 {
    RGBA_Image *img = (RGBA_Image *)im;
 
+   evas_cache_image_ref(im);
    if (((int)im->w > 0) && ((int)im->h > 0) &&
        (((im->flags.loaded) && (img->image.data)) ||
         (im->flags.textured && !im->flags.updated_data)))
@@ -1388,18 +1477,22 @@ evas_cache_image_preload_data(Image_Entry *im, const Eo *target,
              free(tmp);
           }
         evas_object_inform_call_image_preloaded((Evas_Object*)target);
+        evas_cache_image_drop(im);
         return;
      }
    im->flags.loaded = 0;
    if (!_evas_cache_image_entry_preload_add(im, target, func, engine_data, custom_data))
      evas_object_inform_call_image_preloaded((Evas_Object*) target);
+   evas_cache_image_drop(im);
 }
 
 EAPI void
 evas_cache_image_preload_cancel(Image_Entry *im, const Eo *target)
 {
    if (!target) return;
+   evas_cache_image_ref(im);
    _evas_cache_image_entry_preload_remove(im, target);
+   evas_cache_image_drop(im);
 }
 
 #ifdef CACHEDUMP
@@ -1436,6 +1529,7 @@ _dump_cache(Evas_Cache_Image *cache)
           cache->limit / 1024);
    printf("................................................................\n");
    total = 0;
+   SLKL(engine_lock);
    EINA_INLIST_FOREACH(cache->lru_nodata, im)
       _dump_img(im, "NODATA");
    EINA_INLIST_FOREACH(cache->lru, im)
@@ -1445,6 +1539,7 @@ _dump_cache(Evas_Cache_Image *cache)
           total,
           cache->usage);
    eina_hash_foreach(cache->activ, _dump_cache_active, NULL);
+   SLKU(engine_lock);
 }
 #endif
 
@@ -1456,6 +1551,7 @@ evas_cache_image_flush(Evas_Cache_Image *cache)
 #endif  
    if (cache->limit == (unsigned int)-1) return -1;
 
+   SLKL(engine_lock);
    while ((cache->lru) && (cache->limit < (unsigned int)cache->usage))
      {
         Image_Entry *im;
@@ -1475,6 +1571,7 @@ evas_cache_image_flush(Evas_Cache_Image *cache)
         cache->func.surface_delete(im);
         im->flags.loaded = 0;
      }
+   SLKU(engine_lock);
 
    return cache->usage;
 }
@@ -1485,7 +1582,9 @@ evas_cache_image_empty(Evas_Cache_Image *cache)
    int err;
    Image_Entry *im;
 
+   SLKL(engine_lock);
    im = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL, &err);
+   SLKU(engine_lock);
    if (!im) return NULL;
    im->references = 1;
    return im;
@@ -1494,16 +1593,23 @@ evas_cache_image_empty(Evas_Cache_Image *cache)
 EAPI void
 evas_cache_image_colorspace(Image_Entry *im, Evas_Colorspace cspace)
 {
-   if (im->space == cspace) return;
+   evas_cache_image_ref(im);
+   if (im->space == cspace) goto done;
    im->space = cspace;
-   if (!im->cache) return;
+   if (!im->cache) goto done;
    im->cache->func.color_space(im, cspace);
+done:
+   evas_cache_image_drop(im);
 }
 
 EAPI void *
 evas_cache_private_from_image_entry_get(Image_Entry *im)
 {
-   return (void *)im->cache->data;
+   void *data;
+   evas_cache_image_ref(im);
+   data = (void *)im->cache->data;
+   evas_cache_image_drop(im);
+   return data;
 }
 
 EAPI void *