Fix invalid access if using async-render

Ouch, that was nasty! src/lib/cache/evas_cache_image.c was assuming
all Image_Entry were RGBA_Image (why?!?!?), thus doing the cast and
having mutexes and other to operate on garbage (possibly crashing due
segv). This happened to be the case with Soft16_Image used by
software_16 engines.

I'm not sure, but this may fix problems that people noticed with
async-render hanging their systems even if not explicitly enabled
during runtime.

I also found it quite strange the number of locks required by this
code! Clearly we could use macros to simplify and avoid bugs, but
maybe some atomic_inc/dec code should be used to remove half of the
mutexes in that code?

/me wonders what kinds of bug more we can expect from this code :-/



SVN revision: 50300
This commit is contained in:
Gustavo Sverzut Barbieri 2010-07-16 22:52:04 +00:00
parent a7e471700b
commit 7521047f09
4 changed files with 75 additions and 74 deletions

View File

@ -935,16 +935,16 @@ evas_cache_image_drop(Image_Entry *im)
if (references == 0)
{
#ifdef EVAS_FRAME_QUEUING
LKL(((RGBA_Image *)im)->ref_fq_add);
LKL(((RGBA_Image *)im)->ref_fq_del);
if (((RGBA_Image *)im)->ref_fq[0] != ((RGBA_Image *)im)->ref_fq[1])
LKL(im->ref_fq_add);
LKL(im->ref_fq_del);
if (im->ref_fq[0] != im->ref_fq[1])
{
LKU(((RGBA_Image *)im)->ref_fq_add);
LKU(((RGBA_Image *)im)->ref_fq_del);
LKU(im->ref_fq_add);
LKU(im->ref_fq_del);
return;
}
LKU(((RGBA_Image *)im)->ref_fq_add);
LKU(((RGBA_Image *)im)->ref_fq_del);
LKU(im->ref_fq_add);
LKU(im->ref_fq_del);
#endif
#ifdef BUILD_ASYNC_PRELOAD

View File

@ -142,9 +142,9 @@ _evas_common_rgba_image_new(void)
im->flags = RGBA_IMAGE_NOTHING;
im->ref = 1;
#ifdef EVAS_FRAME_QUEUING
LKI(im->ref_fq_add);
LKI(im->ref_fq_del);
pthread_cond_init(&(im->cond_fq_del), NULL);
LKI(im->cache_entry.ref_fq_add);
LKI(im->cache_entry.ref_fq_del);
pthread_cond_init(&(im->cache_entry.cond_fq_del), NULL);
#endif
evas_common_rgba_image_scalecache_init(&im->cache_entry);
@ -159,9 +159,9 @@ _evas_common_rgba_image_delete(Image_Entry *ie)
#ifdef BUILD_PIPE_RENDER
evas_common_pipe_free(im);
# ifdef EVAS_FRAME_QUEUING
LKD(im->ref_fq_add);
LKD(im->ref_fq_del);
pthread_cond_destroy(&(im->cond_fq_del));
LKD(im->cache_entry.ref_fq_add);
LKD(im->cache_entry.ref_fq_del);
pthread_cond_destroy(&(im->cache_entry.cond_fq_del));
# endif
#endif
evas_common_rgba_image_scalecache_shutdown(&im->cache_entry);

View File

@ -19,9 +19,9 @@ evas_common_surface_alloc(void *surface, int x, int y, int w, int h)
e_surface = calloc(1, sizeof(Evas_Surface));
e_surface->im = surface;
LKL(e_surface->im->ref_fq_add);
e_surface->im->ref_fq[0]++;
LKU(e_surface->im->ref_fq_add);
LKL(e_surface->im->cache_entry.ref_fq_add);
e_surface->im->cache_entry.ref_fq[0]++;
LKU(e_surface->im->cache_entry.ref_fq_add);
e_surface->x = x;
e_surface->y = y;
e_surface->w = w;
@ -39,9 +39,9 @@ evas_common_surface_dealloc(Evas_Surface *surface)
{
d_surface = surface;
surface = (Evas_Surface *)eina_inlist_remove(EINA_INLIST_GET(surface), EINA_INLIST_GET(d_surface));
LKL(d_surface->im->ref_fq_del);
d_surface->im->ref_fq[1]++;
LKU(d_surface->im->ref_fq_del);
LKL(d_surface->im->cache_entry.ref_fq_del);
d_surface->im->cache_entry.ref_fq[1]++;
LKU(d_surface->im->cache_entry.ref_fq_del);
free(d_surface);
@ -287,7 +287,7 @@ evas_common_pipe_thread(void *data)
// {
// thinfo->info = NULL;
// INF(" TH %i GO", thinfo->thread_num);
EINA_INLIST_FOREACH(EINA_INLIST_GET(info->im->pipe), p)
EINA_INLIST_FOREACH(EINA_INLIST_GET(info->im->cache_entry.pipe), p)
{
int i;
@ -378,7 +378,7 @@ evas_common_frameq_thread(void *data)
p_info.w = surface->im->cache_entry.w;
p_info.h = surface->im->cache_entry.h;
EINA_INLIST_FOREACH(EINA_INLIST_GET(p_info.im->pipe), p)
EINA_INLIST_FOREACH(EINA_INLIST_GET(p_info.im->cache_entry.pipe), p)
{
int i;
@ -820,7 +820,7 @@ evas_common_pipe_begin(RGBA_Image *im)
return;
#endif
if (!im->pipe) return;
if (!im->cache_entry.pipe) return;
if (thread_num == 1) return;
y = 0;
h = im->cache_entry.h / thread_num;
@ -965,7 +965,7 @@ evas_common_pipe_flush(RGBA_Image *im)
RGBA_Pipe *p;
int i;
if (!im->pipe) return;
if (!im->cache_entry.pipe) return;
#ifndef EVAS_FRAME_QUEUING
@ -1002,13 +1002,13 @@ evas_common_pipe_free(RGBA_Image *im)
RGBA_Pipe *p;
int i;
if (!im->pipe) return;
if (!im->cache_entry.pipe) return;
/* FIXME: PTHREAD join all threads here (if not finished) */
/* free pipe */
while (im->pipe)
while (im->cache_entry.pipe)
{
p = im->pipe;
p = im->cache_entry.pipe;
for (i = 0; i < p->op_num; i++)
{
if (p->op[i].free_func)
@ -1016,7 +1016,7 @@ evas_common_pipe_free(RGBA_Image *im)
p->op[i].free_func(&(p->op[i]));
}
}
im->pipe = (RGBA_Pipe *)eina_inlist_remove(EINA_INLIST_GET(im->pipe), EINA_INLIST_GET(p));
im->cache_entry.pipe = (RGBA_Pipe *)eina_inlist_remove(EINA_INLIST_GET(im->cache_entry.pipe), EINA_INLIST_GET(p));
free(p);
}
}
@ -1057,8 +1057,8 @@ evas_common_pipe_rectangle_draw(RGBA_Image *dst, RGBA_Draw_Context *dc,
RGBA_Pipe_Op *op;
if ((w < 1) || (h < 1)) return;
dst->pipe = evas_common_pipe_add(dst->pipe, &op);
if (!dst->pipe) return;
dst->cache_entry.pipe = evas_common_pipe_add(dst->cache_entry.pipe, &op);
if (!dst->cache_entry.pipe) return;
op->op.rect.x = x;
op->op.rect.y = y;
op->op.rect.w = w;
@ -1100,8 +1100,8 @@ evas_common_pipe_line_draw(RGBA_Image *dst, RGBA_Draw_Context *dc,
{
RGBA_Pipe_Op *op;
dst->pipe = evas_common_pipe_add(dst->pipe, &op);
if (!dst->pipe) return;
dst->cache_entry.pipe = evas_common_pipe_add(dst->cache_entry.pipe, &op);
if (!dst->cache_entry.pipe) return;
op->op.line.x0 = x0;
op->op.line.y0 = y0;
op->op.line.x1 = x1;
@ -1158,8 +1158,8 @@ evas_common_pipe_poly_draw(RGBA_Image *dst, RGBA_Draw_Context *dc,
RGBA_Polygon_Point *pts = NULL, *p, *pp;
if (!points) return;
dst->pipe = evas_common_pipe_add(dst->pipe, &op);
if (!dst->pipe) return;
dst->cache_entry.pipe = evas_common_pipe_add(dst->cache_entry.pipe, &op);
if (!dst->cache_entry.pipe) return;
/* FIXME: copy points - maybe we should refcount? */
for (p = points; p; p = (RGBA_Polygon_Point *)(EINA_INLIST_GET(p))->next)
{
@ -1244,8 +1244,8 @@ evas_common_pipe_grad_draw(RGBA_Image *dst, RGBA_Draw_Context *dc,
RGBA_Pipe_Op *op;
if (!gr) return;
dst->pipe = evas_common_pipe_add(dst->pipe, &op);
if (!dst->pipe) return;
dst->cache_entry.pipe = evas_common_pipe_add(dst->cache_entry.pipe, &op);
if (!dst->cache_entry.pipe) return;
op->op.grad.x = x;
op->op.grad.y = y;
op->op.grad.w = w;
@ -1330,8 +1330,8 @@ evas_common_pipe_grad2_draw(RGBA_Image *dst, RGBA_Draw_Context *dc,
RGBA_Pipe_Op *op;
if (!gr) return;
dst->pipe = evas_common_pipe_add(dst->pipe, &op);
if (!dst->pipe) return;
dst->cache_entry.pipe = evas_common_pipe_add(dst->cache_entry.pipe, &op);
if (!dst->cache_entry.pipe) return;
op->op.grad2.x = x;
op->op.grad2.y = y;
op->op.grad2.w = w;
@ -1416,8 +1416,8 @@ evas_common_pipe_text_draw(RGBA_Image *dst, RGBA_Draw_Context *dc,
RGBA_Pipe_Op *op;
if ((!fn) || (!text)) return;
dst->pipe = evas_common_pipe_add(dst->pipe, &op);
if (!dst->pipe) return;
dst->cache_entry.pipe = evas_common_pipe_add(dst->cache_entry.pipe, &op);
if (!dst->cache_entry.pipe) return;
op->op.text.x = x;
op->op.text.y = y;
op->op.text.text = strdup(text);
@ -1439,10 +1439,10 @@ static void
evas_common_pipe_op_image_free(RGBA_Pipe_Op *op)
{
#ifdef EVAS_FRAME_QUEUING
LKL(op->op.image.src->ref_fq_del);
op->op.image.src->ref_fq[1]++;
LKU(op->op.image.src->ref_fq_del);
pthread_cond_signal(&(op->op.image.src->cond_fq_del));
LKL(op->op.image.src->cache_entry.ref_fq_del);
op->op.image.src->cache_entry.ref_fq[1]++;
LKU(op->op.image.src->cache_entry.ref_fq_del);
pthread_cond_signal(&(op->op.image.src->cache_entry.cond_fq_del));
#else
op->op.image.src->ref--;
if (op->op.image.src->ref == 0)
@ -1460,14 +1460,14 @@ evas_common_pipe_op_image_flush(RGBA_Image *im)
if (! evas_common_frameq_enabled())
return;
LKL(im->ref_fq_add);
LKL(im->ref_fq_del);
LKL(im->cache_entry.ref_fq_add);
LKL(im->cache_entry.ref_fq_del);
while (im->ref_fq[0] != im->ref_fq[1])
pthread_cond_wait(&(im->cond_fq_del), &(im->ref_fq_del));
while (im->cache_entry.ref_fq[0] != im->cache_entry.ref_fq[1])
pthread_cond_wait(&(im->cache_entry.cond_fq_del), &(im->cache_entry.ref_fq_del));
LKU(im->ref_fq_del);
LKU(im->ref_fq_add);
LKU(im->cache_entry.ref_fq_del);
LKU(im->cache_entry.ref_fq_add);
}
#endif
@ -1583,8 +1583,8 @@ evas_common_pipe_image_draw(RGBA_Image *src, RGBA_Image *dst,
if (!src) return;
// evas_common_pipe_flush(src);
dst->pipe = evas_common_pipe_add(dst->pipe, &op);
if (!dst->pipe) return;
dst->cache_entry.pipe = evas_common_pipe_add(dst->cache_entry.pipe, &op);
if (!dst->cache_entry.pipe) return;
op->op.image.smooth = smooth;
op->op.image.sx = src_region_x;
op->op.image.sy = src_region_y;
@ -1595,9 +1595,9 @@ evas_common_pipe_image_draw(RGBA_Image *src, RGBA_Image *dst,
op->op.image.dw = dst_region_w;
op->op.image.dh = dst_region_h;
#ifdef EVAS_FRAME_QUEUING
LKL(src->ref_fq_add);
src->ref_fq[0]++;
LKU(src->ref_fq_add);
LKL(src->cache_entry.ref_fq_add);
src->cache_entry.ref_fq[0]++;
LKU(src->cache_entry.ref_fq_add);
#else
src->ref++;
#endif
@ -1624,9 +1624,9 @@ static void
evas_common_pipe_op_map4_free(RGBA_Pipe_Op *op)
{
#ifdef EVAS_FRAME_QUEUING
LKL(op->op.image.src->ref_fq_del);
op->op.image.src->ref_fq[1]++;
LKU(op->op.image.src->ref_fq_del);
LKL(op->op.image.src->cache_entry.ref_fq_del);
op->op.image.src->cache_entry.ref_fq[1]++;
LKU(op->op.image.src->cache_entry.ref_fq_del);
#else
op->op.map4.src->ref--;
if (op->op.map4.src->ref == 0)
@ -1674,8 +1674,8 @@ evas_common_pipe_map4_draw(RGBA_Image *src, RGBA_Image *dst,
if (!src) return;
pts_copy = malloc(sizeof (RGBA_Map_Point) * 4);
if (!pts_copy) return;
dst->pipe = evas_common_pipe_add(dst->pipe, &op);
if (!dst->pipe)
dst->cache_entry.pipe = evas_common_pipe_add(dst->cache_entry.pipe, &op);
if (!dst->cache_entry.pipe)
{
free(pts_copy);
return;
@ -1687,9 +1687,9 @@ evas_common_pipe_map4_draw(RGBA_Image *src, RGBA_Image *dst,
op->op.map4.smooth = smooth;
op->op.map4.level = level;
#ifdef EVAS_FRAME_QUEUING
LKL(src->ref_fq_add);
src->ref_fq[0]++;
LKU(src->ref_fq_add);
LKL(src->cache_entry.ref_fq_add);
src->cache_entry.ref_fq[0]++;
LKU(src->cache_entry.ref_fq_add);
#else
src->ref++;
#endif
@ -1720,18 +1720,18 @@ evas_common_pipe_map4_render(RGBA_Image *root)
int i;
/* Map imply that we need to process them recursively first. */
for (p = root->pipe; p; p = (RGBA_Pipe *)(EINA_INLIST_GET(p))->next)
for (p = root->cache_entry.pipe; p; p = (RGBA_Pipe *)(EINA_INLIST_GET(p))->next)
{
for (i = 0; i < p->op_num; i++)
{
if (p->op[i].op_func == evas_common_pipe_map4_draw_do)
{
if (p->op[i].op.map4.src->pipe)
if (p->op[i].op.map4.src->cache_entry.pipe)
evas_common_pipe_map4_render(p->op[i].op.map4.src);
}
else if (p->op[i].op_func == evas_common_pipe_image_draw_do)
{
if (p->op[i].op.image.src->pipe)
if (p->op[i].op.image.src->cache_entry.pipe)
evas_common_pipe_map4_render(p->op[i].op.image.src);
}
}

View File

@ -551,6 +551,16 @@ struct _Image_Entry
LK(lock_references); // needed for accessing references
#endif
#ifdef BUILD_PIPE_RENDER
RGBA_Pipe *pipe;
#ifdef EVAS_FRAME_QUEUING
LK(ref_fq_add);
LK(ref_fq_del);
pthread_cond_t cond_fq_del;
int ref_fq[2]; // ref_fq[0] is for addition, ref_fq[1] is for deletion
#endif
#endif
unsigned char scale;
RGBA_Image_Loadopts load_opts;
@ -736,15 +746,6 @@ struct _RGBA_Image
} info;
void *extended_info;
#ifdef BUILD_PIPE_RENDER
RGBA_Pipe *pipe;
#ifdef EVAS_FRAME_QUEUING
LK(ref_fq_add);
LK(ref_fq_del);
pthread_cond_t cond_fq_del;
int ref_fq[2]; // ref_fq[0] is for addition, ref_fq[1] is for deletion
#endif
#endif
int ref;
/* unsigned char scale; */