evas image cache - add lots more locking to try stamp out any thread bug

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
This commit is contained in:
Carsten Haitzler 2017-03-09 11:18:32 +09:00
parent 1a5563ab63
commit d550190d6b
1 changed files with 131 additions and 25 deletions

View 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 *