From 2e4d2331f027b0159294f261cbc1922481a2fffe Mon Sep 17 00:00:00 2001 From: Marek Kasik Date: Fri, 6 Sep 2013 14:43:53 +0200 Subject: [PATCH] cairo-ft: Make usage of freetype thread safe Allocate new FT_Library for each thread as recommended in freetype.h. Libraries are stored in _cairo_hash_table_t where thread IDs are used as keys to the hash table. Every time a FT_Library is needed a lookup is performed on the hash table. If there is not a FT_Library for current thread, a new one is created and inserted to the hash table. --- src/cairo-ft-font.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 93 insertions(+), 6 deletions(-) diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c index 9f4b524..533b3d8 100644 --- a/src/cairo-ft-font.c +++ b/src/cairo-ft-font.c @@ -227,7 +227,8 @@ _cairo_ft_resolve_pattern (FcPattern *pattern, typedef struct _cairo_ft_unscaled_font_map { cairo_hash_table_t *hash_table; - FT_Library ft_library; + cairo_hash_table_t *ft_libraries; + cairo_mutex_t ft_libraries_mutex; int num_open_faces; } cairo_ft_unscaled_font_map_t; @@ -257,6 +258,81 @@ _font_map_release_face_lock_held (cairo_ft_unscaled_font_map_t *font_map, } } +typedef struct _ft_library_entry_t { + cairo_hash_entry_t base; + FT_Library ft_library; +} ft_library_entry_t; + +static cairo_bool_t +_ft_library_threads_equal (const void *key_a, + const void *key_b) +{ + const ft_library_entry_t *library_a = key_a; + const ft_library_entry_t *library_b = key_b; + pthread_t thread_a = library_a->base.hash; + pthread_t thread_b = library_b->base.hash; + + return (pthread_equal (thread_a, thread_b) != 0); +} + +static ft_library_entry_t * +_ft_library_get (cairo_ft_unscaled_font_map_t *font_map) +{ + ft_library_entry_t key, *entry; + cairo_status_t status; + + key.base.hash = pthread_self (); + + CAIRO_MUTEX_LOCK (font_map->ft_libraries_mutex); + entry = _cairo_hash_table_lookup (font_map->ft_libraries, &key.base); + if (entry == NULL) + { + entry = malloc (sizeof (ft_library_entry_t)); + if (unlikely (entry == NULL)) + goto FAIL; + + entry->base.hash = pthread_self (); + if (unlikely (FT_Init_FreeType (&entry->ft_library))) + goto FAIL; + + status = _cairo_hash_table_insert (font_map->ft_libraries, (cairo_hash_entry_t *) entry); + if (unlikely (status)) { + FT_Done_FreeType (entry->ft_library); + goto FAIL; + } + } + + CAIRO_MUTEX_UNLOCK (font_map->ft_libraries_mutex); + + return entry; + +FAIL: + if (entry != NULL) + free (entry); + + CAIRO_MUTEX_UNLOCK (font_map->ft_libraries_mutex); + + return NULL; +} + +static void +_ft_library_done (void *entry, + void *closure) +{ + ft_library_entry_t *library_entry = entry; + + FT_Done_FreeType (library_entry->ft_library); + free (library_entry); +} + +static void +_ft_libraries_done (cairo_ft_unscaled_font_map_t *font_map) +{ + CAIRO_MUTEX_LOCK (font_map->ft_libraries_mutex); + _cairo_hash_table_foreach (font_map->ft_libraries, _ft_library_done, NULL); + CAIRO_MUTEX_UNLOCK (font_map->ft_libraries_mutex); +} + static cairo_status_t _cairo_ft_unscaled_font_map_create (void) { @@ -277,7 +353,12 @@ _cairo_ft_unscaled_font_map_create (void) if (unlikely (font_map->hash_table == NULL)) goto FAIL; - if (unlikely (FT_Init_FreeType (&font_map->ft_library))) + CAIRO_MUTEX_INIT (font_map->ft_libraries_mutex); + CAIRO_MUTEX_LOCK (font_map->ft_libraries_mutex); + font_map->ft_libraries = + _cairo_hash_table_create (_ft_library_threads_equal); + CAIRO_MUTEX_UNLOCK (font_map->ft_libraries_mutex); + if (unlikely (_ft_library_get (font_map) == NULL)) goto FAIL; font_map->num_open_faces = 0; @@ -326,9 +407,12 @@ _cairo_ft_unscaled_font_map_destroy (void) font_map); assert (font_map->num_open_faces == 0); - FT_Done_FreeType (font_map->ft_library); - - _cairo_hash_table_destroy (font_map->hash_table); + _ft_libraries_done (font_map); + CAIRO_MUTEX_LOCK (font_map->ft_libraries_mutex); + _cairo_hash_table_destroy (font_map->ft_libraries); + font_map->ft_libraries = NULL; + CAIRO_MUTEX_UNLOCK (font_map->ft_libraries_mutex); + CAIRO_MUTEX_FINI (font_map->ft_libraries_mutex); free (font_map); } @@ -647,6 +731,7 @@ _cairo_ft_unscaled_font_lock_face (cairo_ft_unscaled_font_t *unscaled) { cairo_ft_unscaled_font_map_t *font_map; FT_Face face = NULL; + ft_library_entry_t *entry; CAIRO_MUTEX_LOCK (unscaled->mutex); unscaled->lock_count++; @@ -676,7 +761,9 @@ _cairo_ft_unscaled_font_lock_face (cairo_ft_unscaled_font_t *unscaled) } _cairo_ft_unscaled_font_map_unlock (); - if (FT_New_Face (font_map->ft_library, + entry = _ft_library_get (font_map); + if (entry != NULL && + FT_New_Face (entry->ft_library, unscaled->filename, unscaled->id, &face) != FT_Err_Ok) -- 1.8.3.1