Re: Making PangoCairo threadsafe
- From: Behdad Esfahbod <behdad behdad org>
- To: gtk-devel-list <gtk-devel-list gnome org>
- Cc: gtk-i18n-list <gtk-i18n-list gnome org>
- Subject: Re: Making PangoCairo threadsafe
- Date: Mon, 20 Nov 2006 18:51:59 -0500
Filed a bug for tracking this:
http://bugzilla.gnome.org/show_bug.cgi?id=377539
On Mon, 2006-11-20 at 17:05 -0500, Behdad Esfahbod wrote:
> Hi,
>
> So, I there was this more-than-evil bug
> Bug 356666 – pango is not thread-safe, nautilus does not honour that
> http://bugzilla.gnome.org/show_bug.cgi?id=356666
>
> that I wanted to fix. The problem is that the per-fontmap
> PangoCairoRenderer that pangocairo is using was being used by two
> threads (one Gtk+ UI stuff, another a librsvg thumbnailer) and that's
> not good. After a quick check with mclasen and otaylor, I chose to go
> for mutex-ing the renderer, make a single cached instance of it, and
> create a new one if the cached one is being used. Here is the patch
> that I committed and is in pango-1.14.8 that was just released:
>
> http://bugzilla.gnome.org/attachment.cgi?id=76925&action=view
>
> The patch is fairly simple. More interesting is the test case I wrote:
>
> http://bugzilla.gnome.org/attachment.cgi?id=76942
>
> The cool thing about the test is that it's very simple, yet hits the bug
> very easily. No more after the patch. However, if you look at the test
> case, I'm calling into Pango once before spawning the threads. If you
> comment that line, it will blow up in a number of places, causing a
> crash or getting boxes only in the output.
>
> So, Pango is not thread-safe, and advertised so. However, people seem
> to believe that it's safe to use it as long as a single PangoContext or
> PangoLayout instance is not used from multiple threads simultaneously
> (which is not true either). I'm looking into achieving that, and I can
> use some help.
>
> Both Pango and Cairo are designed to be thread-safe, API-wise. No
> problem there. However, there are bugs in both. There is a patch for
> cairo already that may or may not be enough:
>
> https://bugs.freedesktop.org/show_bug.cgi?id=8801
>
>
> As for pango, I did some grepping to identify places that need a fix:
>
> - First, the static variables. Assuming that
> g_enum_register_static(), g_type_register_static(), and
> g_quark_from_static_string() are idempotent, and ignoring the pangox
> backend, it comes down to:
>
> $ grep -E '\<static\>[^(]*[;=]' *.c | grep -v '\<const\>' | grep -v -E '\<(GType|GQuark|querymodules.c)\>' | grep -v -E 'querymodules|pangox[-.]|type_id\>'
> modules.c:static GList *maps = NULL;
> modules.c:static GSList *registered_engines = NULL;
> modules.c:static GSList *dlloaded_engines = NULL;
> modules.c:static GHashTable *dlloaded_modules;
> modules.c:static GObjectClass *parent_class;
> modules.c: static GEnumClass *class = NULL;
> modules.c: static gboolean init = FALSE;
> modules.c: static gboolean no_module_warning = FALSE;
> pangoatsui-fontmap.c:static gpointer pango_atsui_family_parent_class;
> pangoatsui-fontmap.c:static gpointer pango_atsui_face_parent_class;
> pango-attributes.c: static guint current_type = 0x1000000;
> pangocairo-fontmap.c: static PangoFontMap *default_font_map = NULL;
> pangocairo-render.c:static PangoCairoRenderer *cached_renderer = NULL;
> pangocairo-render.c:static GStaticMutex cached_renderer_mutex = G_STATIC_MUTEX_INIT;
> pango-engine.c: static PangoEngineShape *fallback_shaper = NULL;
> pangofc-fontmap.c: static gboolean registered_modules = FALSE;
> pangofc-fontmap.c: static GEnumClass *class = NULL;
> pango-fontmap.c: static GHashTable *warned_fonts = NULL;
> pango-fontset.c:static PangoFontsetClass *simple_parent_class; /* Parent class structure for PangoFontsetSimple */
> pangoft2.c: static char *default_msg = NULL;
> pangoft2-fontmap.c:static PangoFT2FontMap *pango_ft2_global_fontmap = NULL;
> pango-ot-info.c:static GObjectClass *parent_class;
> pango-ot-ruleset.c:static GObjectClass *parent_class;
> pango-script.c: static int saved_mid = PANGO_SCRIPT_TABLE_MIDPOINT;
> pango-utils.c:static GHashTable *pango_aliases_ht = NULL;
> pango-utils.c:static GHashTable *config_hash = NULL;
> pango-utils.c: static gchar *result = NULL;
> pango-utils.c: static gchar *result = NULL;
> pango-utils.c: static GHashTable *hash = NULL;
> pangowin32.c: static guint last = 0; /* Cache of one */
> pangowin32-fontmap.c:static PangoWin32FontMap *default_fontmap = NULL;
> pangoxft-fontmap.c:static GSList *fontmaps = NULL;
> pangoxft-fontmap.c:static GSList *registered_displays;
>
>
> - Next, g_object_set_[q]data*():
>
> $ grep g_object_set_ *.c | grep -v warned_quark
> pangocairo-font.c: g_object_set_data_full (G_OBJECT (cfont), "hex_box_info", NULL, NULL);
> pangocairo-font.c: g_object_set_data_full (G_OBJECT (cfont), "hex_box_info", hbi, (GDestroyNotify)_pango_cairo_hex_box_info_destroy);
> pangocairo-fontmap.c: g_object_set_qdata_full (G_OBJECT (context), context_info_quark,
> pango-context.c: g_object_set_qdata_full (G_OBJECT (fontset), cache_quark,
> pangox.c: g_object_set_qdata_full (G_OBJECT (result),
>
>
> - And finally, all other caches:
>
> $ grep 'cache.*=' *.c | grep -v -E '^pangox[-.]'
> pangocairo-fcfont.c: cffont->glyph_extents_cache = g_new0 (GlyphExtentsCacheEntry, GLYPH_CACHE_NUM_ENTRIES);
> pangocairo-fcfont.c: cffont->glyph_extents_cache[0].glyph = 1; /* glyph 1 cannot happen in bucket 0 */
> pangocairo-fcfont.c: if (cffont->glyph_extents_cache == NULL)
> pangocairo-render.c:static PangoCairoRenderer *cached_renderer = NULL;
> pangocairo-render.c:static GStaticMutex cached_renderer_mutex = G_STATIC_MUTEX_INIT;
> pangocairo-render.c: cached_renderer = g_object_new (PANGO_TYPE_CAIRO_RENDERER, NULL);
> pangocairo-win32font.c: face->cached_fonts = g_slist_prepend (face->cached_fonts, win32font);
> pango-context.c: * We cache the results of character,fontset => font,shaper in a hash table
> pango-context.c: static GQuark cache_quark = 0;
> pango-context.c: cache_quark = g_quark_from_static_string ("pango-shaper-font-cache");
> pango-context.c: cache = g_object_get_qdata (G_OBJECT (fontset), cache_quark);
> pango-context.c: cache = g_slice_new (ShaperFontCache);
> pango-context.c: cache->hash = g_hash_table_new_full (g_direct_hash, NULL,
> pango-context.c: state->cache = NULL;
> pango-context.c: state->cache = NULL;
> pango-context.c: state->cache = get_shaper_font_cache (state->current_fonts);
> pangofc-font.c: if (G_UNLIKELY (priv->char_to_glyph_cache == NULL))
> pangofc-font.c: priv->char_to_glyph_cache = g_new0 (GUnicharToGlyphCacheEntry, GLYPH_CACHE_NUM_ENTRIES);
> pangofc-font.c: priv->char_to_glyph_cache[0].ch = 1; /* char 1 cannot happen in bucket 0 */
> pangofc-fontmap.c: priv->fontset_cache = g_queue_new ();
> pangofc-fontmap.c: patterns->cache_link = NULL;
> pangofc-fontmap.c: patterns->cache_link != priv->fontset_cache->head))
> pangofc-fontmap.c: GQueue *cache = priv->fontset_cache;
> pangofc-fontmap.c: if (patterns->cache_link == cache->tail)
> pangofc-fontmap.c: cache->tail = patterns->cache_link->prev;
> pangofc-fontmap.c: cache->head = g_list_remove_link (cache->head, patterns->cache_link);
> pangofc-fontmap.c: if (cache->length == FONTSET_CACHE_SIZE)
> pangofc-fontmap.c: tmp_patterns->cache_link = NULL;
> pangofc-fontmap.c: patterns->cache_link = g_list_prepend (NULL, patterns);
> pangofc-fontmap.c: GQueue *cache = priv->fontset_cache;
> pangofc-fontmap.c: cache->head = NULL;
> pangofc-fontmap.c: cache->tail = NULL;
> pangofc-fontmap.c: cache->length = 0;
> pangoft2.c: info->cached_glyph = cached_glyph;
> pangoft2.c: PANGO_FT2_FONT (font)->glyph_cache_destroy = destroy_notify;
> pangoft2-render.c: add_glyph_to_cache = FALSE;
> pangoft2-render.c: add_glyph_to_cache = TRUE;
> pangowin32.c: cache = pango_win32_font_map_get_font_cache (win32font->fontmap);
> pangowin32.c: PangoWin32FontCache *cache = pango_win32_font_map_get_font_cache (win32font->fontmap);
> pangowin32-fontcache.c: g_return_if_fail (cache != NULL);
> pangowin32-fontcache.c: cache = g_slice_new (PangoWin32FontCache);
> pangowin32-fontcache.c: cache->forward = g_hash_table_new (logfont_hash, logfont_equal);
> pangowin32-fontcache.c: cache->back = g_hash_table_new (g_direct_hash, g_direct_equal);
> pangowin32-fontcache.c: cache->mru = NULL;
> pangowin32-fontcache.c: cache->mru_tail = NULL;
> pangowin32-fontcache.c: cache->mru_count = 0;
> pangowin32-fontcache.c: g_return_val_if_fail (cache != NULL, NULL);
> pangowin32-fontcache.c: cache->mru_tail = cache->mru_tail->prev;
> pangowin32-fontcache.c: cache->mru_tail->next = NULL;
> pangowin32-fontcache.c: cache->mru->prev = entry->mru;
> pangowin32-fontcache.c: cache->mru = entry->mru;
> pangowin32-fontcache.c: if (cache->mru_count == CACHE_SIZE)
> pangowin32-fontcache.c: cache->mru_tail = cache->mru_tail->prev;
> pangowin32-fontcache.c: cache->mru_tail->next = NULL;
> pangowin32-fontcache.c: cache->mru = g_list_prepend (cache->mru, entry);
> pangowin32-fontcache.c: cache->mru_tail = cache->mru;
> pangowin32-fontcache.c: g_return_if_fail (cache != NULL);
> pangowin32-fontmap.c: win32fontmap->font_cache = pango_win32_font_cache_new ();
> pangowin32-fontmap.c: face->cached_fonts = g_slist_prepend (face->cached_fonts, win32font);
> pangowin32-fontmap.c: win32face->cached_fonts = NULL;
> pangowin32-fontmap.c: face->cached_fonts = g_slist_remove (face->cached_fonts, font);
> pangowin32-fontmap.c: win32font->in_cache = TRUE;
> pangowin32-fontmap.c: win32font->in_cache = FALSE;
>
>
> [These don't include the modules. All greps done in pango/pango/]
>
> All seem like boring but easy fixes, using a few static mutexes. I have
> a question though: For platforms that we care about, are int and pointer
> assignments atomic? Ok, rkaway is telling me that they are not. In
> that case, even the patch that I committed is not completely correct.
> What do people typically do, what are the idioms? Other comments?
> Offering hand?
>
>
> Regards,
>
--
behdad
http://behdad.org/
"Commandment Three says Do Not Kill, Amendment Two says Blood Will Spill"
-- Dan Bern, "New American Language"
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]