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)
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
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"
MAINTAINERCLEANFILES = Makefile.in
-SUBDIRS = lib modules
+SUBDIRS = lib bin modules
--- /dev/null
+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
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}
MAINTAINERCLEANFILES = Makefile.in
-SUBDIRS = canvas data cache file engines imaging include
+SUBDIRS = canvas data cache cserve file engines imaging include
AM_CPPFLAGS = \
-I. \
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@ \
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
#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 <pthread.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;
-
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)\" \
#include "evas_common.h"
#include "evas_private.h"
+#include "evas_cs.h"
extern Eina_List *evas_modules;
static int initcount = 0;
evas_module_init();
evas_async_events_init();
+#ifdef EVAS_CSERVE
+ if (getenv("EVAS_CSERVE")) evas_cserve_init();
+#endif
}
return ++initcount;
}
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();
--- /dev/null
+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
--- /dev/null
+#ifndef EVAS_CS_H
+#define EVAS_CS_H 1
+
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+#include <arpa/inet.h>
+#include <errno.h>
+
+#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
--- /dev/null
+#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
--- /dev/null
+#include "evas_cs.h"
+
+#ifdef EVAS_CSERVE
+
+#endif
--- /dev/null
+#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
--- /dev/null
+#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
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)\" \
#include "evas_common.h"
#include "evas_private.h"
+#include "evas_cs.h"
extern Eina_List *evas_modules;
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)
{
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);
{
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))
* 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);
}
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)
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);
}
{
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);
}
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); */
// 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;
}
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;
#endif
Image_Entry_Flags flags;
+ void *data1, *data2;
};
struct _Engine_Image_Entry