summaryrefslogtreecommitdiff
path: root/src/cairo-xlib-xcb-surface.c
diff options
context:
space:
mode:
authorUli Schlachter <psychon@znc.in>2011-07-17 17:55:26 +0200
committerUli Schlachter <psychon@znc.in>2011-07-18 10:29:08 +0200
commit2e264e73df0b5a2f6d6a7f906f483d4a827a5375 (patch)
treeac6a09374297313a9b5f26f892036fc9030c92cb /src/cairo-xlib-xcb-surface.c
parent0dc63f5bb409de0013bf845f96383cc9dca27980 (diff)
downloadcairo-2e264e73df0b5a2f6d6a7f906f483d4a827a5375.tar.gz
xlib-xcb: Fix an "extension leak"
When the xlib-xcb backend created a new cairo_device_t for a Display*, it called XAddExtension to get a callback on XCloseDisplay(). However, when the last surface using this device is destroyed, this extension isn't unregistered because there is no API for this. I noticed that gvim was quite slow after a while with xlib-xcb. The reason is that xlib has a linked list of registered extensions that it has to walk through for various callbacks. Since xlib-xcb caused lots of "dead" extension, this got quite slow when there were about 20k entries in this list. The fix is to make sure that the cairo_device_t isn't finished/destroyed when the last surface using it is destroyed. For this, we keep an internal reference which is only dropped when the device is finished. This happens when someone explicitly calls cairo_device_finish or when our XCloseDisplay hook runs. The same thing is done by cairo-xlib. I didn't port this over to xlib-xcb because at that time I didn't understand why it was needed. Signed-off-by: Uli Schlachter <psychon@znc.in>
Diffstat (limited to 'src/cairo-xlib-xcb-surface.c')
-rw-r--r--src/cairo-xlib-xcb-surface.c9
1 files changed, 9 insertions, 0 deletions
diff --git a/src/cairo-xlib-xcb-surface.c b/src/cairo-xlib-xcb-surface.c
index 6381e05c5..335a33a5d 100644
--- a/src/cairo-xlib-xcb-surface.c
+++ b/src/cairo-xlib-xcb-surface.c
@@ -278,6 +278,8 @@ _cairo_xlib_xcb_display_finish (void *abstract_display)
display->xcb_device = NULL;
XESetCloseDisplay (display->dpy, display->codes->extension, NULL);
+ /* Drop the reference from _cairo_xlib_xcb_device_create */
+ cairo_device_destroy (&display->base);
}
static int
@@ -301,6 +303,7 @@ _cairo_xlib_xcb_close_display(Display *dpy, XExtCodes *codes)
/* Make sure the xcb and xlib-xcb devices are finished */
cairo_device_finish (display->xcb_device);
cairo_device_finish (&display->base);
+
cairo_device_destroy (&display->base);
return 0;
}
@@ -370,6 +373,12 @@ _cairo_xlib_xcb_device_create (Display *dpy, cairo_device_t *xcb_device)
_cairo_device_init (&display->base, &_cairo_xlib_xcb_device_backend);
XESetCloseDisplay (dpy, display->codes->extension, _cairo_xlib_xcb_close_display);
+ /* Add a reference for _cairo_xlib_xcb_display_finish. This basically means
+ * that the device's reference count never drops to zero
+ * as long as our Display* is alive. We need this because there is no
+ * "XDelExtension" to undo XAddExtension and having lots of registered
+ * extensions slows down libX11. */
+ cairo_device_reference (&display->base);
display->dpy = dpy;
display->xcb_device = cairo_device_reference(xcb_device);