From ad7698feb5f818ba2657b01bbc04f7fb537c1297 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 13 Mar 2007 20:11:49 +0000 Subject: [PATCH] Introduce hooks for _cairo_xlib_close_display() This patch adds a simple hook data type for a notifier style callback and introduces two functions to manipulate a list of callbacks for cleaning up on display closure. --- src/cairo-xlib-private.h | 15 ++++ src/cairo-xlib-screen.c | 153 +++++++++++++++++++++++++++++++-------- 2 files changed, 136 insertions(+), 32 deletions(-) diff --git a/src/cairo-xlib-private.h b/src/cairo-xlib-private.h index ddac05a7d..8ba46a2ec 100644 --- a/src/cairo-xlib-private.h +++ b/src/cairo-xlib-private.h @@ -37,6 +37,14 @@ #include "cairo-xlib.h" typedef struct _cairo_xlib_screen_info cairo_xlib_screen_info_t; +typedef struct _cairo_xlib_hook cairo_xlib_hook_t; + +struct _cairo_xlib_hook { + cairo_xlib_hook_t *next; + void (*func) (Display *display, void *data); + void *data; + void *key; +}; struct _cairo_xlib_screen_info { cairo_xlib_screen_info_t *next; @@ -46,11 +54,18 @@ struct _cairo_xlib_screen_info { cairo_bool_t has_render; cairo_font_options_t font_options; + + cairo_xlib_hook_t *close_display_hooks; }; cairo_private cairo_xlib_screen_info_t * _cairo_xlib_screen_info_get (Display *display, Screen *screen); +cairo_private cairo_bool_t +_cairo_xlib_add_close_display_hook (Display *display, void (*func) (Display *, void *), void *data, void *key); +cairo_private void +_cairo_xlib_remove_close_display_hook (Display *display, void *key); + #if CAIRO_HAS_XLIB_XRENDER_SURFACE #include "cairo-xlib-xrender.h" diff --git a/src/cairo-xlib-screen.c b/src/cairo-xlib-screen.c index 2316fe147..4c34608a2 100644 --- a/src/cairo-xlib-screen.c +++ b/src/cairo-xlib-screen.c @@ -247,31 +247,36 @@ CAIRO_MUTEX_DECLARE(_xlib_screen_mutex); static cairo_xlib_screen_info_t *_cairo_xlib_screen_list = NULL; -/* XXX: From this function we should also run through and cleanup - * anything else that still has a pointer to this Display*. For - * example, we should clean up any Xlib-specific glyph caches. */ static int _cairo_xlib_close_display (Display *dpy, XExtCodes *codes) { - cairo_xlib_screen_info_t *info, *prev; + cairo_xlib_screen_info_t *info, **prev, *next; /* * Unhook from the global list */ CAIRO_MUTEX_LOCK (_xlib_screen_mutex); - prev = NULL; - for (info = _cairo_xlib_screen_list; info; info = info->next) { + prev = &_cairo_xlib_screen_list; + for (info = _cairo_xlib_screen_list; info; info = next) { + next = info->next; if (info->display == dpy) { - if (prev) - prev->next = info->next; - else - _cairo_xlib_screen_list = info->next; + *prev = next; + /* call all registered shutdown routines */ + while (info->close_display_hooks) { + cairo_xlib_hook_t *hook = info->close_display_hooks; + info->close_display_hooks = hook->next; + + hook->func (dpy, hook->data); + + free (hook); + } free (info); - break; + } else { + prev = &info->next; } - prev = info; } + *prev = NULL; CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex); /* Return value in accordance with requirements of @@ -291,6 +296,11 @@ _cairo_xlib_screen_info_reset (void) 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); } @@ -300,8 +310,8 @@ _cairo_xlib_screen_info_reset (void) } -cairo_xlib_screen_info_t * -_cairo_xlib_screen_info_get (Display *dpy, Screen *screen) +static cairo_xlib_screen_info_t * +_cairo_xlib_screen_info_get_unlocked (Display *dpy, Screen *screen) { cairo_xlib_screen_info_t *info; cairo_xlib_screen_info_t **prev; @@ -309,26 +319,15 @@ _cairo_xlib_screen_info_get (Display *dpy, Screen *screen) XExtCodes *codes; cairo_bool_t seen_display = FALSE; - /* There is an apparent deadlock between this mutex and the - * mutex for the display, but it's actually safe. For the - * app to call XCloseDisplay() while any other thread is - * inside this function would be an error in the logic - * app, and the CloseDisplay hook is the only other place we - * acquire this mutex. - */ - CAIRO_MUTEX_LOCK (_xlib_screen_mutex); - for (prev = &_cairo_xlib_screen_list; (info = *prev); prev = &(*prev)->next) { if (info->display == dpy) { seen_display = TRUE; - if (info->screen == screen) - { + if (info->screen == screen || screen == NULL) { /* * MRU the list */ - if (prev != &_cairo_xlib_screen_list) - { + if (prev != &_cairo_xlib_screen_list) { *prev = info->next; info->next = _cairo_xlib_screen_list; _cairo_xlib_screen_list = info; @@ -339,18 +338,17 @@ _cairo_xlib_screen_info_get (Display *dpy, Screen *screen) } if (info) - goto out; + return info; info = malloc (sizeof (cairo_xlib_screen_info_t)); if (!info) - goto out; + return NULL; if (!seen_display) { codes = XAddExtension (dpy); if (!codes) { free (info); - info = NULL; - goto out; + return NULL; } XESetCloseDisplay (dpy, codes->extension, _cairo_xlib_close_display); @@ -361,17 +359,108 @@ _cairo_xlib_screen_info_get (Display *dpy, Screen *screen) info->has_render = (XRenderQueryExtension (dpy, &event_base, &error_base) && (XRenderFindVisualFormat (dpy, DefaultVisual (dpy, DefaultScreen (dpy))) != 0)); + info->close_display_hooks = NULL; + _cairo_xlib_init_screen_font_options (info); info->next = _cairo_xlib_screen_list; _cairo_xlib_screen_list = info; - out: + return info; +} +cairo_xlib_screen_info_t * +_cairo_xlib_screen_info_get (Display *dpy, Screen *screen) +{ + cairo_xlib_screen_info_t *info; + + /* There is an apparent deadlock between this mutex and the + * mutex for the display, but it's actually safe. For the + * app to call XCloseDisplay() while any other thread is + * inside this function would be an error in the logic + * app, and the CloseDisplay hook is the only other place we + * acquire this mutex. + */ + CAIRO_MUTEX_LOCK (_xlib_screen_mutex); + + info = _cairo_xlib_screen_info_get_unlocked (dpy, screen); + CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex); return info; } +cairo_bool_t +_cairo_xlib_add_close_display_hook (Display *dpy, void (*func) (Display *, void *), void *data, void *key) +{ + cairo_xlib_screen_info_t *info; + cairo_xlib_hook_t *hook; + cairo_xlib_hook_t **prev; + cairo_bool_t success = FALSE; + + CAIRO_MUTEX_LOCK (_xlib_screen_mutex); + + info = _cairo_xlib_screen_info_get_unlocked (dpy, NULL); + if (!info) + goto unlock; + + for (prev = &info->close_display_hooks; (hook = *prev); prev = &hook->next) + { + if (hook->key == key) { + /* + * MRU the list + */ + if (prev != &info->close_display_hooks) { + *prev = hook->next; + hook->next = info->close_display_hooks; + info->close_display_hooks = hook; + } + break; + } + } + + if (!hook) { + hook = malloc (sizeof (cairo_xlib_hook_t)); + if (!hook) + goto unlock; + hook->func = func; + hook->data = data; + hook->key = key; + hook->next = info->close_display_hooks; + info->close_display_hooks = hook; + } + + success = TRUE; + unlock: + CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex); + return success; +} + +void +_cairo_xlib_remove_close_display_hook (Display *dpy, void *key) +{ + cairo_xlib_screen_info_t *info; + cairo_xlib_hook_t *hook; + cairo_xlib_hook_t **prev; + + CAIRO_MUTEX_LOCK (_xlib_screen_mutex); + + info = _cairo_xlib_screen_info_get_unlocked (dpy, NULL); + if (!info) + goto unlock; + + for (prev = &info->close_display_hooks; (hook = *prev); prev = &hook->next) + { + if (hook->key == key) { + *prev = hook->next; + free (hook); + break; + } + } + +unlock: + CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex); +} + void _cairo_xlib_screen_reset_static_data (void) {