From bdec39afb41471e7ebc86122239741a819e4a8b3 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Mon, 15 Oct 2012 17:58:55 -0500 Subject: Add a threadsafe hashtable and use it in pangofc-fontmap Inching our way closer to threadsafe pangofc. --- configure.in | 2 + pango/Makefile.am | 3 +- pango/pango-threadsafe.h | 128 +++++++++++++++++++++++++++++++++++++++++++++++ pango/pangofc-fontmap.c | 63 +++++++++++------------ tests/Makefile.am | 5 +- 5 files changed, 167 insertions(+), 34 deletions(-) create mode 100644 pango/pango-threadsafe.h diff --git a/configure.in b/configure.in index a0e00578..26c775e6 100644 --- a/configure.in +++ b/configure.in @@ -469,6 +469,8 @@ AC_SUBST(GLIB_MKENUMS) # Add in gthread-2.0 to CFLAGS but not to LIBS so we get any # necesary defines for thread-safety. GLIB_CFLAGS=`$PKG_CONFIG --cflags $GLIB_MODULES gthread-2.0` +GTHREAD_LIBS=`$PKG_CONFIG --libs $GLIB_MODULES gthread-2.0` +AC_SUBST(GTHREAD_LIBS) # # Checks for LibThai diff --git a/pango/Makefile.am b/pango/Makefile.am index ab092c92..1387b786 100644 --- a/pango/Makefile.am +++ b/pango/Makefile.am @@ -89,8 +89,9 @@ libpango_1_0_la_SOURCES = \ pango-renderer.c \ pango-script.c \ pango-script-lang-table.h \ - pango-script-private.h \ + pango-script-private.h \ pango-tabs.c \ + pango-threadsafe.h \ pango-utils.c \ reorder-items.c \ shape.c \ diff --git a/pango/pango-threadsafe.h b/pango/pango-threadsafe.h new file mode 100644 index 00000000..c4abd683 --- /dev/null +++ b/pango/pango-threadsafe.h @@ -0,0 +1,128 @@ +/* Pango + * pango-threadsafe.h: Thread-safe alternatives of glib datastructures + * + * Copyright (C) 2012 Google, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Google author(s): Behdad Esfahbod + */ + +#ifndef __PANGO_THREADSAFE_H__ +#define __PANGO_THREADSAFE_H__ + +#include +#include + +G_BEGIN_DECLS + +typedef struct _PHashTable { + GHashTable *ht; + GMutex mx; +} PHashTable; + + +static inline +PHashTable* p_hash_table_new (GHashFunc hash_func, + GEqualFunc key_equal_func) +{ + PHashTable *p = g_slice_new0 (PHashTable); + + p->ht = g_hash_table_new (hash_func, key_equal_func); + + return p; +} + +static inline +PHashTable* p_hash_table_new_full (GHashFunc hash_func, + GEqualFunc key_equal_func, + GDestroyNotify key_destroy_func, + GDestroyNotify value_destroy_func) +{ + PHashTable *p = g_slice_new0 (PHashTable); + + p->ht = g_hash_table_new_full (hash_func, + key_equal_func, + key_destroy_func, + value_destroy_func); + + return p; +} + +static inline +void p_hash_table_destroy (PHashTable *hash_table) +{ + g_hash_table_destroy (hash_table->ht); + g_mutex_clear (&hash_table->mx); + g_slice_free (PHashTable, hash_table); +} + +static inline +void p_hash_table_insert (PHashTable *hash_table, + gpointer key, + gpointer value) +{ + g_mutex_lock (&hash_table->mx); + g_hash_table_insert (hash_table->ht, key, value); + g_mutex_unlock (&hash_table->mx); +} + +static inline +void p_hash_table_replace (PHashTable *hash_table, + gpointer key, + gpointer value) +{ + g_mutex_lock (&hash_table->mx); + g_hash_table_replace (hash_table->ht, key, value); + g_mutex_unlock (&hash_table->mx); +} + +static inline +gboolean p_hash_table_remove (PHashTable *hash_table, + gconstpointer key) +{ + gboolean ret; + g_mutex_lock (&hash_table->mx); + ret = g_hash_table_remove (hash_table->ht, key); + g_mutex_unlock (&hash_table->mx); + return ret; +} + +static inline +gpointer p_hash_table_lookup (PHashTable *hash_table, + gconstpointer key) +{ + gpointer ret; + g_mutex_lock (&hash_table->mx); + ret = g_hash_table_lookup (hash_table->ht, key); + g_mutex_unlock (&hash_table->mx); + return ret; +} + +static inline +void p_hash_table_foreach (PHashTable *hash_table, + GHFunc func, + gpointer user_data) +{ + g_mutex_lock (&hash_table->mx); + g_hash_table_foreach (hash_table->ht, func, user_data); + g_mutex_unlock (&hash_table->mx); +} + + +G_END_DECLS + +#endif /* __PANGO_THREADSAFE_H__ */ diff --git a/pango/pangofc-fontmap.c b/pango/pangofc-fontmap.c index d4a8fa96..5be2b815 100644 --- a/pango/pangofc-fontmap.c +++ b/pango/pangofc-fontmap.c @@ -30,6 +30,7 @@ #include "pango-impl-utils.h" #include "modules.h" #include "pango-enum-types.h" +#include "pango-threadsafe.h" /* Overview: @@ -106,19 +107,19 @@ typedef struct _PangoFcFontset PangoFcFontset; struct _PangoFcFontMapPrivate { - GHashTable *fontset_hash; /* Maps PangoFcFontsetKey -> PangoFcFontset */ + PHashTable *fontset_hash; /* Maps PangoFcFontsetKey -> PangoFcFontset */ GQueue *fontset_cache; /* Recently used fontsets */ - GHashTable *font_hash; /* Maps PangoFcFontKey -> PangoFcFont */ + PHashTable *font_hash; /* Maps PangoFcFontKey -> PangoFcFont */ - GHashTable *patterns_hash; /* Maps FcPattern -> PangoFcPatterns */ + PHashTable *patterns_hash; /* Maps FcPattern -> PangoFcPatterns */ /* pattern_hash is used to make sure we only store one copy of * each identical pattern. (Speeds up lookup). */ - GHashTable *pattern_hash; + PHashTable *pattern_hash; - GHashTable *font_face_data_hash; /* Maps font file name/id -> data */ + PHashTable *font_face_data_hash; /* Maps font file name/id -> data */ /* List of all families availible */ PangoFcFamily **families; @@ -687,7 +688,7 @@ pango_fc_patterns_new (FcPattern *pat, PangoFcFontMap *fontmap) PangoFcPatterns *pats; pat = uniquify_pattern (fontmap, pat); - pats = g_hash_table_lookup (fontmap->priv->patterns_hash, pat); + pats = p_hash_table_lookup (fontmap->priv->patterns_hash, pat); if (pats) return pango_fc_patterns_ref (pats); @@ -699,7 +700,7 @@ pango_fc_patterns_new (FcPattern *pat, PangoFcFontMap *fontmap) FcPatternReference (pat); pats->pattern = pat; - g_hash_table_insert (fontmap->priv->patterns_hash, + p_hash_table_insert (fontmap->priv->patterns_hash, pats->pattern, pats); return pats; @@ -728,8 +729,8 @@ pango_fc_patterns_unref (PangoFcPatterns *pats) /* Only remove from fontmap hash if we are in it. This is not necessarily * the case after a cache_clear() call. */ if (pats->fontmap->priv->patterns_hash && - pats == g_hash_table_lookup (pats->fontmap->priv->patterns_hash, pats->pattern)) - g_hash_table_remove (pats->fontmap->priv->patterns_hash, + pats == p_hash_table_lookup (pats->fontmap->priv->patterns_hash, pats->pattern)) + p_hash_table_remove (pats->fontmap->priv->patterns_hash, pats->pattern); if (pats->pattern) @@ -1034,23 +1035,23 @@ pango_fc_font_map_init (PangoFcFontMap *fcfontmap) priv->n_families = -1; - priv->font_hash = g_hash_table_new ((GHashFunc)pango_fc_font_key_hash, + priv->font_hash = p_hash_table_new ((GHashFunc)pango_fc_font_key_hash, (GEqualFunc)pango_fc_font_key_equal); - priv->fontset_hash = g_hash_table_new_full ((GHashFunc)pango_fc_fontset_key_hash, + priv->fontset_hash = p_hash_table_new_full ((GHashFunc)pango_fc_fontset_key_hash, (GEqualFunc)pango_fc_fontset_key_equal, NULL, (GDestroyNotify)g_object_unref); priv->fontset_cache = g_queue_new (); - priv->patterns_hash = g_hash_table_new (NULL, NULL); + priv->patterns_hash = p_hash_table_new (NULL, NULL); - priv->pattern_hash = g_hash_table_new_full ((GHashFunc) FcPatternHash, + priv->pattern_hash = p_hash_table_new_full ((GHashFunc) FcPatternHash, (GEqualFunc) FcPatternEqual, (GDestroyNotify) FcPatternDestroy, NULL); - priv->font_face_data_hash = g_hash_table_new_full ((GHashFunc)pango_fc_font_face_data_hash, + priv->font_face_data_hash = p_hash_table_new_full ((GHashFunc)pango_fc_font_face_data_hash, (GEqualFunc)pango_fc_font_face_data_equal, (GDestroyNotify)pango_fc_font_face_data_free, NULL); @@ -1066,19 +1067,19 @@ pango_fc_font_map_fini (PangoFcFontMap *fcfontmap) g_queue_free (priv->fontset_cache); priv->fontset_cache = NULL; - g_hash_table_destroy (priv->fontset_hash); + p_hash_table_destroy (priv->fontset_hash); priv->fontset_hash = NULL; - g_hash_table_destroy (priv->patterns_hash); + p_hash_table_destroy (priv->patterns_hash); priv->patterns_hash = NULL; - g_hash_table_destroy (priv->font_hash); + p_hash_table_destroy (priv->font_hash); priv->font_hash = NULL; - g_hash_table_destroy (priv->font_face_data_hash); + p_hash_table_destroy (priv->font_face_data_hash); priv->font_face_data_hash = NULL; - g_hash_table_destroy (priv->pattern_hash); + p_hash_table_destroy (priv->pattern_hash); priv->pattern_hash = NULL; for (i = 0; i < priv->n_families; i++) @@ -1199,7 +1200,7 @@ pango_fc_font_map_add (PangoFcFontMap *fcfontmap, key_copy = pango_fc_font_key_copy (key); _pango_fc_font_set_font_key (fcfont, key_copy); - g_hash_table_insert (priv->font_hash, key_copy, fcfont); + p_hash_table_insert (priv->font_hash, key_copy, fcfont); } /* Remove mapping from fcfont->key to fcfont */ @@ -1217,9 +1218,9 @@ _pango_fc_font_map_remove (PangoFcFontMap *fcfontmap, /* Only remove from fontmap hash if we are in it. This is not necessarily * the case after a cache_clear() call. */ if (priv->font_hash && - fcfont == g_hash_table_lookup (priv->font_hash, key)) + fcfont == p_hash_table_lookup (priv->font_hash, key)) { - g_hash_table_remove (priv->font_hash, key); + p_hash_table_remove (priv->font_hash, key); } _pango_fc_font_set_font_key (fcfont, NULL); pango_fc_font_key_free (key); @@ -1489,7 +1490,7 @@ uniquify_pattern (PangoFcFontMap *fcfontmap, PangoFcFontMapPrivate *priv = fcfontmap->priv; FcPattern *old_pattern; - old_pattern = g_hash_table_lookup (priv->pattern_hash, pattern); + old_pattern = p_hash_table_lookup (priv->pattern_hash, pattern); if (old_pattern) { return old_pattern; @@ -1497,7 +1498,7 @@ uniquify_pattern (PangoFcFontMap *fcfontmap, else { FcPatternReference (pattern); - g_hash_table_insert (priv->pattern_hash, pattern, pattern); + p_hash_table_insert (priv->pattern_hash, pattern, pattern); return pattern; } } @@ -1520,7 +1521,7 @@ pango_fc_font_map_new_font (PangoFcFontMap *fcfontmap, pango_fc_font_key_init (&key, fcfontmap, fontset_key, match); - fcfont = g_hash_table_lookup (priv->font_hash, &key); + fcfont = p_hash_table_lookup (priv->font_hash, &key); if (fcfont) return g_object_ref (fcfont); @@ -1708,7 +1709,7 @@ pango_fc_fontset_cache (PangoFcFontset *fontset, { PangoFcFontset *tmp_fontset = g_queue_pop_tail (cache); tmp_fontset->cache_link = NULL; - g_hash_table_remove (priv->fontset_hash, tmp_fontset->key); + p_hash_table_remove (priv->fontset_hash, tmp_fontset->key); } fontset->cache_link = g_list_prepend (NULL, fontset); @@ -1730,7 +1731,7 @@ pango_fc_font_map_load_fontset (PangoFontMap *fontmap, pango_fc_fontset_key_init (&key, fcfontmap, context, desc, language); - fontset = g_hash_table_lookup (priv->fontset_hash, &key); + fontset = p_hash_table_lookup (priv->fontset_hash, &key); if (G_UNLIKELY (!fontset)) { @@ -1740,7 +1741,7 @@ pango_fc_font_map_load_fontset (PangoFontMap *fontmap, return NULL; fontset = pango_fc_fontset_new (&key, patterns); - g_hash_table_insert (priv->fontset_hash, pango_fc_fontset_get_key (fontset), fontset); + p_hash_table_insert (priv->fontset_hash, pango_fc_fontset_get_key (fontset), fontset); pango_fc_patterns_unref (patterns); } @@ -1788,7 +1789,7 @@ pango_fc_font_map_get_font_face_data (PangoFcFontMap *fcfontmap, if (FcPatternGetInteger (font_pattern, FC_INDEX, 0, &key.id) != FcResultMatch) return NULL; - data = g_hash_table_lookup (priv->font_face_data_hash, &key); + data = p_hash_table_lookup (priv->font_face_data_hash, &key); if (G_LIKELY (data)) return data; @@ -1799,7 +1800,7 @@ pango_fc_font_map_get_font_face_data (PangoFcFontMap *fcfontmap, data->pattern = font_pattern; FcPatternReference (data->pattern); - g_hash_table_insert (priv->font_face_data_hash, data, data); + p_hash_table_insert (priv->font_face_data_hash, data, data); return data; } @@ -1995,7 +1996,7 @@ pango_fc_font_map_shutdown (PangoFcFontMap *fcfontmap) if (priv->closed) return; - g_hash_table_foreach (priv->font_hash, (GHFunc) shutdown_font, fcfontmap); + p_hash_table_foreach (priv->font_hash, (GHFunc) shutdown_font, fcfontmap); for (i = 0; i < priv->n_families; i++) priv->families[i]->fontmap = NULL; diff --git a/tests/Makefile.am b/tests/Makefile.am index fa3ed125..2726bbba 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -41,12 +41,12 @@ TESTS_ENVIRONMENT = \ srcdir=$(srcdir) \ PANGO_RC_FILE=./pangorc -noinst_PROGRAMS = gen-all-unicode dump-boundaries +noinst_PROGRAMS = gen-all-unicode dump-boundaries check_PROGRAMS = testboundaries testboundaries_ucd testcolor testscript if HAVE_CAIRO -check_PROGRAMS += testiter +check_PROGRAMS += testiter test-pangocairo-threads endif if HAVE_FREETYPE check_PROGRAMS += test-ot-tags @@ -64,6 +64,7 @@ testiter_LDADD = $(TEST_PANGOCAIRO_LIBS) testscript_LDADD = $(TEST_PANGO_LIBS) test_ot_tags_LDADD = $(TEST_PANGOFT2_LIBS) dump_boundaries_LDADD = $(TEST_PANGO_LIBS) +test_pangocairo_threads_LDADD = $(TEST_PANGOCAIRO_LIBS) $(GTHREAD_LIBS) if HAVE_CXX check_PROGRAMS += cxx-test -- cgit v1.2.1