[cairo-commit] src/cairo-xlib-private.h src/cairo-xlib-screen.c
src/cairo-xlib-surface.c
Chris Wilson
ickle at kemper.freedesktop.org
Thu Apr 12 15:31:56 PDT 2007
src/cairo-xlib-private.h | 6 +++
src/cairo-xlib-screen.c | 77 ++++++++++++++++++++++++++++++++++++-----------
src/cairo-xlib-surface.c | 4 ++
3 files changed, 70 insertions(+), 17 deletions(-)
New commits:
diff-tree 8a4c108a4be6c4650cefe80e68d4c9974ccc27ba (from 50ef5bcf7b5e6cc903f9247256fbd4439887ab5e)
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Thu Apr 12 22:19:03 2007 +0100
Add a reference count to cairo_xlib_screen_info_t
Due to the interaction between multiple threads showing glyphs and
asynchronous CloseDisplays, it is possible for a font to maintain a
cairo_xlib_screen_info_t beyond the CloseDisplay. The simple solution
is to add a reference count in order to track the lifetime of the
cairo_xlib_screen_info_t correctly.
diff --git a/src/cairo-xlib-private.h b/src/cairo-xlib-private.h
index 8ba46a2..e715343 100644
--- a/src/cairo-xlib-private.h
+++ b/src/cairo-xlib-private.h
@@ -48,6 +48,7 @@ struct _cairo_xlib_hook {
struct _cairo_xlib_screen_info {
cairo_xlib_screen_info_t *next;
+ unsigned int ref_count;
Display *display;
Screen *screen;
@@ -61,6 +62,11 @@ struct _cairo_xlib_screen_info {
cairo_private cairo_xlib_screen_info_t *
_cairo_xlib_screen_info_get (Display *display, Screen *screen);
+cairo_private cairo_xlib_screen_info_t *
+_cairo_xlib_screen_info_reference (cairo_xlib_screen_info_t *info);
+cairo_private void
+_cairo_xlib_screen_info_destroy (cairo_xlib_screen_info_t *info);
+
cairo_private cairo_bool_t
_cairo_xlib_add_close_display_hook (Display *display, void (*func) (Display *, void *), void *data, void *key);
cairo_private void
diff --git a/src/cairo-xlib-screen.c b/src/cairo-xlib-screen.c
index f79cb49..4d64726 100644
--- a/src/cairo-xlib-screen.c
+++ b/src/cairo-xlib-screen.c
@@ -267,6 +267,53 @@ _cairo_xlib_call_close_display_hooks (ca
}
}
+static void
+_cairo_xlib_screen_info_reference_lock_held (cairo_xlib_screen_info_t *info)
+{
+ assert (info->ref_count > 0);
+ info->ref_count++;
+}
+
+cairo_xlib_screen_info_t *
+_cairo_xlib_screen_info_reference (cairo_xlib_screen_info_t *info)
+{
+ if (info == NULL)
+ return NULL;
+
+ /* use our global mutex until we get a real atomic inc */
+ CAIRO_MUTEX_LOCK (_cairo_xlib_screen_mutex);
+
+ _cairo_xlib_screen_info_reference_lock_held (info);
+
+ CAIRO_MUTEX_UNLOCK (_cairo_xlib_screen_mutex);
+
+ return info;
+}
+
+static void
+_cairo_xlib_screen_info_destroy_lock_held (cairo_xlib_screen_info_t *info)
+{
+ assert (info->ref_count > 0);
+ if (--info->ref_count)
+ return;
+
+ _cairo_xlib_call_close_display_hooks (info);
+ free (info);
+}
+
+void
+_cairo_xlib_screen_info_destroy (cairo_xlib_screen_info_t *info)
+{
+ if (info == NULL)
+ return;
+
+ CAIRO_MUTEX_LOCK (_cairo_xlib_screen_mutex);
+
+ _cairo_xlib_screen_info_destroy_lock_held (info);
+
+ CAIRO_MUTEX_UNLOCK (_cairo_xlib_screen_mutex);
+}
+
static int
_cairo_xlib_close_display (Display *dpy, XExtCodes *codes)
{
@@ -281,9 +328,10 @@ _cairo_xlib_close_display (Display *dpy,
for (info = _cairo_xlib_screen_list; info; info = next) {
next = info->next;
if (info->display == dpy) {
+ /* trigger the hooks explicitly as we know the display is closing */
_cairo_xlib_call_close_display_hooks (info);
+ _cairo_xlib_screen_info_destroy_lock_held (info);
*prev = next;
- free (info);
} else {
prev = &info->next;
}
@@ -299,31 +347,23 @@ _cairo_xlib_close_display (Display *dpy,
static void
_cairo_xlib_screen_info_reset (void)
{
- cairo_xlib_screen_info_t *info, *next;
-
/*
* Delete everything in the list.
*/
CAIRO_MUTEX_LOCK (_cairo_xlib_screen_mutex);
- for (info = _cairo_xlib_screen_list; info; info = next) {
- next = info->next;
- while (info->close_display_hooks) {
- cairo_xlib_hook_t *hook = info->close_display_hooks;
- info->close_display_hooks = hook->next;
- free (hook);
- }
- free (info);
+ while (_cairo_xlib_screen_list != NULL) {
+ cairo_xlib_screen_info_t *info = _cairo_xlib_screen_list;
+ _cairo_xlib_screen_list = info->next;
+ _cairo_xlib_screen_info_destroy_lock_held (info);
}
- _cairo_xlib_screen_list = NULL;
-
CAIRO_MUTEX_UNLOCK (_cairo_xlib_screen_mutex);
}
static cairo_xlib_screen_info_t *
-_cairo_xlib_screen_info_get_unlocked (Display *dpy, Screen *screen)
+_cairo_xlib_screen_info_get_lock_held (Display *dpy, Screen *screen)
{
cairo_xlib_screen_info_t *info;
cairo_xlib_screen_info_t **prev;
@@ -366,6 +406,7 @@ _cairo_xlib_screen_info_get_unlocked (Di
XESetCloseDisplay (dpy, codes->extension, _cairo_xlib_close_display);
}
+ info->ref_count = 1;
info->display = dpy;
info->screen = screen;
info->close_display_hooks = NULL;
@@ -397,7 +438,9 @@ _cairo_xlib_screen_info_get (Display *dp
*/
CAIRO_MUTEX_LOCK (_cairo_xlib_screen_mutex);
- info = _cairo_xlib_screen_info_get_unlocked (dpy, screen);
+ info = _cairo_xlib_screen_info_get_lock_held (dpy, screen);
+ if (info != NULL)
+ _cairo_xlib_screen_info_reference_lock_held (info);
CAIRO_MUTEX_UNLOCK (_cairo_xlib_screen_mutex);
@@ -414,7 +457,7 @@ _cairo_xlib_add_close_display_hook (Disp
CAIRO_MUTEX_LOCK (_cairo_xlib_screen_mutex);
- info = _cairo_xlib_screen_info_get_unlocked (dpy, NULL);
+ info = _cairo_xlib_screen_info_get_lock_held (dpy, NULL);
if (!info)
goto unlock;
@@ -459,7 +502,7 @@ _cairo_xlib_remove_close_display_hook (D
CAIRO_MUTEX_LOCK (_cairo_xlib_screen_mutex);
- info = _cairo_xlib_screen_info_get_unlocked (dpy, NULL);
+ info = _cairo_xlib_screen_info_get_lock_held (dpy, NULL);
if (!info)
goto unlock;
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 55f95bb..b1790a1 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -341,6 +341,9 @@ _cairo_xlib_surface_finish (void *abstra
if (surface->clip_rects != NULL)
free (surface->clip_rects);
+ if (surface->screen_info != NULL)
+ _cairo_xlib_screen_info_destroy (surface->screen_info);
+
surface->dpy = NULL;
return CAIRO_STATUS_SUCCESS;
@@ -1857,6 +1860,7 @@ _cairo_xlib_surface_create_internal (Dis
surface = malloc (sizeof (cairo_xlib_surface_t));
if (surface == NULL) {
+ _cairo_xlib_screen_info_destroy (screen_info);
_cairo_error (CAIRO_STATUS_NO_MEMORY);
return (cairo_surface_t*) &_cairo_surface_nil;
}
More information about the cairo-commit
mailing list