[PATCH 1/2] xlib-xcb: Register a XCloseDisplay hook

Uli Schlachter psychon at znc.in
Sun Jul 3 08:45:58 PDT 2011


This commits makes the xlib-xcb backend produce its own cairo_device_t. When
such a device is finished, the underlying xcb device is finished, too.

This per-Display* device is used to manage the registration of a XCloseDisplay
hook via XAddExtension/XESetCloseDisplay in the same way that the xlib backend
does this. The device is necessary to see if we already registered an extension.

This fixes weird errors when running cairo-test-suite with -a -s. They were
caused because the backend didn't see the XCloseDisplay and the next
XOpenDisplay happened to create a xcb_connection_t with the same address as the
last display. This caused the xcb backend to assume lots of wrongness.

This commit makes use of _cairo_xlib_display_mutex which is otherwise compiled
in but not used anywhere when xlib-xcb is enabled.

Signed-off-by: Uli Schlachter <psychon at znc.in>
---
 src/cairo-xlib-xcb-surface.c |  143 +++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 140 insertions(+), 3 deletions(-)

diff --git a/src/cairo-xlib-xcb-surface.c b/src/cairo-xlib-xcb-surface.c
index 8fe0e50..1d1a45b 100644
--- a/src/cairo-xlib-xcb-surface.c
+++ b/src/cairo-xlib-xcb-surface.c
@@ -45,8 +45,25 @@
 
 #include "cairo-xcb-private.h"
 #include "cairo-xlib-xrender-private.h"
+#include "cairo-xlib-private.h"
 
 #include <X11/Xlib-xcb.h>
+#include <X11/Xlibint.h>	/* For XESetCloseDisplay */
+
+struct cairo_xlib_xcb_display_t {
+    cairo_device_t  base;
+
+    Display        *dpy;
+    cairo_device_t *xcb_device;
+    XExtCodes      *codes;
+
+    cairo_list_t    link;
+};
+typedef struct cairo_xlib_xcb_display_t cairo_xlib_xcb_display_t;
+
+/* List of all cairo_xlib_xcb_display_t alive,
+ * protected by _cairo_xlib_display_mutex */
+static cairo_list_t displays;
 
 static cairo_surface_t *
 _cairo_xlib_xcb_surface_create (void *dpy,
@@ -245,6 +262,121 @@ static const cairo_surface_backend_t _cairo_xlib_xcb_surface_backend = {
     _cairo_xlib_xcb_surface_glyphs,
 };
 
+static void
+_cairo_xlib_xcb_display_finish (void *abstract_display)
+{
+    cairo_xlib_xcb_display_t *display = (cairo_xlib_xcb_display_t *) abstract_display;
+
+    CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
+    cairo_list_del (&display->link);
+    CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
+
+    cairo_device_finish (display->xcb_device);
+    cairo_device_destroy (display->xcb_device);
+    display->xcb_device = NULL;
+
+    XESetCloseDisplay (display->dpy, display->codes->extension, NULL);
+}
+
+static int
+_cairo_xlib_xcb_close_display(Display *dpy, XExtCodes *codes)
+{
+    cairo_xlib_xcb_display_t *display;
+
+    CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
+    cairo_list_foreach_entry (display,
+			      cairo_xlib_xcb_display_t,
+			      &displays,
+			      link)
+    {
+	if (display->dpy == dpy)
+	{
+	    /* _cairo_xlib_xcb_display_finish will lock the mutex again
+	     * -> deadlock (This mutex isn't recursive) */
+	    CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
+
+	    /* Make sure the xlib-xcb (and thus the xcb) device is finished
+	     * when the X11 connection is closed. */
+	    cairo_device_finish (&display->base);
+	    return 0;
+	}
+    }
+    CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
+
+    return 0;
+}
+
+static const cairo_device_backend_t _cairo_xlib_xcb_device_backend = {
+    CAIRO_DEVICE_TYPE_XLIB,
+
+    NULL,
+    NULL,
+
+    NULL, /* flush */
+    _cairo_xlib_xcb_display_finish,
+    free, /* destroy */
+};
+
+static cairo_device_t *
+_cairo_xlib_xcb_device_create (Display *dpy, cairo_device_t *xcb_device)
+{
+    cairo_xlib_xcb_display_t *display = NULL;
+    cairo_device_t *device;
+
+    CAIRO_MUTEX_INITIALIZE ();
+
+    CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
+    if (displays.next == NULL) {
+	cairo_list_init (&displays);
+    }
+
+    cairo_list_foreach_entry (display,
+			      cairo_xlib_xcb_display_t,
+			      &displays,
+			      link)
+    {
+	if (display->dpy == dpy) {
+	    /* Maintain MRU order. */
+	    if (displays.next != &display->link)
+		cairo_list_move (&display->link, &displays);
+
+	    /* Grab a reference for our caller */
+	    device = cairo_device_reference (&display->base);
+	    assert (display->xcb_device == xcb_device);
+	    goto unlock;
+	}
+	printf("still have %p in list\n", display);
+    }
+
+    display = malloc (sizeof (cairo_xlib_xcb_display_t));
+    if (unlikely (display == NULL)) {
+	device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
+	goto unlock;
+    }
+
+    display->codes = XAddExtension (dpy);
+    if (unlikely (display->codes == NULL)) {
+	device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
+	free (display);
+	goto unlock;
+    }
+
+    _cairo_device_init (&display->base, &_cairo_xlib_xcb_device_backend);
+
+    XESetCloseDisplay (dpy, display->codes->extension, _cairo_xlib_xcb_close_display);
+
+    display->dpy = dpy;
+    display->xcb_device = cairo_device_reference(xcb_device);
+
+    cairo_list_add (&display->link, &displays);
+    device = &display->base;
+
+unlock:
+    CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
+
+    return device;
+}
+
 static cairo_surface_t *
 _cairo_xlib_xcb_surface_create (void *dpy,
 				void *scr,
@@ -265,9 +397,12 @@ _cairo_xlib_xcb_surface_create (void *dpy,
 
     _cairo_surface_init (&surface->base,
 			 &_cairo_xlib_xcb_surface_backend,
-			 xcb->device,
+			 _cairo_xlib_xcb_device_create (dpy, xcb->device),
 			 xcb->content);
 
+    /* _cairo_surface_init() got another reference to the device, drop ours */
+    cairo_device_destroy (surface->base.device);
+
     surface->display = dpy;
     surface->screen = scr;
     surface->visual = visual;
@@ -604,13 +739,15 @@ void
 cairo_xlib_device_debug_set_precision (cairo_device_t *device,
 				       int precision)
 {
-    cairo_xcb_device_debug_set_precision (device, precision);
+    cairo_xlib_xcb_display_t *display = (cairo_xlib_xcb_display_t *) device;
+    cairo_xcb_device_debug_set_precision (display->xcb_device, precision);
 }
 
 int
 cairo_xlib_device_debug_get_precision (cairo_device_t *device)
 {
-    return cairo_xcb_device_debug_get_precision (device);
+    cairo_xlib_xcb_display_t *display = (cairo_xlib_xcb_display_t *) device;
+    return cairo_xcb_device_debug_get_precision (display->xcb_device);
 }
 
 #endif /* CAIRO_HAS_XLIB_XCB_FUNCTIONS */
-- 
1.7.5.4


--------------030606010808080108020706
Content-Type: text/x-diff;
 name="0002-xlib-xcb-xcb-Check-for-right-device-in-gs-et_precisi.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename*0="0002-xlib-xcb-xcb-Check-for-right-device-in-gs-et_precisi.pa";
 filename*1="tch"



More information about the cairo mailing list