From d550190d6be8fe4d1ba44042ad8d9c17cf232079 Mon Sep 17 00:00:00 2001 From: "Carsten Haitzler (Rasterman)" Date: Thu, 9 Mar 2017 11:18:32 +0900 Subject: [PATCH] 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 --- src/lib/evas/cache/evas_cache_image.c | 156 +++++++++++++++++++++----- 1 file changed, 131 insertions(+), 25 deletions(-) diff --git a/src/lib/evas/cache/evas_cache_image.c b/src/lib/evas/cache/evas_cache_image.c index a404fadb02..ff958581cf 100644 --- a/src/lib/evas/cache/evas_cache_image.c +++ b/src/lib/evas/cache/evas_cache_image.c @@ -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 *