From dd7595a3475407a7fa96a97393bae8c5220e8762 Mon Sep 17 00:00:00 2001 From: David Walter Seikel Date: Wed, 4 Jan 2012 18:41:13 +1000 Subject: Add the base Enlightenment Foundation Libraries - eina, eet, evas, ecore, embryo, and edje. Note that embryo wont be used, but I'm not sure yet if you can build edje without it. --- libraries/evas/src/lib/cache/evas_preload.c | 264 ++++++++++++++++++++++++++++ 1 file changed, 264 insertions(+) create mode 100644 libraries/evas/src/lib/cache/evas_preload.c (limited to 'libraries/evas/src/lib/cache/evas_preload.c') diff --git a/libraries/evas/src/lib/cache/evas_preload.c b/libraries/evas/src/lib/cache/evas_preload.c new file mode 100644 index 0000000..6e0412a --- /dev/null +++ b/libraries/evas/src/lib/cache/evas_preload.c @@ -0,0 +1,264 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef HAVE_EVIL +# include +#endif + +#ifdef BUILD_ASYNC_PRELOAD +# include +# ifdef __linux__ +# include +# endif +#endif + +#include "evas_common.h" +#include "evas_private.h" +#include "Evas.h" + +#ifdef BUILD_ASYNC_PRELOAD + +static int _threads_max = 0; + +typedef struct _Evas_Preload_Pthread_Worker Evas_Preload_Pthread_Worker; +typedef struct _Evas_Preload_Pthread_Data Evas_Preload_Pthread_Data; + +typedef void (*_evas_preload_pthread_func)(void *data); + +struct _Evas_Preload_Pthread_Worker +{ + EINA_INLIST; + + _evas_preload_pthread_func func_heavy; + _evas_preload_pthread_func func_end; + _evas_preload_pthread_func func_cancel; + void *data; + Eina_Bool cancel : 1; +}; + +struct _Evas_Preload_Pthread_Data +{ + pthread_t thread; +}; + +static int _threads_count = 0; +static Evas_Preload_Pthread_Worker *_workers = NULL; + +static LK(_mutex); + +static void +_evas_preload_thread_end(void *data) +{ + Evas_Preload_Pthread_Data *pth = data; + Evas_Preload_Pthread_Data *p = NULL; + + if (pthread_join(pth->thread, (void **)&p) == 0) free(p); + else return; + eina_threads_shutdown(); +} + +static void +_evas_preload_thread_done(void *target __UNUSED__, Evas_Callback_Type type __UNUSED__, void *event_info) +{ + Evas_Preload_Pthread_Worker *work = event_info; + if (work->cancel) + { + if (work->func_cancel) work->func_cancel(work->data); + } + else + work->func_end(work->data); + + free(work); +} + +static void * +_evas_preload_thread_worker(void *data) +{ + Evas_Preload_Pthread_Data *pth = data; + Evas_Preload_Pthread_Worker *work; + + eina_sched_prio_drop(); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); +on_error: + for (;;) + { + LKL(_mutex); + if (!_workers) + { + LKU(_mutex); + break; + } + + work = _workers; + _workers = EINA_INLIST_CONTAINER_GET(eina_inlist_remove(EINA_INLIST_GET(_workers), + EINA_INLIST_GET(_workers)), + Evas_Preload_Pthread_Worker); + LKU(_mutex); + + if (work->func_heavy) work->func_heavy(work->data); + evas_async_events_put(pth, 0, work, _evas_preload_thread_done); + } + + LKL(_mutex); + if (_workers) + { + LKU(_mutex); + goto on_error; + } + _threads_count--; + LKU(_mutex); + + // dummy worker to wake things up + work = malloc(sizeof(Evas_Preload_Pthread_Worker)); + if (!work) return NULL; + + work->data = pth; + work->func_heavy = NULL; + work->func_end = (_evas_preload_pthread_func) _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) +{ +#ifdef BUILD_ASYNC_PRELOAD + _threads_max = eina_cpu_count(); + if (_threads_max < 1) _threads_max = 1; + + LKI(_mutex); +#endif +} + +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; + + /* Force processing of async events. */ + evas_async_events_process(); + LKL(_mutex); + while (_workers) + { + work = _workers; + _workers = EINA_INLIST_CONTAINER_GET(eina_inlist_remove(EINA_INLIST_GET(_workers), + EINA_INLIST_GET(_workers)), + Evas_Preload_Pthread_Worker); + if (work->func_cancel) work->func_cancel(work->data); + free(work); + } + LKU(_mutex); + + LKD(_mutex); +#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) + { + func_cancel((void *)data); + return NULL; + } + + work->func_heavy = func_heavy; + work->func_end = func_end; + work->func_cancel = func_cancel; + work->cancel = EINA_FALSE; + work->data = (void *)data; + + LKL(_mutex); + _workers = (Evas_Preload_Pthread_Worker *)eina_inlist_append(EINA_INLIST_GET(_workers), EINA_INLIST_GET(work)); + if (_threads_count == _threads_max) + { + LKU(_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; + + eina_threads_init(); + + if (pthread_create(&pth->thread, NULL, _evas_preload_thread_worker, pth) == 0) + { + LKL(_mutex); + _threads_count++; + LKU(_mutex); + return (Evas_Preload_Pthread*)work; + } + + eina_threads_shutdown(); + + on_error: + LKL(_mutex); + if (_threads_count == 0) + { + LKU(_mutex); + if (work->func_cancel) work->func_cancel(work->data); + free(work); + return NULL; + } + LKU(_mutex); + 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 (void *)1; +#endif +} + +Eina_Bool +evas_preload_thread_cancel(Evas_Preload_Pthread *thread) +{ +#ifdef BUILD_ASYNC_PRELOAD + Evas_Preload_Pthread_Worker *work; + + if (!thread) return EINA_TRUE; + LKL(_mutex); + EINA_INLIST_FOREACH(_workers, work) + { + if (work == (Evas_Preload_Pthread_Worker *)thread) + { + _workers = EINA_INLIST_CONTAINER_GET(eina_inlist_remove(EINA_INLIST_GET(_workers), + EINA_INLIST_GET(work)), + Evas_Preload_Pthread_Worker); + LKU(_mutex); + if (work->func_cancel) work->func_cancel(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 +} -- cgit v1.1