diff options
author | Uli Schlachter <psychon@znc.in> | 2011-07-17 17:55:26 +0200 |
---|---|---|
committer | Uli Schlachter <psychon@znc.in> | 2011-07-18 10:29:08 +0200 |
commit | 2e264e73df0b5a2f6d6a7f906f483d4a827a5375 (patch) | |
tree | ac6a09374297313a9b5f26f892036fc9030c92cb /src/cairo-xlib-xcb-surface.c | |
parent | 0dc63f5bb409de0013bf845f96383cc9dca27980 (diff) | |
download | cairo-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.c | 9 |
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); |