[xlib] Add locking around GC cache.

The per-screen cached of most-recently freed GCs lacks suitable locking
for it to be threadsafe.
This commit is contained in:
Chris Wilson 2008-04-10 14:49:47 +01:00
parent 9166686abd
commit dc714106e1
2 changed files with 22 additions and 10 deletions

View file

@ -79,6 +79,7 @@ typedef struct _cairo_xlib_visual_info {
struct _cairo_xlib_screen_info { struct _cairo_xlib_screen_info {
cairo_xlib_screen_info_t *next; cairo_xlib_screen_info_t *next;
cairo_reference_count_t ref_count; cairo_reference_count_t ref_count;
cairo_mutex_t mutex;
cairo_xlib_display_t *display; cairo_xlib_display_t *display;
Screen *screen; Screen *screen;

View file

@ -256,12 +256,14 @@ _cairo_xlib_screen_info_close_display (cairo_xlib_screen_info_t *info)
{ {
int i; int i;
CAIRO_MUTEX_LOCK (info->mutex);
for (i = 0; i < ARRAY_LENGTH (info->gc); i++) { for (i = 0; i < ARRAY_LENGTH (info->gc); i++) {
if (info->gc[i] != NULL) { if (info->gc[i] != NULL) {
XFreeGC (info->display->display, info->gc[i]); XFreeGC (info->display->display, info->gc[i]);
info->gc[i] = NULL; info->gc[i] = NULL;
} }
} }
CAIRO_MUTEX_UNLOCK (info->mutex);
} }
void void
@ -295,6 +297,8 @@ _cairo_xlib_screen_info_destroy (cairo_xlib_screen_info_t *info)
_cairo_array_fini (&info->visuals); _cairo_array_fini (&info->visuals);
CAIRO_MUTEX_FINI (info->mutex);
free (info); free (info);
} }
@ -335,6 +339,7 @@ _cairo_xlib_screen_info_get (Display *dpy, Screen *screen)
info = malloc (sizeof (cairo_xlib_screen_info_t)); info = malloc (sizeof (cairo_xlib_screen_info_t));
if (info != NULL) { if (info != NULL) {
CAIRO_REFERENCE_COUNT_INIT (&info->ref_count, 2); /* Add one for display cache */ CAIRO_REFERENCE_COUNT_INIT (&info->ref_count, 2); /* Add one for display cache */
CAIRO_MUTEX_INIT (info->mutex);
info->display = _cairo_xlib_display_reference (display); info->display = _cairo_xlib_display_reference (display);
info->screen = screen; info->screen = screen;
info->has_render = FALSE; info->has_render = FALSE;
@ -385,16 +390,18 @@ GC
_cairo_xlib_screen_get_gc (cairo_xlib_screen_info_t *info, int depth) _cairo_xlib_screen_get_gc (cairo_xlib_screen_info_t *info, int depth)
{ {
GC gc; GC gc;
cairo_bool_t needs_reset;
depth = depth_to_index (depth); depth = depth_to_index (depth);
CAIRO_MUTEX_LOCK (info->mutex);
gc = info->gc[depth]; gc = info->gc[depth];
info->gc[depth] = NULL; info->gc[depth] = NULL;
needs_reset = info->gc_needs_clip_reset & (1 << depth);
CAIRO_MUTEX_UNLOCK (info->mutex);
if (info->gc_needs_clip_reset & (1 << depth)) { if (needs_reset)
XSetClipMask(info->display->display, gc, None); XSetClipMask(info->display->display, gc, None);
info->gc_needs_clip_reset &= ~(1 << depth);
}
return gc; return gc;
} }
@ -403,21 +410,25 @@ cairo_status_t
_cairo_xlib_screen_put_gc (cairo_xlib_screen_info_t *info, int depth, GC gc, cairo_bool_t reset_clip) _cairo_xlib_screen_put_gc (cairo_xlib_screen_info_t *info, int depth, GC gc, cairo_bool_t reset_clip)
{ {
cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_status_t status = CAIRO_STATUS_SUCCESS;
GC oldgc;
depth = depth_to_index (depth); depth = depth_to_index (depth);
if (info->gc[depth] != NULL) { CAIRO_MUTEX_LOCK (info->mutex);
status = _cairo_xlib_display_queue_work (info->display, oldgc = info->gc[depth];
(cairo_xlib_notify_func) XFreeGC,
info->gc[depth],
NULL);
}
info->gc[depth] = gc; info->gc[depth] = gc;
if (reset_clip) if (reset_clip)
info->gc_needs_clip_reset |= 1 << depth; info->gc_needs_clip_reset |= 1 << depth;
else else
info->gc_needs_clip_reset &= ~(1 << depth); info->gc_needs_clip_reset &= ~(1 << depth);
CAIRO_MUTEX_UNLOCK (info->mutex);
if (oldgc != NULL) {
status = _cairo_xlib_display_queue_work (info->display,
(cairo_xlib_notify_func) XFreeGC,
oldgc,
NULL);
}
return status; return status;
} }