diff --git a/legacy/evas/configure.ac b/legacy/evas/configure.ac index 6edfe01bf9..fb66fcd9e5 100644 --- a/legacy/evas/configure.ac +++ b/legacy/evas/configure.ac @@ -137,11 +137,30 @@ dnl when used, that option makes configure script fails when dnl a requirement is selected, but not met. AC_ARG_ENABLE(strict, AC_HELP_STRING( - [enable strict mode]), + [--enable-strict], + [enable strict checking mode. [[default==disabled]]]), [use_strict="yes"], [use_strict="no"] ) +####################################### +## CACHE SERVER (CSERVE / CS) +want_evas_cserve="yes" +AC_MSG_CHECKING(whether to build shared cache server and support) +AC_ARG_ENABLE(evas-cserve, + AC_HELP_STRING( + [--disable-evas-cserve], + [disable shared cache server support. [[default=enabled]]] + ), + [ want_evas_cserve="$enableval" ] +) +AC_MSG_RESULT($want_evas_cserve) + +AM_CONDITIONAL(EVAS_CSERVE, test "x$want_evas_cserve" = "xyes") +if test "x$want_evas_cserve" = "xyes"; then + AC_DEFINE(EVAS_CSERVE, 1, [Shared caceh server.]) +fi + ################################################################## #fribidi support - OPTIONAL! PKG_CHECK_MODULES([FRIBIDI], [fribidi], ,HAS_BIDI=0) @@ -1044,12 +1063,14 @@ evas.pc doc/evas.dox doc/Makefile src/Makefile +src/bin/Makefile src/lib/Makefile src/lib/canvas/Makefile src/lib/data/Makefile src/lib/file/Makefile src/lib/imaging/Makefile src/lib/cache/Makefile +src/lib/cserve/Makefile src/lib/engines/Makefile src/lib/engines/common/Makefile src/lib/engines/common/evas_op_add/Makefile @@ -1172,11 +1193,13 @@ echo " SSE.....................: $build_cpu_sse" echo " ALTIVEC.................: $build_cpu_altivec" echo " NEON....................: $build_cpu_neon" echo " Thread Support..........: $build_pthreads" +echo "Features:" echo " MAGIC_DEBUG.............: $want_evas_magic_debug" +echo " Cache Server............: $want_evas_cserve" echo -echo "Threaded Pipe Rendering...: $build_pipe_render" -echo "Async Events..............: $build_async_events" -echo "Async Image Preload.......: $build_async_preload" +echo " Threaded Pipe Rendering.: $build_pipe_render" +echo " Async Events............: $build_async_events" +echo " Async Image Preload.....: $build_async_preload" echo echo "ARGB Software Engine Options:" echo " Sampling Scaler.........: $scaler_sample" diff --git a/legacy/evas/src/Makefile.am b/legacy/evas/src/Makefile.am index 75f3f7011c..1f5220881d 100644 --- a/legacy/evas/src/Makefile.am +++ b/legacy/evas/src/Makefile.am @@ -1,3 +1,3 @@ MAINTAINERCLEANFILES = Makefile.in -SUBDIRS = lib modules +SUBDIRS = lib bin modules diff --git a/legacy/evas/src/bin/Makefile.am b/legacy/evas/src/bin/Makefile.am new file mode 100644 index 0000000000..76c7aa8d98 --- /dev/null +++ b/legacy/evas/src/bin/Makefile.am @@ -0,0 +1,40 @@ +MAINTAINERCLEANFILES = Makefile.in + +if EVAS_CSERVE + +AM_CPPFLAGS = \ +-I. \ +-I$(top_srcdir)/src/lib \ +-I$(top_srcdir)/src/lib/include \ +-I$(top_srcdir)/src/lib/cserve \ +-DPACKAGE_BIN_DIR=\"$(bindir)\" \ +-DPACKAGE_LIB_DIR=\"$(libdir)\" \ +-DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \ +@EINA_CFLAGS@ \ +@FREETYPE_CFLAGS@ \ +@FRIBIDI_CFLAGS@ \ +@EET_CFLAGS@ \ +@FONTCONFIG_CFLAGS@ \ +@pthread_cflags@ + +AM_CFLAGS = @WIN32_CFLAGS@ + +bin_PROGRAMS = evas_cserve evas_cserve_test + +evas_cserve_SOURCES = \ +evas_cserve_main.c + +evas_cserve_LDADD = \ +$(top_builddir)/src/lib/libevas.la + +evas_cserve_test_LDFLAGS = + +evas_cserve_test_SOURCES = \ +evas_cserve_test_main.c + +evas_cserve_test_LDADD = \ +$(top_builddir)/src/lib/libevas.la + +evas_cserve_test_LDFLAGS = + +endif diff --git a/legacy/evas/src/bin/evas_cserve_main.c b/legacy/evas/src/bin/evas_cserve_main.c new file mode 100644 index 0000000000..68bb7261f7 --- /dev/null +++ b/legacy/evas/src/bin/evas_cserve_main.c @@ -0,0 +1,733 @@ +#include "Evas.h" +#include "evas_cs.h" + +// fixme:'s +// +// sigint/term - catch and shut down cleanly (server) +// sigpipe - catch and ignore (both) +// cwd for loading files needs to be put into a full path (client) +// add ops to get/set cache size, check time and cache time (both) +// add ops to get internal state (both) +// preload - make it work (both) +// monitor /proc/meminfo and if mem low - free items until cache empty (server) +// +// pants! + +typedef struct _Img Img; +typedef struct _Lopt Lopt; + +struct _Lopt +{ + int scale_down_by; // if > 1 then use this + double dpi; // if > 0.0 use this + int w, h; // if > 0 use this +}; + +struct _Img +{ + Image_Entry ie; + int ref; + int usage; + Mem *mem; + const char *key; + time_t cached; + struct { + const char *file; + const char *key; + time_t modtime; + time_t last_stat; + } file; + Lopt load_opts; + struct { + int w, h; + void *data; + Eina_Bool alpha : 1; + } image; + Eina_Bool dead : 1; + Eina_Bool active : 1; +}; + +// config +static int stat_res_interval = 2; + +static time_t t_now = 0; + +static Evas_Cache_Image *cache = NULL; + +static Eina_Hash *active_images = NULL; +static Eina_List *cache_images = NULL; +static int cache_usage = 0; +static int cache_max_usage = 1 * 1024 * 1024; +static int cache_item_timeout = -1; +static int cache_item_timeout_check = 10; +static Mem *stat_mem = NULL; + +static int stat_mem_num = 0; +static Eina_List *stat_mems = NULL; + +static void +stat_clean(Mem *m) +{ + int *ints; + int size, pid, *ids, count, i; + + ints = (int *)m->data; + size = ints[0]; + if (!evas_cserve_mem_resize(m, size)) return; + ints = (int *)m->data; + pid = ints[1]; + count = (size - (2 * sizeof(int))) / sizeof(int); + ids = ints + 2; + for (i = 0; i < count; i++) + evas_cserve_mem_del(pid, ids[i]); +} + +static int +stat_init(Mem *m) +{ + int *ints; + + ints = (int *)m->data; + + if (!evas_cserve_mem_resize(m, 2 * sizeof(int))) return 0; + ints[0] = 2 * sizeof(int); + ints[1] = getpid(); + msync(m->data, 2 * sizeof(int), MS_SYNC | MS_INVALIDATE); + return 1; +} + +static int +stat_update(Mem *m) +{ + Eina_List *l; + Mem *m2; + int *ints, *ids, i; + + ints = (int *)m->data; + ints[0] = (2 * sizeof(int)) + (eina_list_count(stat_mems) * sizeof(int)); + if (!evas_cserve_mem_resize(m, ints[0])) return 0; + ints = (int *)m->data; + ids = ints + 2; + i = 0; + EINA_LIST_FOREACH(stat_mems, l, m2) + { + ids[i] = m2->id; + i++; + } + msync(m->data, ints[0], MS_SYNC | MS_INVALIDATE); + return 1; +} + +static Image_Entry * +_img_alloc(void) +{ + Img *img; + + img = calloc(1, sizeof(Img)); + return (Image_Entry *)img; +} + +static void +_img_dealloc(Image_Entry *ie) +{ + Img *img = (Img *)ie; + free(img); +} + +static int +_img_surface_alloc(Image_Entry *ie, int w, int h) +{ + Img *img = (Img *)ie; + + img->mem = evas_cserve_mem_new(w * h * sizeof(DATA32), NULL); + if (!img->mem) return -1; + img->image.data = img->mem->data + img->mem->offset; + + stat_mems = eina_list_append(stat_mems, img->mem); + stat_update(stat_mem); + return 0; +} + +static void +_img_surface_delete(Image_Entry *ie) +{ + Img *img = (Img *)ie; + + if (!img->mem) return; + + stat_mems = eina_list_remove(stat_mems, img->mem); + stat_update(stat_mem); + + evas_cserve_mem_free(img->mem); + img->mem = NULL; + img->image.data = NULL; +} + +static DATA32 * +_img_surface_pixels(Image_Entry *ie) +{ + Img *img = (Img *)ie; + + return img->image.data; +} + +static int +_img_load(Image_Entry *ie) +{ + return evas_common_load_rgba_image_module_from_file(ie); +} + +static void +_img_unload(Image_Entry *ie) +{ +} + +static void +_img_dirty_region(Image_Entry *ie, int x, int y, int w, int h) +{ +} + +static int +_img_dirty(Image_Entry *dst, const Image_Entry *src) +{ + return 0; +} + +static int +_img_size_set(Image_Entry *dst, const Image_Entry *src, int w, int h) +{ + return 0; +} + +static int +_img_copied_data(Image_Entry *ie, int w, int h, DATA32 *image_data, int alpha, int cspace) +{ + return 0; +} + +static int +_img_data(Image_Entry *ie, int w, int h, DATA32 *image_data, int alpha, int cspace) +{ + return 0; +} + +static int +_img_color_space(Image_Entry *ie, int cspace) +{ + return 0; +} + +static int +_img_load_data(Image_Entry *ie) +{ + return evas_common_load_rgba_image_data_from_file(ie); +} + +static int +_img_mem_size_get(Image_Entry *ie) +{ + return 1; +} + +static void +img_init(void) +{ + const Evas_Cache_Image_Func cache_funcs = + { + _img_alloc,//Image_Entry *(*alloc)(void); + _img_dealloc,//void (*dealloc)(Image_Entry *im); + /* The cache provide some helpers for surface manipulation. */ + _img_surface_alloc,//int (*surface_alloc)(Image_Entry *im, int w, int h); + _img_surface_delete,//void (*surface_delete)(Image_Entry *im); + _img_surface_pixels,//DATA32 *(*surface_pixels)(Image_Entry *im); + /* The cache is doing the allocation and deallocation, you must just do the rest. */ + _img_load,//int (*constructor)(Image_Entry *im); + _img_unload,//void (*destructor)(Image_Entry *im); + _img_dirty_region,//void (*dirty_region)(Image_Entry *im, int x, int y, int w, int h); + /* Only called when references > 0. Need to provide a fresh copie of im. */ + /* The destination surface does have a surface, but no allocated pixel data. */ + _img_dirty,//int (*dirty)(Image_Entry *dst, const Image_Entry *src); + /* Only called when references == 1. We will call drop on im'. */ + /* The destination surface does not have any surface. */ + _img_size_set,//int (*size_set)(Image_Entry *dst, const Image_Entry *src, int w, int h); + /* The destination surface does not have any surface. */ + _img_copied_data,//int (*copied_data)(Image_Entry *dst, int w, int h, DATA32 *image_data, int alpha, int cspace); + /* The destination surface does not have any surface. */ + _img_data,//int (*data)(Image_Entry *dst, int w, int h, DATA32 *image_data, int alpha, int cspace); + _img_color_space,//int (*color_space)(Image_Entry *dst, int cspace); + /* This function need to update im->w and im->h. */ + _img_load_data,//int (*load)(Image_Entry *im); + _img_mem_size_get,//int (*mem_size_get)(Image_Entry *im); + NULL,//void (*debug)(const char *context, Image_Entry *im); + }; + + active_images = eina_hash_string_superfast_new(NULL); + cache = evas_cache_image_init(&cache_funcs); +} + +static void +img_shutdown(void) +{ + evas_cache_image_shutdown(cache); + cache = NULL; + // FIXME: shutdown properly +} + +static Img * +img_new(const char *file, const char *key, RGBA_Image_Loadopts *load_opts, const char *bufkey) +{ + Img *img; + struct stat st; + int ret; + Image_Entry *ie; + int err = 0; + + ret = stat(file, &st); + if (ret < 0) return NULL; + ie = evas_cache_image_request(cache, file, key, load_opts, &err); + if (!ie) return NULL; + img = (Img *)ie; + img->key = eina_stringshare_add(bufkey); + img->file.modtime = st.st_mtime; + img->file.file = eina_stringshare_add(file); + if (key) img->file.key = eina_stringshare_add(key); + img->load_opts.scale_down_by = load_opts->scale_down_by; + img->load_opts.dpi = load_opts->dpi; + img->load_opts.w = load_opts->w; + img->load_opts.h = load_opts->h; + img->image.w = ie->w; + img->image.h = ie->h; + img->image.alpha = ie->flags.alpha; + img->ref = 1; + img->active = 1; + + img->usage = sizeof(Img) + strlen(img->key) + 1 + strlen(img->file.file) + 1; + if (img->file.key) img->usage += strlen(img->file.key) + 1; + // fixme: load img, get header + eina_hash_direct_add(active_images, img->key, img); + return img; +} + +static void +img_loaddata(Img *img) +{ + // fixme: load img data + evas_cache_image_load_data((Image_Entry *)img); + if (img->image.data) + msync(img->image.data, img->image.w * img->image.h * sizeof(DATA32), MS_SYNC | MS_INVALIDATE); + img->usage += + (4096 * (((img->image.w * img->image.h * sizeof(DATA32)) + 4095) / 4096)) + + sizeof(Mem); +} + +static void +img_free(Img *img) +{ + eina_stringshare_del(img->key); + eina_stringshare_del(img->file.file); + eina_stringshare_del(img->file.key); + evas_cache_image_drop((Image_Entry *)img); +} + +static void +cache_clean(void) +{ + while ((cache_usage > cache_max_usage) && (cache_images)) + { + Img *img; + Eina_List *l; + + l = eina_list_last(cache_images); + if (!l) break; + img = l->data; + if (!img) break; + cache_images = eina_list_remove_list(cache_images, l); + cache_usage -= img->usage; + img_free(img); + } +} + +static void +cache_timeout(time_t t) +{ + Eina_List *l, *l_next; + Img *img; + + if (cache_item_timeout < 0) return; + EINA_LIST_FOREACH_SAFE(cache_images, l, l_next, img) + { + if ((t - img->cached) > cache_item_timeout) + { + cache_images = eina_list_remove_list(cache_images, l); + cache_usage -= img->usage; + img_free(img); + } + } +} + +static void +img_cache(Img *img) +{ + eina_hash_del(active_images, img->key, img); + img->active = 0; + if (img->dead) + { + img_free(img); + return; + } + cache_images = eina_list_prepend(cache_images, img); + img->cached = t_now; + cache_usage += img->usage; + if (cache_usage > cache_max_usage) + cache_clean(); +} + +static void +img_dead(Img *img) +{ + if (img->active) return; + cache_images = eina_list_remove(cache_images, img); + img_free(img); +} + +static Eina_Bool +img_ok(Img *img) +{ + struct stat st; + int ret; + + if (img->dead) return 0; + if ((t_now > img->file.last_stat) && + ((t_now - img->file.last_stat) < stat_res_interval)) return 1; + img->file.last_stat = t_now; + ret = stat(img->file.file, &st); + if (ret < 0) + { + img->dead = 1; + img_dead(img); + return 0; + } + if (st.st_mtime != img->file.modtime) + { + img->dead = 1; + img_dead(img); + return 0; + } + return 1; +} + +static Img * +img_load(const char *file, const char *key, RGBA_Image_Loadopts *load_opts) +{ + Img *img; + char buf[8192]; + Eina_List *l, *l_next; + + if (!file) return NULL; + if (key) + snprintf(buf, sizeof(buf), "%s///::/%s/\001/%i/%1.8f/%ix%i", + file, key, + load_opts->scale_down_by, + load_opts->dpi, + load_opts->w, load_opts->h); + else + snprintf(buf, sizeof(buf), "%s///\001/%i/%1.8f/%ix%i", + file, + load_opts->scale_down_by, + load_opts->dpi, + load_opts->w, load_opts->h); + img = eina_hash_find(active_images, buf); + if ((img) && (img_ok(img))) + { + img->ref++; + return img; + } + + // FIXME: keep hash of cached images too + EINA_LIST_FOREACH_SAFE(cache_images, l, l_next, img) + { + if (!strcmp(img->key, buf)) + { + if (img_ok(img)) + { + img->ref++; + cache_images = eina_list_remove_list(cache_images, l); + eina_hash_direct_add(active_images, img->key, img); + return img; + } + } + } + return img_new(file, key, load_opts, buf); +} + +static void +img_unload(Img *img) +{ + img->ref--; + if (img->ref <= 0) + { + img_cache(img); + } +} + +static void +img_forcedunload(Img *img) +{ + img->dead = 1; + img_unload(img); +} + +static void +img_preload(Img *img) +{ + printf("preload '%s'\n", img->file.file); +} + +static void +client_del(void *data, Client *c) +{ + Eina_List *images; + Img *img; + + images = data; + EINA_LIST_FREE(images, img) + { + img_unload(img); + } +} + +static int +message(void *fdata, Server *s, Client *c, int opcode, int size, unsigned char *data) +{ + t_now = time(NULL); + switch (opcode) + { + case OP_INIT: + { + Op_Init *rep; + Op_Init msg; + + memset(&msg, 0, sizeof(msg)); + msg.pid = getpid(); + rep = (Op_Init *)data; + c->pid = rep->pid; + c->func = client_del; + c->data = NULL; + evas_cserve_client_send(c, OP_INIT, sizeof(msg), (unsigned char *)(&msg)); + } + break; + case OP_LOAD: + { + Op_Load *rep; + Op_Load_Reply msg; + Img *img; + RGBA_Image_Loadopts lopt = {0, 0.0, 0, 0}; + char *file = NULL, *key = NULL; + + rep = (Op_Load *)data; + file = data + sizeof(Op_Load); + key = file + strlen(file) + 1; + if (key[0] == 0) key = NULL; + lopt.scale_down_by = rep->lopt.scale_down_by; + lopt.dpi = rep->lopt.dpi; + lopt.w = rep->lopt.w; + lopt.h = rep->lopt.h; + img = img_load(file, key, &lopt); + if (img) + { + Eina_List *list; + + list = c->data; + list = eina_list_append(list, img); + c->data = list; + } + memset(&msg, 0, sizeof(msg)); + msg.handle = img; + if ((img) && (img->mem)) + { + msg.mem.id = img->mem->id; + msg.mem.offset = img->mem->offset; + msg.mem.size = img->mem->size; + } + else + msg.mem.id = msg.mem.offset = msg.mem.size = 0; + if (img) + { + msg.image.w = img->image.w; + msg.image.h = img->image.h; + msg.image.alpha = img->image.alpha; + } + evas_cserve_client_send(c, OP_LOAD, sizeof(msg), (unsigned char *)(&msg)); + } + break; + case OP_UNLOAD: + { + Op_Unload *rep; + Img *img; + + rep = (Op_Unload *)data; + img = rep->handle; + c->data = eina_list_remove(c->data, img); + img_unload(img); + } + break; + case OP_LOADDATA: + { + Op_Loaddata *rep; + Op_Loaddata_Reply msg; + Img *img; +// fixme: handle loadopts on loaddata +// RGBA_Image_Loadopts lopt = {0, 0.0, 0, 0}; + + rep = (Op_Loaddata *)data; + img = rep->handle; + img_loaddata(img); + memset(&msg, 0, sizeof(msg)); + if (img->mem) + { + msg.mem.id = img->mem->id; + msg.mem.offset = img->mem->offset; + msg.mem.size = img->mem->size; + } + else + msg.mem.id = msg.mem.offset = msg.mem.size = 0; + evas_cserve_client_send(c, OP_LOADDATA, sizeof(msg), (unsigned char *)(&msg)); + } + break; + case OP_PRELOAD: + { + Op_Preload *rep; + Img *img; + + rep = (Op_Preload *)data; + img = rep->handle; + c->data = eina_list_remove(c->data, img); + printf("preload %p\n", img); + img_preload(img); + } + case OP_FORCEDUNLOAD: + { + Op_Forcedunload *rep; + Img *img; + + rep = (Op_Forcedunload *)data; + img = rep->handle; + c->data = eina_list_remove(c->data, img); + img_forcedunload(img); + } + break; + default: + break; + } +} + +static void +parse_args(int argc, char **argv) +{ + int i; + + for (i = 1; i < argc; i++) + { + if ((!strcmp(argv[i], "-h")) || + (!strcmp(argv[i], "-help")) || + (!strcmp(argv[i], "--help"))) + { + printf("Options:\n" + "\t-h This help\n" + "\t-csize Size of speculative cache (Kb)\n" + "\t-ctime Maximum life of a cached image (seconds)\n" + "\t-ctimecheck Time between checking the cache for timeouts (seconds)\n" + "\n"); + exit(0); + } + else if ((!strcmp(argv[i], "-csize")) && (i < (argc - 1))) + { + i++; + cache_max_usage = atoi(argv[i]) * 1024; + } + else if ((!strcmp(argv[i], "-ctime")) && (i < (argc - 1))) + { + i++; + cache_item_timeout = atoi(argv[i]); + } + else if ((!strcmp(argv[i], "-ctimecheck")) && (i < (argc - 1))) + { + i++; + cache_item_timeout_check = atoi(argv[i]); + } + } +} + +int +main(int argc, char **argv) +{ + Server *s; + time_t last_check, t, t_next; + + parse_args(argc, argv); + + eina_init(); + evas_init(); + + img_init(); + s = evas_cserve_server_add(); + if (!s) + { + printf("ERROR: server socket init fail. abort.\n"); + goto error; + } + stat_mem = evas_cserve_mem_open(0, 0, "status", sizeof(int), 0); + if (stat_mem) + { + printf("WARNING: previous evas_cserve left garbage. cleaning up.\n"); + stat_clean(stat_mem); + evas_cserve_mem_close(stat_mem); + stat_mem = NULL; + } + stat_mem = evas_cserve_mem_new(sizeof(int), "status"); + if (!stat_mem) + { + printf("ERROR: cannot create status shmseg. abort.\n"); + goto error; + } + if (!stat_init(stat_mem)) + { + printf("ERROR: cannot init status shmseg. abort.\n"); + evas_cserve_mem_free(stat_mem); + stat_mem = NULL; + goto error; + } + + evas_cserve_server_message_handler_set(s, message, NULL); + last_check = time(NULL); + t_next = 0; + if (cache_item_timeout_check > 0) t_next = cache_item_timeout_check; + for (;;) + { + /* fixme: timeout 0 only her - future use timeouts for timed + * housekeping */ + evas_cserve_server_wait(s, t_next * 1000000); + t = time(NULL); + t_next = t - last_check; + if ((t_next) > cache_item_timeout_check) + { + t_next = cache_item_timeout_check; + + last_check = t; + cache_timeout(t); + } + if ((t_next <= 0) && (cache_item_timeout_check > 0)) + t_next = 1; + } + error: + img_shutdown(); + if (stat_mem) + { + evas_cserve_mem_free(stat_mem); + stat_mem = NULL; + } + + evas_shutdown(); + eina_shutdown(); + return 0; +} diff --git a/legacy/evas/src/bin/evas_cserve_test_main.c b/legacy/evas/src/bin/evas_cserve_test_main.c new file mode 100644 index 0000000000..8a72705d0d --- /dev/null +++ b/legacy/evas/src/bin/evas_cserve_test_main.c @@ -0,0 +1,33 @@ +#include "evas_cs.h" + +int +main(int argc, char **argv) +{ + evas_init(); + + printf("evas_cserve_init = %i\n", evas_cserve_init()); + + { + Image_Entry *ie; + RGBA_Image_Loadopts lopt = { 0, 0.0, 0, 0}; + + ie = malloc(sizeof(Image_Entry)); + if (evas_cserve_image_load(ie, argv[1], NULL, &lopt)) + { + printf("load ok\n"); + if (evas_cserve_image_data_load(ie)) + { + Mem *m; + + m = ie->data2; + printf("first pixel: %08x\n", *((int *)m->data)); + printf("load data ok\n"); +// evas_cserve_image_free(ie); + } + } + } + + evas_cserve_shutdown(); + evas_shutdown(); + return 0; +} diff --git a/legacy/evas/src/lib/Makefile.am b/legacy/evas/src/lib/Makefile.am index fd50028bf8..4e305569b6 100644 --- a/legacy/evas/src/lib/Makefile.am +++ b/legacy/evas/src/lib/Makefile.am @@ -1,6 +1,6 @@ MAINTAINERCLEANFILES = Makefile.in -SUBDIRS = canvas data cache file engines imaging include +SUBDIRS = canvas data cache cserve file engines imaging include AM_CPPFLAGS = \ -I. \ @@ -30,6 +30,7 @@ data/libevas_data.la \ file/libevas_file.la \ cache/libevas_cache.la \ imaging/libevas_imaging.la \ +cserve/libevas_cserve.la \ engines/common/libevas_engine_common.la \ @dlopen_libs@ \ @FREETYPE_LIBS@ \ @@ -47,6 +48,7 @@ data/libevas_data.la \ file/libevas_file.la \ cache/libevas_cache.la \ imaging/libevas_imaging.la \ +cserve/libevas_cserve.la \ engines/common/libevas_engine_common.la if BUILD_ENGINE_SOFTWARE_16 diff --git a/legacy/evas/src/lib/cache/evas_cache_image.c b/legacy/evas/src/lib/cache/evas_cache_image.c index cffa4ca351..3c304fe67c 100644 --- a/legacy/evas/src/lib/cache/evas_cache_image.c +++ b/legacy/evas/src/lib/cache/evas_cache_image.c @@ -18,6 +18,11 @@ #include "evas_common.h" #include "evas_private.h" +#ifdef EVAS_CSERVE +// FIXME: cache server and threaded preload clash badly atm - disable +#undef BUILD_ASYNC_PRELOAD +#endif + #ifdef BUILD_ASYNC_PRELOAD #include @@ -801,8 +806,11 @@ evas_cache_image_dirty(Image_Entry *im, int x, int y, int w, int h) cache = im->cache; if (!(im->flags.dirty)) { +#ifndef EVAS_CSERVE +// if ref 1 also copy if using shared cache as its read-only if (im->references == 1) im_dirty = im; else +#endif { int error; diff --git a/legacy/evas/src/lib/canvas/Makefile.am b/legacy/evas/src/lib/canvas/Makefile.am index 637ddaec9e..96d614ca5c 100644 --- a/legacy/evas/src/lib/canvas/Makefile.am +++ b/legacy/evas/src/lib/canvas/Makefile.am @@ -1,10 +1,10 @@ - MAINTAINERCLEANFILES = Makefile.in AM_CPPFLAGS = \ -I. \ -I$(top_srcdir)/src/lib \ -I$(top_srcdir)/src/lib/include \ +-I$(top_srcdir)/src/lib/cserve \ -DPACKAGE_BIN_DIR=\"$(bindir)\" \ -DPACKAGE_LIB_DIR=\"$(libdir)\" \ -DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \ diff --git a/legacy/evas/src/lib/canvas/evas_main.c b/legacy/evas/src/lib/canvas/evas_main.c index fe2d2c2388..2d2065b506 100644 --- a/legacy/evas/src/lib/canvas/evas_main.c +++ b/legacy/evas/src/lib/canvas/evas_main.c @@ -1,5 +1,6 @@ #include "evas_common.h" #include "evas_private.h" +#include "evas_cs.h" extern Eina_List *evas_modules; static int initcount = 0; @@ -28,6 +29,9 @@ evas_init(void) evas_module_init(); evas_async_events_init(); +#ifdef EVAS_CSERVE + if (getenv("EVAS_CSERVE")) evas_cserve_init(); +#endif } return ++initcount; } @@ -38,6 +42,9 @@ evas_shutdown(void) initcount--; if (initcount == 0) { +#ifdef EVAS_CSERVE + if (getenv("EVAS_CSERVE")) evas_cserve_shutdown(); +#endif evas_async_events_shutdown(); evas_font_dir_cache_free(); evas_common_shutdown(); diff --git a/legacy/evas/src/lib/cserve/Makefile.am b/legacy/evas/src/lib/cserve/Makefile.am new file mode 100644 index 0000000000..117ee4dc72 --- /dev/null +++ b/legacy/evas/src/lib/cserve/Makefile.am @@ -0,0 +1,29 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I. \ +-I$(top_srcdir)/src/lib \ +-I$(top_srcdir)/src/lib/include \ +-I$(top_srcdir)/src/lib/cserve \ +-DPACKAGE_BIN_DIR=\"$(bindir)\" \ +-DPACKAGE_LIB_DIR=\"$(libdir)\" \ +-DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \ +@EINA_CFLAGS@ \ +@FREETYPE_CFLAGS@ \ +@FRIBIDI_CFLAGS@ \ +@EET_CFLAGS@ \ +@FONTCONFIG_CFLAGS@ \ +@pthread_cflags@ + +noinst_LTLIBRARIES = libevas_cserve.la +libevas_cserve_la_SOURCES = \ +evas_cs.h \ +evas_cs_main.c \ +evas_cs_server.c \ +evas_cs_client.c \ +evas_cs_mem.c + +libevas_cserve_la_LIBADD = @EINA_LIBS@ -lrt + +libevas_la_DEPENDENCIES = \ +$(top_builddir)/config.h diff --git a/legacy/evas/src/lib/cserve/evas_cs.h b/legacy/evas/src/lib/cserve/evas_cs.h new file mode 100644 index 0000000000..bc9ab397e8 --- /dev/null +++ b/legacy/evas/src/lib/cserve/evas_cs.h @@ -0,0 +1,199 @@ +#ifndef EVAS_CS_H +#define EVAS_CS_H 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "evas_common.h" +#include "evas_private.h" + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# ifdef EFL_EVAS_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else +# define EAPI +# endif /* ! DLL_EXPORT */ +# else +# define EAPI __declspec(dllimport) +# endif /* ! EFL_EVAS_BUILD */ +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif /* ! _WIN32 */ + +#ifdef EVAS_CSERVE + +#define LENGTH_OF_SOCKADDR_UN(s) (strlen((s)->sun_path) + (size_t)(((struct sockaddr_un *)NULL)->sun_path)) + +typedef struct _Server Server; +typedef struct _Client Client; +typedef struct _Mem Mem; + +struct _Server +{ + char *socket_path; + int fd; + Eina_List *clients; + int (*func) (void *fdata, Server *s, Client *c, int opcode, int size, unsigned char *data); + void *data; + pid_t pid; +}; + +struct _Client +{ + Server *server; + unsigned char *buf; + int bufsize, bufalloc; + int fd; + unsigned char *inbuf; + int inbufsize, inbufalloc; + unsigned char dead : 1; + void (*func) (void *fdata, Client *c); + void *data; + pid_t pid; +}; + +struct _Mem +{ + unsigned char *data; + char *name; + int fd; + int id; + int offset; + int size; + int ref; + Eina_Bool write : 1; +}; + +//// for comms +// for clients to connect to cserve +EAPI Eina_Bool evas_cserve_init(void); +EAPI int evas_cserve_use_get(void); +EAPI void evas_cserve_shutdown(void); +EAPI Eina_Bool evas_cserve_image_load(Image_Entry *ie, const char *file, const char *key, RGBA_Image_Loadopts *lopt); +EAPI Eina_Bool evas_cserve_image_data_load(Image_Entry *ie); +EAPI void evas_cserve_image_free(Image_Entry *ie); + +// for the server +EAPI Server *evas_cserve_server_add(void); +EAPI void evas_cserve_server_del(Server *s); +EAPI void evas_cserve_client_send(Client *c, int opcode, int size, unsigned char *data); +EAPI void evas_cserve_server_message_handler_set(Server *s, int (*func) (void *fdata, Server *s, Client *c, int opcode, int size, unsigned char *data), void *data); +EAPI void evas_cserve_server_wait(Server *s, int timeout); + +//// for memory +// for server +EAPI Mem *evas_cserve_mem_new(int size, const char *name); +EAPI void evas_cserve_mem_free(Mem *m); + +// for client +EAPI Mem *evas_cserve_mem_open(int pid, int id, const char *name, int size, int write); +EAPI void evas_cserve_mem_close(Mem *m); + +// for both +EAPI Eina_Bool evas_cserve_mem_resize(Mem *m, int size); +EAPI void evas_cserve_mem_del(int pid, int id); + + +enum +{ + OP_NOP, // 0 + + OP_INIT, // 1 + OP_LOAD, // 2 + OP_UNLOAD, // 3 + OP_LOADDATA, // 4 + OP_PRELOAD, // 5 + OP_FORCEDUNLOAD, // 6 + + OP_INVALID // 6 +}; + +typedef struct +{ + pid_t pid; +} Op_Init; +typedef struct +{ + struct { + int scale_down_by; + double dpi; + int w, h; + } lopt; +} Op_Load; // +"file""key" +typedef struct +{ + void *handle; + struct { + int id; + int offset; + int size; + } mem; + struct { + int w, h; + Eina_Bool alpha : 1; + } image; +} Op_Load_Reply; +typedef struct +{ + void *handle; +} Op_Unload; +typedef struct +{ + void *handle; +} Op_Loaddata; +typedef struct +{ + struct { + int id; + int offset; + int size; + } mem; +} Op_Loaddata_Reply; +typedef struct +{ + void *handle; +} Op_Preload; +typedef struct +{ + void *handle; + struct { + int id; + int offset; + int size; + } mem; +} Op_Preload_Reply; +typedef struct +{ + void *handle; +} Op_Forcedunload; + +#endif + +#endif diff --git a/legacy/evas/src/lib/cserve/evas_cs_client.c b/legacy/evas/src/lib/cserve/evas_cs_client.c new file mode 100644 index 0000000000..d9b9248caf --- /dev/null +++ b/legacy/evas/src/lib/cserve/evas_cs_client.c @@ -0,0 +1,245 @@ +#include "evas_cs.h" + +#ifdef EVAS_CSERVE + +static Server * +server_connect(void) +{ + Server *s; + char buf[PATH_MAX]; + int curstate = 0; + struct sockaddr_un socket_unix; + int socket_unix_len; + + s = calloc(1, sizeof(Server)); + if (!s) return NULL; + s->fd = -1; + snprintf(buf, sizeof(buf), "/tmp/.evas-cserve-%x", getuid()); + s->socket_path = strdup(buf); + if (!s->socket_path) + { + free(s); + return NULL; + } + s->fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (s->fd < 0) goto error; + if (fcntl(s->fd, F_SETFD, FD_CLOEXEC) < 0) goto error; + if (setsockopt(s->fd, SOL_SOCKET, SO_REUSEADDR, &curstate, sizeof(curstate)) < 0) + goto error; + socket_unix.sun_family = AF_UNIX; + strncpy(socket_unix.sun_path, buf, sizeof(socket_unix.sun_path)); + socket_unix_len = LENGTH_OF_SOCKADDR_UN(&socket_unix); + if (connect(s->fd, (struct sockaddr *)&socket_unix, socket_unix_len) < 0) goto error; + return s; + error: + if (s->fd >= 0) close(s->fd); + free(s->socket_path); + free(s); + return NULL; +} + +static void +server_disconnect(Server *s) +{ + close(s->fd); + free(s->socket_path); + free(s); +} + +static int +server_send(Server *s, int opcode, int size, unsigned char *data) +{ + int ints[2]; + int num; + + ints[0] = size; + ints[1] = opcode; + num = write(s->fd, ints, (sizeof(int) * 2)); + if (num < 0) return 0; + num = write(s->fd, data, size); + if (num < 0) return 0; + return 1; +} + +static unsigned char * +server_read(Server *s, int *opcode, int *size) +{ + int ints[2], num; + unsigned char *data; + + num = read(s->fd, ints, sizeof(int) * 2); + if (num != (sizeof(int) * 2)) return NULL; + *size = ints[0]; + *opcode = ints[1]; + if ((*size < 0) || (*size > (1024 * 1024))) return NULL; + data = malloc(*size); + if (!data) return NULL; + num = read(s->fd, data, *size); + if (num != *size) + { + free(data); + return NULL; + } + return data; +} + +static int +server_init(Server *s) +{ + Op_Init msg, *rep; + int opcode; + int size; + + msg.pid = getpid(); + if (!server_send(s, OP_INIT, sizeof(msg), (unsigned char *)(&msg))) + return 0; + rep = (Op_Init *)server_read(s, &opcode, &size); + if (rep) + { + s->pid = rep->pid; + free(rep); + } + return 1; +} + +static Server *cserve = NULL; +static int csrve_init = 0; + +EAPI Eina_Bool +evas_cserve_init(void) +{ + csrve_init++; + if (cserve) return 1; + cserve = server_connect(); + if (!cserve) return 0; + if (!server_init(cserve)) + { + server_disconnect(cserve); + cserve = NULL; + return 0; + } + return 1; +} + +EAPI int +evas_cserve_use_get(void) +{ + return csrve_init; +} + +EAPI void +evas_cserve_shutdown(void) +{ + csrve_init--; + if (csrve_init > 0) return; + if (!cserve) return; + server_disconnect(cserve); + cserve = NULL; +} + +static void +server_reinit(void) +{ + if (cserve) return; + cserve = server_connect(); + if (cserve) + { + if (!server_init(cserve)) + { + server_disconnect(cserve); + cserve = NULL; + } + } +} + +EAPI Eina_Bool +evas_cserve_image_load(Image_Entry *ie, const char *file, const char *key, RGBA_Image_Loadopts *lopt) +{ + Op_Load msg; + Op_Load_Reply *rep; + unsigned char *buf; + int flen, klen; + int opcode; + int size; + + if (csrve_init > 0) server_reinit(); + else return 0; + if (!cserve) return 0; + if (!key) key = ""; + memset(&msg, 0, sizeof(msg)); + msg.lopt.scale_down_by = lopt->scale_down_by; + msg.lopt.dpi = lopt->dpi; + msg.lopt.w = lopt->w; + msg.lopt.h = lopt->h; + flen = strlen(file) + 1; + klen = strlen(key) + 1; + buf = malloc(sizeof(msg) + flen + klen); + memcpy(buf, &msg, sizeof(msg)); + strcpy(buf + sizeof(msg), file); + strcpy(buf + sizeof(msg) + flen, key); + if (!buf) return 0; + if (!server_send(cserve, OP_LOAD, + sizeof(msg) + flen + klen, + buf)) + { + free(buf); + return 0; + } + free(buf); + if (!cserve) return 0; + rep = (Op_Load_Reply *)server_read(cserve, &opcode, &size); + if ((rep) && (opcode == OP_LOAD) && (size == sizeof(Op_Load_Reply))) + { + ie->w = rep->image.w; + ie->h = rep->image.h; + ie->flags.alpha = rep->image.alpha; + ie->data1 = rep->handle; + } + if (ie->data1 == NULL) return 0; + return 1; +} + +EAPI Eina_Bool +evas_cserve_image_data_load(Image_Entry *ie) +{ + Op_Loaddata msg; + Op_Loaddata_Reply *rep; + int opcode; + int size; + if (csrve_init > 0) server_reinit(); + else return 0; + if (!cserve) return 0; + if (ie->data1 == NULL) return 0; + memset(&msg, 0, sizeof(msg)); + msg.handle = ie->data1; + if (!server_send(cserve, OP_LOADDATA, sizeof(msg), (unsigned char *)(&msg))) + return 0; + if (!cserve) return 0; + rep = (Op_Loaddata_Reply *)server_read(cserve, &opcode, &size); + if ((rep) && (opcode == OP_LOADDATA) && (size == sizeof(Op_Loaddata_Reply))) + { + if (rep->mem.size <= 0) return 0; + ie->data2 = evas_cserve_mem_open(cserve->pid, rep->mem.id, NULL, rep->mem.size, 0); + return 1; + } + return 0; +} + +EAPI void +evas_cserve_image_free(Image_Entry *ie) +{ + Op_Unload msg; + + if (csrve_init > 0) server_reinit(); + else return; + if (!cserve) return; + if (ie->data1 == NULL) return; + memset(&msg, 0, sizeof(msg)); + msg.handle = ie->data1; + if (ie->data2) evas_cserve_mem_close(ie->data2); + ie->data2 = NULL; + server_send(cserve, OP_UNLOAD, sizeof(msg), (unsigned char *)(&msg)); + ie->data1 = NULL; +} + +#endif diff --git a/legacy/evas/src/lib/cserve/evas_cs_main.c b/legacy/evas/src/lib/cserve/evas_cs_main.c new file mode 100644 index 0000000000..7bb2978739 --- /dev/null +++ b/legacy/evas/src/lib/cserve/evas_cs_main.c @@ -0,0 +1,5 @@ +#include "evas_cs.h" + +#ifdef EVAS_CSERVE + +#endif diff --git a/legacy/evas/src/lib/cserve/evas_cs_mem.c b/legacy/evas/src/lib/cserve/evas_cs_mem.c new file mode 100644 index 0000000000..3e7a944c7b --- /dev/null +++ b/legacy/evas/src/lib/cserve/evas_cs_mem.c @@ -0,0 +1,155 @@ +#include "evas_cs.h" + +#ifdef EVAS_CSERVE + +EAPI Mem * +evas_cserve_mem_new(int size, const char *name) +{ + Mem *m; + static int id = 0; + char buf[PATH_MAX]; + + m = calloc(1, sizeof(Mem)); + if (!m) return NULL; + if (name) + snprintf(buf, sizeof(buf), "/evas-shm-%x.%s", getuid(), name); + else + { + id++; + snprintf(buf, sizeof(buf), "/evas-shm-%x.%x.%x", getuid(), getpid(), id); + } + m->id = id; + m->offset = 0; + m->name = strdup(buf); + if (!m->name) + { + free(m); + return NULL; + } + m->size = size; + m->fd = shm_open(m->name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); + if (m->fd < 0) + { + free(m->name); + free(m); + return NULL; + } + if (ftruncate(m->fd, m->size) < 0) + { + shm_unlink(m->name); + close(m->fd); + free(m->name); + free(m); + return NULL; + } + m->data = mmap(NULL, m->size, PROT_READ | PROT_WRITE, MAP_SHARED, m->fd, 0); + if (m->data == MAP_FAILED) + { + shm_unlink(m->name); + close(m->fd); + free(m->name); + free(m); + return NULL; + } + m->ref = 1; + m->write = 1; + return m; +} + +EAPI void +evas_cserve_mem_free(Mem *m) +{ + shm_unlink(m->name); + munmap(m->data, m->size); + close(m->fd); + free(m->name); + free(m); +} + +EAPI Mem * +evas_cserve_mem_open(int pid, int id, const char *name, int size, int write) +{ + Mem *m; + char buf[PATH_MAX]; + + m = calloc(1, sizeof(Mem)); + if (!m) return NULL; + if (name) + snprintf(buf, sizeof(buf), "/evas-shm-%x.%s", getuid(), name); + else + snprintf(buf, sizeof(buf), "/evas-shm-%x.%x.%x", getuid(), pid, id); + m->name = strdup(buf); + if (!m->name) + { + free(m); + return NULL; + } + m->size = size; + if (write) + m->fd = shm_open(m->name, O_RDWR, S_IRUSR | S_IWUSR); + else + m->fd = shm_open(m->name, O_RDONLY, S_IRUSR); + if (m->fd < 0) + { + free(m->name); + free(m); + return NULL; + } + m->write = write; + if (write) + m->data = mmap(NULL, m->size, PROT_READ | PROT_WRITE, MAP_SHARED, m->fd, 0); + else + m->data = mmap(NULL, m->size, PROT_READ, MAP_SHARED, m->fd, 0); + if (m->data == MAP_FAILED) + { + close(m->fd); + free(m->name); + free(m); + return NULL; + } + m->ref = 1; + return m; +} + +EAPI void +evas_cserve_mem_close(Mem *m) +{ + munmap(m->data, m->size); + close(m->fd); + free(m->name); + free(m); +} + +EAPI Eina_Bool +evas_cserve_mem_resize(Mem *m, int size) +{ + if (m->write) + { + if (ftruncate(m->fd, size) < 0) return 0; + munmap(m->data, m->size); + m->data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, m->fd, 0); + } + else + { + munmap(m->data, m->size); + m->data = mmap(NULL, size, PROT_READ, MAP_SHARED, m->fd, 0); + } + if (m->data == MAP_FAILED) + { + m->data = NULL; + return 0; + } + m->size = size; + return 1; +} + +EAPI void +evas_cserve_mem_del(int pid, int id) +{ + char buf[PATH_MAX]; + + snprintf(buf, sizeof(buf), "/evas-shm-%x.%x.%x", getuid(), pid, id); + shm_unlink(buf); +} + +#endif diff --git a/legacy/evas/src/lib/cserve/evas_cs_server.c b/legacy/evas/src/lib/cserve/evas_cs_server.c new file mode 100644 index 0000000000..14e53ccddc --- /dev/null +++ b/legacy/evas/src/lib/cserve/evas_cs_server.c @@ -0,0 +1,343 @@ +#include "evas_cs.h" + +#ifdef EVAS_CSERVE + +EAPI Server * +evas_cserve_server_add(void) +{ + Server *s; + char buf[PATH_MAX]; + struct sockaddr_un socket_unix; + struct linger lin; + mode_t pmode; + int socket_unix_len; + + s = calloc(1, sizeof(Server)); + if (!s) return NULL; + s->fd = -1; + snprintf(buf, sizeof(buf), "/tmp/.evas-cserve-%x", getuid()); + s->socket_path = strdup(buf); + if (!s->socket_path) + { + free(s); + return NULL; + } + pmode = umask(~(S_IRUSR | S_IWUSR)); + start: + s->fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (s->fd < 0) goto error; + if (fcntl(s->fd, F_SETFL, O_NONBLOCK) < 0) goto error; + if (fcntl(s->fd, F_SETFD, FD_CLOEXEC) < 0) goto error; + lin.l_onoff = 1; + lin.l_linger = 0; + if (setsockopt(s->fd, SOL_SOCKET, SO_LINGER, &lin, sizeof(struct linger)) < 0) + goto error; + socket_unix.sun_family = AF_UNIX; + strncpy(socket_unix.sun_path, buf, sizeof(socket_unix.sun_path)); + socket_unix_len = LENGTH_OF_SOCKADDR_UN(&socket_unix); + if (bind(s->fd, (struct sockaddr *)&socket_unix, socket_unix_len) < 0) + { + if ((connect(s->fd, (struct sockaddr *)&socket_unix, socket_unix_len) < 0) && + (unlink(s->socket_path) >= 0)) + { + close(s->fd); + goto start; + } + else + goto error; + } + if (listen(s->fd, 4096) < 0) goto error; + umask(pmode); + return s; + error: + umask(pmode); + if (s->fd >= 0) close(s->fd); + free(s->socket_path); + free(s); + return NULL; +} + +EAPI void +evas_cserve_server_del(Server *s) +{ + /* FIXME: del clients! */ + close(s->fd); + unlink(s->socket_path); + free(s->socket_path); + free(s); +} + +static void +server_accept(Server *s) +{ + Client *c; + int new_fd; + struct sockaddr_in incoming; + size_t size_in; + + size_in = sizeof(struct sockaddr_in); + new_fd = accept(s->fd, (struct sockaddr *)&incoming, (socklen_t *)&size_in); + if (new_fd < 0) return; + fcntl(new_fd, F_SETFL, O_NONBLOCK); + fcntl(new_fd, F_SETFD, FD_CLOEXEC); + c = calloc(1, sizeof(Client)); + if (!c) + { + close(new_fd); + return; + } + c->server = s; + c->fd = new_fd; + s->clients = eina_list_append(s->clients, c); +} + +static void +client_flush(Client *c) +{ + int num; + + num = write(c->fd, c->buf, c->bufsize); + if (num < 0) + { + c->dead = 1; + return; + } + if (num != c->bufsize) + { + unsigned char *buf; + + buf = malloc(c->bufsize - num); + if (buf) + { + memcpy(buf, c->buf + num, c->bufsize - num); + free(c->buf); + c->bufsize = c->bufsize - num; + c->bufalloc = c->bufsize; + c->buf = buf; + } + } + else + { + free(c->buf); + c->buf = NULL; + c->bufsize = 0; + c->bufalloc = 0; + } +} + +static void +client_buf_add(Client *c, unsigned char *data, int size) +{ + int newsize; + unsigned char *buf; + + newsize = c->bufalloc + size; + if (newsize > c->bufalloc) + { + c->bufalloc + newsize + 1024; + buf = realloc(c->buf, c->bufalloc); + if (buf) c->buf = buf; + else return; + } + memcpy(c->buf + c->bufsize, data, size); + c->bufsize += size; +} + +static void +client_write(Client *c, unsigned char *data, int size) +{ + int num; + + num = write(c->fd, data, size); + if (num != size) + client_buf_add(c, data + num, size - num); +} + +EAPI void +evas_cserve_client_send(Client *c, int opcode, int size, unsigned char *data) +{ + unsigned char *data2; + int *ints; + + data2 = malloc(size + (sizeof(int) * 2)); + if (!data2) return; + ints = (int *)data2; + ints[0] = size; + ints[1] = opcode; + memcpy(data2 + (sizeof(int) * 2), data, size); + client_write(c, data2, size + (sizeof(int) * 2)); + free(data2); +} + +static void +server_message_handle(Server *s, Client *c, int opcode, int size, unsigned char *data) +{ + if (s->func) s->func(s->data, s, c, opcode, size, data); +} + +EAPI void +evas_cserve_server_message_handler_set(Server *s, int (*func) (void *fdata, Server *s, Client *c, int opcode, int size, unsigned char *data), void *data) +{ + s->func = func; + s->data = data; +} + +static int +server_parse(Server *s, Client *c) +{ + int *ints; + unsigned char *data, *newbuf; + + if (c->inbufsize < sizeof(int)) return; + ints = (int *)((c->inbuf)); + if ((ints[0] < 0) || (ints[0] > (1024 * 1024))) + return; + if (c->inbufsize < (ints[0] + (sizeof(int) * 2))) + { + return 0; + } + data = c->inbuf + (sizeof(int) * 2); + server_message_handle(s, c, ints[1], ints[0], data); + c->inbufalloc -= ints[0] + (sizeof(int) * 2); + if (c->inbufalloc == 0) + { + free(c->inbuf); + c->inbuf = NULL; + c->inbufsize = 0; + return 0; + } + newbuf = malloc(c->inbufalloc); + if (!newbuf) + { + c->inbufalloc += ints[0] + (sizeof(int) * 2); + /* fixme - bad situation */ + return 0; + } + memcpy(newbuf, c->inbuf + ints[0] + (sizeof(int) * 2), c->inbufalloc); + c->inbufsize -= ints[0] + (sizeof(int) * 2); + free(c->inbuf); + c->inbuf = newbuf; + return 1; +} + +static void +server_data(Server *s, Client *c, unsigned char *data, int size) +{ + if (!c->inbuf) + { + c->inbuf = malloc(size); + if (c->inbuf) + { + memcpy(c->inbuf, data, size); + c->inbufalloc = size; + c->inbufsize = size; + } + else + { + /* fixme - bad situation */ + return; + } + } + else + { + int size2; + + size2 = c->inbufsize + size; + if (size2 > c->inbufalloc) + { + unsigned char *newbuf; + + c->inbufalloc = size2; + newbuf = realloc(c->inbuf, c->inbufalloc); + if (newbuf) c->inbuf = newbuf; + else size2 = 0; + } + if (size2 > 0) + { + memcpy(c->inbuf + c->inbufsize, data, size); + c->inbufsize = size2; + } + else + { + /* fixme - bad situation */ + return; + } + } + while (server_parse(s, c)); +} + +EAPI void +evas_cserve_server_wait(Server *s, int timeout) +{ + fd_set rset, wset, xset; + int maxfd; + int ret; + struct timeval to; + Eina_List *l, *dead = NULL; + Client *c; + + maxfd = 0; + FD_ZERO(&rset); + FD_ZERO(&wset); + FD_ZERO(&xset); + FD_SET(s->fd, &rset); + if (s->fd > maxfd) maxfd = s->fd; + EINA_LIST_FOREACH(s->clients, l, c) + { + FD_SET(c->fd, &rset); + if (c->buf) + FD_SET(c->fd, &wset); + if (c->fd > maxfd) maxfd = c->fd; + } + if (timeout > 0) + { + to.tv_sec = timeout / 1000000; + to.tv_usec = timeout % 1000000; + ret = select(maxfd + 1, &rset, &wset, &xset, &to); + } + else + ret = select(maxfd + 1, &rset, &wset, &xset, NULL); + if (ret < 1) return; + + EINA_LIST_FOREACH(s->clients, l, c) + { + if (c->dead) continue; + if (FD_ISSET(c->fd, &rset)) + { + char buf[16384]; + int num; + + errno = 0; + num = read(c->fd, buf, sizeof(buf)); + if (num <= 0) + { + c->dead = 1; + dead = eina_list_append(dead, c); + } + else if (num > 0) + { + server_data(s, c, buf, num); + } + } + else if (FD_ISSET(c->fd, &wset)) + { + client_flush(c); + if (c->dead) dead = eina_list_append(dead, c); + } + } + if (FD_ISSET(s->fd, &rset)) + { + server_accept(s); + } + EINA_LIST_FREE(dead, c) + { + if (c->func) c->func(c->data, c); + s->clients = eina_list_remove(s->clients, c); + close(c->fd); + if (c->buf) free(c->buf); + if (c->inbuf) free(c->inbuf); + free(c); + } +} + +#endif diff --git a/legacy/evas/src/lib/engines/common/Makefile.am b/legacy/evas/src/lib/engines/common/Makefile.am index bd76ebabc0..4b998bc15e 100644 --- a/legacy/evas/src/lib/engines/common/Makefile.am +++ b/legacy/evas/src/lib/engines/common/Makefile.am @@ -5,6 +5,7 @@ MAINTAINERCLEANFILES = Makefile.in AM_CPPFLAGS = -I. \ -I$(top_srcdir)/src/lib \ + -I$(top_srcdir)/src/lib/cserve \ -I$(top_srcdir)/src/lib/include \ -DPACKAGE_BIN_DIR=\"$(bindir)\" \ -DPACKAGE_LIB_DIR=\"$(libdir)\" \ diff --git a/legacy/evas/src/lib/engines/common/evas_image_load.c b/legacy/evas/src/lib/engines/common/evas_image_load.c index 9a6a86b783..1fac753b0a 100644 --- a/legacy/evas/src/lib/engines/common/evas_image_load.c +++ b/legacy/evas/src/lib/engines/common/evas_image_load.c @@ -4,6 +4,7 @@ #include "evas_common.h" #include "evas_private.h" +#include "evas_cs.h" extern Eina_List *evas_modules; @@ -43,6 +44,16 @@ evas_common_load_rgba_image_module_from_file(Image_Entry *ie) char *dot; int i; + +#ifdef EVAS_CSERVE + if (evas_cserve_use_get()) + { + if (evas_cserve_image_load(ie, ie->file, ie->key, &(ie->load_opts))) + { + return 0; + } + } +#endif dot = strrchr (ie->file, '.'); if (dot) { @@ -89,7 +100,7 @@ evas_common_load_rgba_image_module_from_file(Image_Entry *ie) return -1; - ok: + ok: ie->info.module = (void*) em; ie->info.loader = (void*) evas_image_load_func; evas_module_ref((Evas_Module*) ie->info.module); @@ -101,9 +112,30 @@ evas_common_load_rgba_image_data_from_file(Image_Entry *ie) { Evas_Image_Load_Func *evas_image_load_func = NULL; - if (!ie->info.module) return -1; if (ie->flags.loaded) return -1; +#ifdef EVAS_CSERVE + if (ie->data1) + { + if (evas_cserve_image_data_load(ie)) + { + RGBA_Image *im = (RGBA_Image *)ie; + Mem *mem; + + mem = ie->data2; + if (mem) + { + im->image.data = mem->data + mem->offset; + im->image.no_free = 1; + return 0; + } + } + return -1; + } +#endif + + if (!ie->info.module) return -1; + evas_image_load_func = ie->info.loader; evas_module_use((Evas_Module*) ie->info.module); if (!evas_image_load_func->file_data(ie, ie->file, ie->key)) diff --git a/legacy/evas/src/lib/engines/common/evas_image_main.c b/legacy/evas/src/lib/engines/common/evas_image_main.c index 495cf96833..00976ac3ec 100644 --- a/legacy/evas/src/lib/engines/common/evas_image_main.c +++ b/legacy/evas/src/lib/engines/common/evas_image_main.c @@ -152,6 +152,9 @@ _evas_common_rgba_image_delete(Image_Entry *ie) * going to empty this struct out in case this happens again so i know * that something else is overwritign this struct - or not */ // memset(im, 0x99, sizeof(im)); +#ifdef EVAS_CSERVE + if (ie->data1) evas_cserve_image_free(ie); +#endif free(im); } @@ -200,6 +203,9 @@ _evas_common_rgba_image_surface_alloc(Image_Entry *ie, int w, int h) RGBA_Image *im = (RGBA_Image *) ie; size_t siz = 0; +#ifdef EVAS_CSERVE + if (ie->data1) return 0; +#endif if (im->image.no_free) return 0; if (im->flags & RGBA_IMAGE_ALPHA_ONLY) @@ -244,6 +250,10 @@ _evas_common_rgba_image_surface_delete(Image_Entry *ie) if (im->image.data && !im->image.no_free) free(im->image.data); +#ifdef EVAS_CSERVE + else if (ie->data1) + evas_cserve_image_free(ie); +#endif im->image.data = NULL; evas_common_rgba_image_scalecache_dirty(&im->cache_entry); } @@ -258,6 +268,9 @@ _evas_common_rgba_image_dirty_region(Image_Entry* ie, int x __UNUSED__, int y __ { RGBA_Image *im = (RGBA_Image *) ie; +#ifdef EVAS_CSERVE + if (ie->data1) evas_cserve_image_free(ie); +#endif im->flags |= RGBA_IMAGE_IS_DIRTY; evas_common_rgba_image_scalecache_dirty(&im->cache_entry); } @@ -274,8 +287,16 @@ _evas_common_rgba_image_dirty(Image_Entry *ie_dst, const Image_Entry *ie_src) evas_cache_image_load_data(&src->cache_entry); if (_evas_common_rgba_image_surface_alloc(&dst->cache_entry, src->cache_entry.w, src->cache_entry.h)) - return 1; + { +#ifdef EVAS_CSERVE + if (ie_src->data1) evas_cserve_image_free(ie_src); +#endif + return 1; + } +#ifdef EVAS_CSERVE + if (ie_src->data1) evas_cserve_image_free(ie_src); +#endif evas_common_image_colorspace_normalize(src); evas_common_image_colorspace_normalize(dst); /* evas_common_blit_rectangle(src, dst, 0, 0, src->cache_entry.w, src->cache_entry.h, 0, 0); */ @@ -293,8 +314,15 @@ _evas_common_rgba_image_ram_usage(Image_Entry *ie) // ram += sizeof(struct _RGBA_Image); // if (im->info.real_file) ram += strlen(im->info.real_file); // if (im->info.comment) ram += strlen(im->info.comment); - if ((im->image.data) && (!im->image.no_free)) - size += im->cache_entry.w * im->cache_entry.h * sizeof(DATA32); + if (im->image.data) + { +#ifdef EVAS_CSERVE + if ((!im->image.no_free) || (ie->data1)) +#else + if ((!im->image.no_free)) +#endif + size += im->cache_entry.w * im->cache_entry.h * sizeof(DATA32); + } size += evas_common_rgba_image_scalecache_usage_get(&im->cache_entry); return size; } @@ -438,6 +466,9 @@ evas_common_image_colorspace_normalize(RGBA_Image *im) case EVAS_COLORSPACE_ARGB8888: if (im->image.data != im->cs.data) { +#ifdef EVAS_CSERVE + if (((Image_Entry *)im)->data1) evas_cserve_image_free(im); +#endif if (!im->image.no_free) free(im->image.data); im->image.data = im->cs.data; im->cs.no_free = im->image.no_free; diff --git a/legacy/evas/src/lib/include/evas_common.h b/legacy/evas/src/lib/include/evas_common.h index 3167ee1bf1..e63623ba65 100644 --- a/legacy/evas/src/lib/include/evas_common.h +++ b/legacy/evas/src/lib/include/evas_common.h @@ -471,6 +471,7 @@ struct _Image_Entry #endif Image_Entry_Flags flags; + void *data1, *data2; }; struct _Engine_Image_Entry