#endif
#ifdef BUILD_ASYNC_PRELOAD
-#include <pthread.h>
-
typedef struct _Evas_Cache_Preload Evas_Cache_Preload;
struct _Evas_Cache_Preload
Image_Entry *ie;
};
-static Eina_Inlist *preload = NULL;
-static Image_Entry *current = NULL;
-static Eina_List *pending = NULL;
-
-static pthread_cond_t cond_done = PTHREAD_COND_INITIALIZER;
-static pthread_cond_t cond_new = PTHREAD_COND_INITIALIZER;
-static pthread_mutex_t mutex_new = PTHREAD_MUTEX_INITIALIZER;
-static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_mutex_t mutex_pending = PTHREAD_MUTEX_INITIALIZER;
-static pthread_mutex_t mutex_surface_alloc = PTHREAD_MUTEX_INITIALIZER;
-static pthread_t tid = 0;
+static LK(engine_lock) = PTHREAD_MUTEX_INITIALIZER;
+static LK(wakeup) = PTHREAD_MUTEX_INITIALIZER;
-static Eina_Bool running = EINA_FALSE;
+static pthread_cond_t cond_wakeup = PTHREAD_COND_INITIALIZER;
-static void *_evas_cache_background_load(void *);
-static void _evas_cache_image_entry_clear_preloaders(Image_Entry *ie);
-static int _evas_cache_image_entry_preload_remove(Image_Entry *ie, const void *target);
+static void _evas_cache_image_entry_preload_remove(Image_Entry *ie, const void *target);
#endif
#define FREESTRC(Var) \
Image_Entry *im,
const char *key)
{
-#ifdef BUILD_ASYNC_PRELOAD
- pthread_mutex_lock(&mutex);
- if (im->flags.pending)
- {
- im->flags.pending = 0;
- pending = eina_list_remove(pending, im);
- }
- pthread_mutex_unlock(&mutex);
-#endif
-
+ /* FIXME: Handle case when image is being processed anyway and don't do a double decode. */
im->cache_key = key;
if (key != NULL)
{
if (cache->func.debug)
cache->func.debug("deleting", ie);
+ if (ie->flags.delete_me == 1)
+ return ;
+
#ifdef BUILD_ASYNC_PRELOAD
- _evas_cache_image_entry_preload_remove(ie, NULL);
+ if (ie->preload)
+ {
+ ie->flags.delete_me = 1;
+
+ _evas_cache_image_entry_preload_remove(ie, NULL);
+ return ;
+ }
#endif
cache->func.destructor(ie);
#ifdef BUILD_ASYNC_PRELOAD
LKI(ie->lock);
ie->targets = NULL;
+ ie->preload = NULL;
+ ie->flags.delete_me = 0;
#endif
if (lo)
hmin = h > 0 ? h : 1;
#ifdef BUILD_ASYNC_PRELOAD
- pthread_mutex_lock(&mutex_surface_alloc);
+ LKL(engine_lock);
#endif
_evas_cache_image_entry_surface_alloc__locked(cache, ie, wmin, hmin);
#ifdef BUILD_ASYNC_PRELOAD
- pthread_mutex_unlock(&mutex_surface_alloc);
+ LKU(engine_lock);
#endif
}
#ifdef BUILD_ASYNC_PRELOAD
static void
-_evas_cache_image_async_call_process(void *obj, Evas_Callback_Type type, void *data)
+_evas_cache_image_async_heavy(void *data)
+{
+ Evas_Cache_Image *cache;
+ Image_Entry *current;
+ int error;
+ int pchannel;
+
+ current = data;
+
+ LKL(current->lock);
+ pchannel = current->channel;
+ current->channel++;
+ cache = current->cache;
+
+ if (!current->flags.loaded)
+ {
+ error = cache->func.load(current);
+ if (cache->func.debug)
+ cache->func.debug("load", current);
+ if (error)
+ {
+ current->flags.loaded = 0;
+ _evas_cache_image_entry_surface_alloc(cache, current,
+ current->w, current->h);
+ }
+ else
+ current->flags.loaded = 1;
+ }
+
+ current->channel = pchannel;
+ LKU(current->lock);
+}
+
+static void
+_evas_cache_image_async_end(void *data)
{
- Image_Entry *ie = (Image_Entry *) obj;
+ Image_Entry *ie = (Image_Entry *) data;
+ Evas_Cache_Target *tmp;
+
+ ie->cache->preload = eina_list_remove(ie->cache->preload, ie);
+ ie->cache->pending = eina_list_remove(ie->cache->pending, ie);
- ie->flags.in_pipe = 0;
+ ie->preload = NULL;
+ ie->flags.preload_done = 1;
while (ie->targets)
{
- Evas_Cache_Target *tmp = ie->targets;
+ tmp = ie->targets;
- evas_object_event_callback_call((Evas_Object*) tmp->target, EVAS_CALLBACK_IMAGE_PRELOADED, NULL);
+ evas_object_inform_call_image_preloaded((Evas_Object*) tmp->target);
ie->targets = (Evas_Cache_Target*) eina_inlist_remove(EINA_INLIST_GET(ie->targets), EINA_INLIST_GET(ie->targets));
free(tmp);
}
}
static void
-_evas_cache_image_entry_clear_preloaders(Image_Entry *ie)
+_evas_cache_image_async_cancel(void *data)
{
- ie->flags.preload = 0;
- ie->flags.in_pipe = 0;
- evas_async_target_del(ie);
-}
+ Image_Entry *ie = (Image_Entry *) data;
-static void
-_evas_cache_image_async_call__locked(Image_Entry *im)
-{
- evas_async_events_put(im, EVAS_CALLBACK_IMAGE_PRELOADED, NULL,
- _evas_cache_image_async_call_process);
-}
+ ie->preload = NULL;
+ ie->cache->pending = eina_list_remove(ie->cache->pending, ie);
-static void
-_evas_cache_image_async_call(Image_Entry *im)
-{
- pthread_mutex_lock(&mutex);
- _evas_cache_image_async_call__locked(im);
- pthread_mutex_unlock(&mutex);
+ if (ie->flags.delete_me || ie->flags.dirty)
+ {
+ ie->flags.delete_me = 0;
+ _evas_cache_image_entry_delete(ie->cache, ie);
+
+ return ;
+ }
+
+ if (ie->flags.loaded)
+ {
+ _evas_cache_image_async_end(ie);
+ }
+
+ if (ie->references == 0)
+ {
+ _evas_cache_image_remove_activ(ie->cache, ie);
+ _evas_cache_image_make_inactiv(ie->cache, ie, ie->cache_key);
+ evas_cache_image_flush(ie->cache);
+ }
}
static int
const void *target)
{
Evas_Cache_Target *tg;
- int ret = 0;
-
- pthread_mutex_lock(&mutex);
- if (!ie->flags.loaded)
- {
- tg = malloc(sizeof (Evas_Cache_Target));
- if (!tg) goto end;
+ if (ie->flags.preload_done) return 0;
- tg->target = target;
- ie->targets = (Evas_Cache_Target*) eina_inlist_append(EINA_INLIST_GET(ie->targets), EINA_INLIST_GET(tg));
+ tg = malloc(sizeof (Evas_Cache_Target));
+ if (!tg) return 0;
- if (!ie->flags.preload)
- {
- Evas_Cache_Preload *tmp;
+ tg->target = target;
- tmp = malloc(sizeof (Evas_Cache_Preload));
- if (!tmp) goto end;
+ ie->targets = (Evas_Cache_Target*) eina_inlist_append(EINA_INLIST_GET(ie->targets), EINA_INLIST_GET(tg));
- tmp->ie = ie;
- preload = eina_inlist_append(preload, EINA_INLIST_GET(tmp));
+ if (!ie->preload) {
+ ie->cache->preload = eina_list_append(ie->cache->preload, ie);
+ ie->flags.pending = 0;
- ie->flags.preload = 1;
- if (ie->flags.pending)
- {
- ie->flags.pending = 0;
- pending = eina_list_remove(pending, ie);
- }
+ ie->preload = evas_preload_thread_run(_evas_cache_image_async_heavy,
+ _evas_cache_image_async_end,
+ _evas_cache_image_async_cancel,
+ ie);
+ }
- if (!running)
- {
- if (tid)
- {
- running = EINA_TRUE;
- pthread_cond_signal(&cond_new);
- }
- else
- {
- if (pthread_create(&tid, NULL, _evas_cache_background_load, NULL) == 0)
- running = EINA_TRUE;
- }
- }
-
- ret = 2;
- }
- ret = 1;
- }
-
- end:
- pthread_mutex_unlock(&mutex);
-
- return ret;
+ return 1;
}
-static int
+static void
_evas_cache_image_entry_preload_remove(Image_Entry *ie, const void *target)
{
- int ret = 0;
-
- pthread_mutex_lock(&mutex);
if (target)
{
Evas_Cache_Target *tg;
}
}
}
-
- if (ie->flags.in_pipe)
- {
- if (!ie->targets)
- _evas_cache_image_entry_clear_preloaders(ie);
- }
- else if (ie->flags.preload)
- {
- if (current == ie)
- {
-// dont wait. simply handle "ie->flags.preload" nicely
-// /* Wait until ie is processed. */
-// pthread_cond_wait(&cond_done, &mutex);
- }
- else
- {
- Evas_Cache_Preload *l;
-
- EINA_INLIST_FOREACH(preload, l)
- {
- if (l->ie == ie)
- {
- if (target)
- {
- // FIXME: No callback when we cancel only for one target ?
- if (!ie->targets)
- _evas_cache_image_entry_clear_preloaders(ie);
- }
- else
- {
- _evas_cache_image_async_call__locked(ie);
- }
-
- if (!ie->targets)
- {
- ie->flags.preload = 0;
- preload = eina_inlist_remove(preload,
- EINA_INLIST_GET(l));
- free(l);
- }
-
- break;
- }
- }
- ret = 1;
- }
- }
- pthread_mutex_unlock(&mutex);
-
- return ret;
-}
-
-static void*
-_evas_cache_background_load(void *data)
-{
- (void) data;
-
- restart:
- while (preload)
+ else
{
- pthread_mutex_lock(&mutex);
- if (preload)
- {
- Evas_Cache_Preload *tmp = (Evas_Cache_Preload*) preload;
-
- current = tmp->ie;
- preload = eina_inlist_remove(preload, preload);
-
- free(tmp);
- }
-
- pthread_mutex_unlock(&mutex);
+ Evas_Cache_Target *tg;
- if (current)
+ while (ie->targets)
{
- Evas_Cache_Image *cache;
- int error;
- int pchannel;
-
- LKL(current->lock);
- pchannel = current->channel;
- current->channel++;
- cache = current->cache;
+ tg = ie->targets;
- if (!current->flags.loaded)
- {
- error = cache->func.load(current);
- if (cache->func.debug)
- cache->func.debug("load", current);
- if (error)
- {
- _evas_cache_image_entry_surface_alloc
- (cache, current, current->w, current->h);
- current->flags.loaded = 0;
- }
- else
- current->flags.loaded = 1;
- }
-
- pthread_mutex_lock(&mutex);
- pthread_mutex_lock(&mutex_pending);
- current->flags.preload = 0;
- current->flags.in_pipe = 1;
- current->channel = pchannel;
- LKU(current->lock);
- pthread_mutex_unlock(&mutex_pending);
- pthread_mutex_unlock(&mutex);
-
- _evas_cache_image_async_call(current);
-
- pthread_mutex_lock(&mutex);
- current = NULL;
- pthread_mutex_unlock(&mutex);
+ ie->targets = (Evas_Cache_Target*) eina_inlist_remove(EINA_INLIST_GET(ie->targets), EINA_INLIST_GET(tg));
+ free(tg);
}
-
- pthread_cond_signal(&cond_done);
}
- pthread_mutex_lock(&mutex);
- if (preload)
+ if (ie->targets == NULL && ie->preload && !ie->flags.pending)
{
- pthread_mutex_unlock(&mutex);
- goto restart;
- }
-
- running = EINA_FALSE;
- pthread_mutex_unlock(&mutex);
+ ie->cache->preload = eina_list_remove(ie->cache->preload, ie);
+ ie->cache->pending = eina_list_append(ie->cache->pending, ie);
- pthread_mutex_lock(&mutex_new);
- pthread_cond_wait(&cond_new, &mutex_new);
- pthread_mutex_unlock(&mutex_new);
- goto restart;
+ ie->flags.pending = 1;
- return NULL;
+ evas_preload_thread_cancel(ie->preload);
+ }
}
#endif
new->references = 1;
+ new->preload = NULL;
+ new->pending = NULL;
+
return new;
}
EAPI void
evas_cache_image_shutdown(Evas_Cache_Image *cache)
{
- Image_Entry *im;
Eina_List *delete_list;
+ Image_Entry *im;
assert(cache != NULL);
cache->references--;
return ;
#ifdef BUILD_ASYNC_PRELOAD
- pthread_mutex_lock(&mutex);
-
- Eina_Inlist *l, *l_next;
- for (l = preload; l != NULL; l = l_next)
+ EINA_LIST_FREE(cache->preload, im)
{
- Evas_Cache_Preload *tmp = (Evas_Cache_Preload *)l;
- Image_Entry *ie = tmp->ie;
-
- l_next = l->next;
-
- if (ie->cache != cache)
- continue;
-
- preload = eina_inlist_remove(preload, l);
- _evas_cache_image_entry_clear_preloaders(ie);
- free(l);
+ /* By doing that we are protecting us from destroying image when the cache is no longuer available. */
+ im->flags.delete_me = 1;
+ _evas_cache_image_entry_preload_remove(im, NULL);
}
- if (current && current->cache == cache)
- _evas_cache_image_entry_clear_preloaders(current);
- pthread_mutex_unlock(&mutex);
+ evas_async_events_process();
#endif
while (cache->lru)
delete_list = eina_list_remove_list(delete_list, delete_list);
}
+#ifdef BUILD_ASYNC_PRELOAD
+ /* Now wait for all pending image to die */
+ while (cache->pending)
+ {
+ evas_async_events_process();
+
+ LKL(wakeup);
+ if (cache->pending)
+ pthread_cond_wait(&cond_wakeup, &wakeup);
+ LKU(wakeup);
+ }
+#endif
+
eina_hash_free(cache->activ);
eina_hash_free(cache->inactiv);
}
EAPI void
-evas_cache_pending_process(void)
-{
- Image_Entry *im;
-
-#ifdef BUILD_ASYNC_PRELOAD
- pthread_mutex_lock(&mutex_pending);
- EINA_LIST_FREE(pending, im)
- {
- Evas_Cache_Image *cache = im->cache;
-
- if (!im->flags.pending) continue;
- im->flags.pending = 0;
- if (im->flags.preload) continue;
-
- if (im->flags.activ)
- {
- if (im->flags.dirty)
- {
- _evas_cache_image_entry_delete(cache, im);
- }
- else
- {
- _evas_cache_image_remove_activ(cache, im);
- _evas_cache_image_make_inactiv(cache, im, im->cache_key);
- evas_cache_image_flush(cache);
- }
- }
- else if (im->flags.cached)
- {
- evas_cache_image_flush(cache);
- }
- }
- pthread_mutex_unlock(&mutex_pending);
-#endif
-}
-
-EAPI void
evas_cache_image_drop(Image_Entry *im)
{
Evas_Cache_Image *cache;
if (im->references == 0)
{
#ifdef BUILD_ASYNC_PRELOAD
- if (!im->flags.pending)
+ if (im->preload)
{
- pthread_mutex_lock(&mutex);
- if (im->flags.preload || im->flags.in_pipe)
- {
- pthread_mutex_unlock(&mutex);
- _evas_cache_image_entry_preload_remove(im, NULL);
- pthread_mutex_lock(&mutex_pending);
- if (!im->flags.pending)
- {
- im->flags.pending = 1;
- pending = eina_list_append(pending, im);
- }
- pthread_mutex_unlock(&mutex_pending);
- return;
- }
- pthread_mutex_unlock(&mutex);
+ _evas_cache_image_entry_preload_remove(im, NULL);
+ return ;
}
#endif
_evas_cache_image_entry_delete(cache, im);
return;
}
-
+
_evas_cache_image_remove_activ(cache, im);
_evas_cache_image_make_inactiv(cache, im, im->cache_key);
evas_cache_image_flush(cache);
EAPI void
evas_cache_image_load_data(Image_Entry *im)
{
- Evas_Cache_Image *cache;
- int error, preload;
+#ifdef BUILD_ASYNC_PRELOAD
+ Eina_Bool preload = EINA_FALSE;
+#endif
+ Evas_Cache_Image *cache;
+ int error;
assert(im);
assert(im->cache);
{
return;
}
+
#ifdef BUILD_ASYNC_PRELOAD
- pthread_mutex_lock(&mutex);
- preload = im->flags.preload;
- /* We check a first time, to prevent useless lock. */
- if (preload)
+ if (im->preload)
{
- if (current == im)
- {
- /* Wait until ie is processed. */
- pthread_cond_wait(&cond_done, &mutex);
- }
+ preload = EINA_TRUE;
+
+ if (!im->flags.pending)
+ {
+ im->cache->preload = eina_list_remove(im->cache->preload, im);
+ im->cache->pending = eina_list_append(im->cache->pending, im);
+ im->flags.pending = 1;
+
+ evas_preload_thread_cancel(im->preload);
+ }
+
+ evas_async_events_process();
+
+ LKL(wakeup);
+ while (im->preload)
+ {
+ pthread_cond_wait(&cond_wakeup, &wakeup);
+ LKU(wakeup);
+
+ evas_async_events_process();
+
+ LKL(wakeup);
+ }
+ LKU(wakeup);
}
- pthread_mutex_unlock(&mutex);
-// _evas_cache_image_entry_preload_remove(im, NULL);
+
if (im->flags.loaded) return ;
LKL(im->lock);
#endif
LKU(im->lock);
#endif
+ im->flags.loaded = 1;
+
if (cache->func.debug)
cache->func.debug("load", im);
-#ifdef BUILD_ASYNC_PRELOAD
- if (preload)
- _evas_cache_image_async_call(im);
-#endif
if (error)
{
_evas_cache_image_entry_surface_alloc(cache, im, im->w, im->h);
im->flags.loaded = 0;
- return ;
}
- im->flags.loaded = 1;
+#ifdef BUILD_ASYNC_PRELOAD
+ if (preload)
+ _evas_cache_image_async_end(im);
+#endif
}
EAPI void
if (im->flags.loaded)
{
- evas_object_event_callback_call((Evas_Object*) target, EVAS_CALLBACK_IMAGE_PRELOADED, NULL);
+ evas_object_inform_call_image_preloaded((Evas_Object*) target);
return ;
}
cache = im->cache;
if (!_evas_cache_image_entry_preload_add(im, target))
- evas_object_event_callback_call((Evas_Object*) target, EVAS_CALLBACK_IMAGE_PRELOADED, NULL);
+ evas_object_inform_call_image_preloaded((Evas_Object*) target);
#else
evas_cache_image_load_data(im);
- evas_object_event_callback_call((Evas_Object*) target, EVAS_CALLBACK_IMAGE_PRELOADED, NULL);
+ evas_object_inform_call_image_preloaded((Evas_Object*) target);
#endif
}
if (target == NULL) return ;
_evas_cache_image_entry_preload_remove(im, target);
-
- pthread_mutex_lock(&mutex_pending);
- if (!im->flags.pending && im->flags.in_pipe)
- {
- im->flags.pending = 1;
- pending = eina_list_append(pending, im);
- }
- pthread_mutex_unlock(&mutex_pending);
-
#else
(void) im;
#endif
return cache->func.surface_pixels(im);
}
+
+EAPI void
+evas_cache_image_wakeup(void)
+{
+#ifdef BUILD_ASYNC_PRELOAD
+ pthread_cond_broadcast(&cond_wakeup);
+#endif
+}
--- /dev/null
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#ifdef BUILD_ASYNC_PRELOAD
+# include <pthread.h>
+#endif
+
+#include "evas_common.h"
+#include "evas_private.h"
+#include "Evas.h"
+
+#ifdef BUILD_ASYNC_PRELOAD
+typedef struct _Evas_Preload_Pthread_Worker Evas_Preload_Pthread_Worker;
+typedef struct _Evas_Preload_Pthread_Data Evas_Preload_Pthread_Data;
+
+struct _Evas_Preload_Pthread_Worker
+{
+ void (*func_heavy)(void *data);
+ void (*func_end)(void *data);
+ void (*func_cancel)(void *data);
+
+ const void *data;
+
+ Eina_Bool cancel : 1;
+};
+
+struct _Evas_Preload_Pthread_Data
+{
+ pthread_t thread;
+};
+#endif
+
+static int _evas_preload_thread_count_max = 0;
+
+#ifdef BUILD_ASYNC_PRELOAD
+static int _evas_preload_thread_count = 0;
+static Eina_List *_evas_preload_thread_data = NULL;
+static Eina_List *_evas_preload_thread = NULL;
+
+static LK(_mutex) = PTHREAD_MUTEX_INITIALIZER;
+
+static void
+_evas_preload_thread_end(Evas_Preload_Pthread_Data *pth)
+{
+ Evas_Preload_Pthread_Data *p;
+
+ if (pthread_join(pth->thread, (void**) &p) != 0)
+ return ;
+
+ _evas_preload_thread = eina_list_remove(_evas_preload_thread, pth);
+}
+
+static void
+_evas_preload_thread_done(void *target, Evas_Callback_Type type, void *event_info)
+{
+ Evas_Preload_Pthread_Worker *work;
+
+ work = event_info;
+
+ if (work->cancel)
+ {
+ if (work->func_cancel)
+ work->func_cancel((void*) work->data);
+ }
+ else
+ {
+ work->func_end((void*) work->data);
+ }
+
+ free(work);
+}
+
+static void *
+_evas_preload_thread_worker(Evas_Preload_Pthread_Data *pth)
+{
+ Evas_Preload_Pthread_Worker *work;
+
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+ pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+
+ on_error:
+
+ while (_evas_preload_thread_data)
+ {
+ LKL(_mutex);
+
+ if (!_evas_preload_thread_data)
+ {
+ LKU(_mutex);
+ break;
+ }
+
+ work = eina_list_data_get(_evas_preload_thread_data);
+ _evas_preload_thread_data = eina_list_remove_list(_evas_preload_thread_data, _evas_preload_thread_data);
+
+ LKU(_mutex);
+
+ work->func_heavy((void*) work->data);
+
+ evas_async_events_put(pth, 0, work, _evas_preload_thread_done);
+ }
+
+ LKL(_mutex);
+ if (_evas_preload_thread_data)
+ {
+ LKU(_mutex);
+ goto on_error;
+ }
+ _evas_preload_thread_count--;
+
+ LKU(_mutex);
+
+ work = malloc(sizeof (Evas_Preload_Pthread_Worker));
+ if (!work) return NULL;
+
+ work->data = pth;
+ work->func_heavy = NULL;
+ work->func_end = (void*) _evas_preload_thread_end;
+ work->func_cancel = NULL;
+ work->cancel = EINA_FALSE;
+
+ evas_async_events_put(pth, 0, work, _evas_preload_thread_done);
+
+ return pth;
+}
+#endif
+
+void
+_evas_preload_thread_init(void)
+{
+ _evas_preload_thread_count_max = eina_cpu_count();
+ if (_evas_preload_thread_count_max <= 0)
+ _evas_preload_thread_count_max = 1;
+}
+
+void
+_evas_preload_thread_shutdown(void)
+{
+ /* FIXME: If function are still running in the background, should we kill them ? */
+#ifdef BUILD_ASYNC_PRELOAD
+ Evas_Preload_Pthread_Worker *work;
+ Evas_Preload_Pthread_Data *pth;
+
+ /* Force processing of async events. */
+ evas_async_events_process();
+
+ LKL(_mutex);
+
+ EINA_LIST_FREE(_evas_preload_thread_data, work)
+ {
+ if (work->func_cancel)
+ work->func_cancel((void*)work->data);
+ free(work);
+ }
+
+ LKU(_mutex);
+
+ EINA_LIST_FREE(_evas_preload_thread, pth)
+ {
+ Evas_Preload_Pthread_Data *p;
+
+ pthread_cancel(pth->thread);
+ pthread_join(pth->thread, (void **) &p);
+ }
+#endif
+}
+
+Evas_Preload_Pthread *
+evas_preload_thread_run(void (*func_heavy)(void *data),
+ void (*func_end)(void *data),
+ void (*func_cancel)(void *data),
+ const void *data)
+{
+#ifdef BUILD_ASYNC_PRELOAD
+ Evas_Preload_Pthread_Worker *work;
+ Evas_Preload_Pthread_Data *pth;
+
+ work = malloc(sizeof (Evas_Preload_Pthread_Worker));
+ if (!work) return NULL;
+
+ work->func_heavy = func_heavy;
+ work->func_end = func_end;
+ work->func_cancel = func_cancel;
+ work->cancel = EINA_FALSE;
+ work->data = data;
+
+ LKL(_mutex);
+ _evas_preload_thread_data = eina_list_append(_evas_preload_thread_data, work);
+
+ if (_evas_preload_thread_count == _evas_preload_thread_count_max)
+ {
+ pthread_mutex_unlock(&_mutex);
+ return (Evas_Preload_Pthread*) work;
+ }
+
+ LKU(_mutex);
+
+ /* One more thread could be created. */
+ pth = malloc(sizeof (Evas_Preload_Pthread_Data));
+ if (!pth)
+ goto on_error;
+
+ if (pthread_create(&pth->thread, NULL, (void*) _evas_preload_thread_worker, pth) == 0)
+ {
+ LKL(_mutex);
+ _evas_preload_thread_count++;
+ LKU(_mutex);
+ return (Evas_Preload_Pthread*) work;
+ }
+
+ on_error:
+ if (_evas_preload_thread_count == 0)
+ {
+ if (work->func_cancel)
+ work->func_cancel((void*) work->data);
+ free(work);
+ }
+ return NULL;
+#else
+ /*
+ If no thread and as we don't want to break app that rely on this
+ facility, we will lock the interface until we are done.
+ */
+ func_heavy((void*) data);
+ func_end((void*) data);
+
+ return EINA_TRUE;
+#endif
+}
+
+Eina_Bool
+evas_preload_thread_cancel(Evas_Preload_Pthread *thread)
+{
+#ifdef BUILD_ASYNC_PRELOAD
+ Evas_Preload_Pthread_Worker *work;
+ Eina_List *l;
+
+ LKL(_mutex);
+
+ EINA_LIST_FOREACH(_evas_preload_thread_data, l, work)
+ if ((void*) work == (void*) thread)
+ {
+ _evas_preload_thread_data = eina_list_remove_list(_evas_preload_thread_data, l);
+
+ LKU(_mutex);
+
+ if (work->func_cancel)
+ work->func_cancel((void*) work->data);
+ free(work);
+
+ return EINA_TRUE;
+ }
+
+ LKU(_mutex);
+
+ /* Delay the destruction */
+ work = (Evas_Preload_Pthread_Worker *) thread;
+ work->cancel = EINA_TRUE;
+ return EINA_FALSE;
+#else
+ return EINA_TRUE;
+#endif
+}
static int _fd_read = -1;
static int _init_evas_event = 0;
-static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER;
typedef struct _Evas_Event_Async Evas_Event_Async;
Evas_Callback_Type type;
};
-static int queue_num = 0;
-static int queue_alloc = 0;
-static Evas_Event_Async *queue = NULL;
-
int
evas_async_events_init(void)
{
int filedes[2];
-
+
_init_evas_event++;
if (_init_evas_event > 1) return _init_evas_event;
-
+
if (pipe(filedes) == -1)
{
_init_evas_event = 0;
return 0;
}
-
+
_fd_read = filedes[0];
_fd_write = filedes[1];
-
+
fcntl(_fd_read, F_SETFL, O_NONBLOCK);
-
+
return _init_evas_event;
}
{
_init_evas_event--;
if (_init_evas_event > 0) return _init_evas_event;
-
+
close(_fd_read);
close(_fd_write);
_fd_read = -1;
return _init_evas_event;
}
-int
-evas_async_target_del(const void *target)
-{
- int i, j, d = 0;
-
- pthread_mutex_lock(&_mutex);
- if (queue)
- {
- for (i = 0; i < queue_num; i++)
- {
- if (queue[i].target == target)
- {
- for (j = i + 1; j < queue_num; j++)
- memcpy(&(queue[j - 1]), &(queue[j]), sizeof(Evas_Event_Async));
- i--;
- queue_num--;
- d++;
- }
- }
- if (queue_num == 0)
- {
- free(queue);
- queue = NULL;
- queue_alloc = 0;
- }
- }
- pthread_mutex_unlock(&_mutex);
- return d;
-}
-
#endif
/**
{
#ifdef BUILD_ASYNC_EVENTS
Evas_Event_Async *ev;
- unsigned char buf[1];
- int i;
int check;
int count = 0;
- int myqueue_num = 0;
- int myqueue_alloc = 0;
- Evas_Event_Async *myqueue = NULL;
-
+
if (_fd_read == -1) return 0;
-
- pthread_mutex_lock(&_mutex);
- do
- {
- check = read(_fd_read, buf, 1);
- }
- while (check > 0);
-
- if (queue)
- {
- myqueue_num = queue_num;
- myqueue_alloc = queue_alloc;
- myqueue = queue;
- queue_num = 0;
- queue_alloc = 0;
- queue = NULL;
- pthread_mutex_unlock(&_mutex);
-
- for (i = 0; i < myqueue_num; i++)
- {
- ev = &(myqueue[i]);
+
+ do {
+ check = read(_fd_read, &ev, sizeof (Evas_Event_Async *));
+
+ if (check == sizeof (Evas_Event_Async *))
+ {
if (ev->func) ev->func((void *)ev->target, ev->type, ev->event_info);
- count++;
- }
- free(myqueue);
- }
- else
- pthread_mutex_unlock(&_mutex);
-
+ free(ev);
+ count++;
+ }
+ } while (check > 0);
+
+ evas_cache_image_wakeup();
+
if (check < 0)
switch (errno)
{
case EISDIR:
_fd_read = -1;
}
-
- evas_cache_pending_process();
+
return count;
#else
return 0;
if (!func) return 0;
if (_fd_write == -1) return 0;
- pthread_mutex_lock(&_mutex);
-
- queue_num++;
- if (queue_num > queue_alloc)
- {
- Evas_Event_Async *q2;
-
- queue_alloc += 32; // 32 slots at a time for async events
- q2 = realloc(queue, queue_alloc * sizeof(Evas_Event_Async));
- if (!q2)
- {
- queue_alloc -= 32;
- queue_num--;
- pthread_mutex_unlock(&_mutex);
- return 0;
- }
- queue = q2;
- }
- ev = &(queue[queue_num - 1]);
- memset(ev, 0, sizeof(Evas_Event_Async));
+ ev = calloc(1, sizeof (Evas_Event_Async));
+ if (!ev) return 0;
+
ev->func = func;
ev->target = target;
ev->type = type;
ev->event_info = event_info;
- do
- {
- unsigned char buf[1] = { 0xf0 };
- check = write(_fd_write, buf, 1);
- } while ((check != 1) && ((errno == EINTR) || (errno == EAGAIN)));
+ do {
+ check = write(_fd_write, &ev, sizeof (Evas_Event_Async*));
+ } while ((check != sizeof (Evas_Event_Async)) && ((errno == EINTR) || (errno == EAGAIN)));
+
+ evas_cache_image_wakeup();
- if (check == 1)
+ if (check == sizeof (Evas_Event_Async*))
result = EINA_TRUE;
else
switch (errno)
case EPIPE:
_fd_write = -1;
}
-
- pthread_mutex_unlock(&_mutex);
+
return result;
#else
func(target, type, event_info);