shared cache server++

is it ok?

1. it can be --disabled in evas's configure, but i think it works WITHOUT
disabling it (runtime) as it falls back to the old way of loading
2. it may cause build problems on some platforms - without it being enabled
we won't find out, so enable.
3. it needs enabling runtime to make use of it so it should be safe for now
until you enable it.

what is it?

it is a SHARED cache server - that means images loaded are loaded BY the
cache server (not by the actual process using evas). images are shared via
shared memory segments (shm_open + mmap). this means only 1 copy is in all
ram at any time - no matter how many processes need it , and its only loaded
once. also if another app has already loaded the same data - and its in the
cache or active hash, then another process needing the same stuff will avoid
the loads as it will just get instant replies from the cache of "image already
there". as it runs in its own process it can also time-out images from the
cache too.

right now you enable it by doing 2 things

1. run evas_cserve (it has cmd-line options to configure cache etc.
2. export EVAS_CSERVE=1 (im the environment of apps that should use the cache
server).

it works (for me) without crashes or problems. except for the following:

1. preloading doesnt work so its disabled if cserve is enabled. thisis
because the load threads interfere withthe unix comms socket causing
problems. this need to really change and have the cserve know about/do
preload and let the select() on the evas async events fd listen for the
unsolicited reply "load done". but it's not broken - simple preloads are
syncronous and forced if cserve is enabled (at build time).
2. if cserve is killed/crashes every app using it will have a bad day. baaad
day. so dont do it. also cserve may be vulnerable to apps crashing on it - it
may also exit with sigpipe. this needs fixing.
3. if the apps load using relative paths - this will break as it doesnt
account for the CWD of the client currently. will be fixed.
4. no way to change cache config runtime (yet)
5. no way to get internal cache state (yet).
6. if cache server exist - it wont clean up the shmem file nodes in /dev/shm
- it will clean on restart (remove the old junk). this needs fixing.

if you fine other issues - let me know.

things for the future:

1. now its a separate server.. the server could do async http etc. loads too
2. as a server it could monitor history of usage of files and images and
auto-pre-load files it knows historically are loaded then whose data is 
immediately accessed.
3. the same infra could be used to share font loads (freetype and/or 
fontconfig data).
4. ultimately being able to share rendered font glyphs will help a lot too.
5. it could, on its own, monitor "free memory" and when free memory runs
load, reduce cache size dynamically. (improving low memory situations).
6. it should get a gui to query cache state/contents and display visually.
this would be awesome to have a list of thumbnails that show whats in the
cache, how many referencesa they have, last active timestamps etc.

blah blah.

please let me know if the build is broken asap though as i will vanish
offline for a bit in about 24hrs...



SVN revision: 40478
This commit is contained in:
Carsten Haitzler 2009-05-01 07:11:07 +00:00
parent de2cd99b4b
commit 46e8aa1b0d
19 changed files with 1899 additions and 12 deletions

View File

@ -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"

View File

@ -1,3 +1,3 @@
MAINTAINERCLEANFILES = Makefile.in
SUBDIRS = lib modules
SUBDIRS = lib bin modules

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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 <pthread.h>
@ -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;

View File

@ -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)\" \

View File

@ -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();

View File

@ -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

View File

@ -0,0 +1,199 @@
#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

View File

@ -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

View File

@ -0,0 +1,5 @@
#include "evas_cs.h"
#ifdef EVAS_CSERVE
#endif

View File

@ -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

View File

@ -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

View File

@ -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)\" \

View File

@ -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))

View File

@ -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;

View File

@ -471,6 +471,7 @@ struct _Image_Entry
#endif
Image_Entry_Flags flags;
void *data1, *data2;
};
struct _Engine_Image_Entry