From b97ab0c94938448dc2b780b8f0f60fb68884899f Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sun, 7 Oct 2012 15:52:25 -0400 Subject: [PATCH] Make FcGetDefaultLang and FcGetDefaultLangs thread-safe --- src/fcdefault.c | 83 +++++++++++++++++++++++++++++++++++-------------- src/fcinit.c | 1 + src/fcint.h | 3 ++ src/fcstr.c | 4 +++ 4 files changed, 68 insertions(+), 23 deletions(-) diff --git a/src/fcdefault.c b/src/fcdefault.c index d977857..62cf63b 100644 --- a/src/fcdefault.c +++ b/src/fcdefault.c @@ -25,6 +25,8 @@ #include "fcint.h" #include +/* MT-safe */ + static const struct { FcObject field; FcBool value; @@ -32,7 +34,6 @@ static const struct { { FC_HINTING_OBJECT, FcTrue }, /* !FT_LOAD_NO_HINTING */ { FC_VERTICAL_LAYOUT_OBJECT, FcFalse }, /* FC_LOAD_VERTICAL_LAYOUT */ { FC_AUTOHINT_OBJECT, FcFalse }, /* FC_LOAD_FORCE_AUTOHINT */ - /* XXX: FC_GLOBAL_ADVANCE is deprecated */ { FC_GLOBAL_ADVANCE_OBJECT, FcTrue }, /* !FC_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH */ { FC_EMBEDDED_BITMAP_OBJECT, FcTrue }, /* !FC_LOAD_NO_BITMAP */ { FC_DECORATIVE_OBJECT, FcFalse }, @@ -40,45 +41,81 @@ static const struct { #define NUM_FC_BOOL_DEFAULTS (int) (sizeof FcBoolDefaults / sizeof FcBoolDefaults[0]) +FcStrSet *default_langs; + FcStrSet * FcGetDefaultLangs (void) { - FcStrSet *result = FcStrSetCreate (); - char *langs; - - langs = getenv ("FC_LANG"); - if (!langs || !langs[0]) - langs = getenv ("LC_ALL"); - if (!langs || !langs[0]) - langs = getenv ("LC_CTYPE"); - if (!langs || !langs[0]) - langs = getenv ("LANG"); - if (langs && langs[0]) + FcStrSet *result; +retry: + result = (FcStrSet *) fc_atomic_ptr_get (&default_langs); + if (!result) { - if (!FcStrSetAddLangs (result, langs)) + char *langs; + + result = FcStrSetCreate (); + + langs = getenv ("FC_LANG"); + if (!langs || !langs[0]) + langs = getenv ("LC_ALL"); + if (!langs || !langs[0]) + langs = getenv ("LC_CTYPE"); + if (!langs || !langs[0]) + langs = getenv ("LANG"); + if (langs && langs[0]) + { + if (!FcStrSetAddLangs (result, langs)) + FcStrSetAdd (result, (const FcChar8 *) "en"); + } + else FcStrSetAdd (result, (const FcChar8 *) "en"); + + FcRefSetConst (&result->ref); + if (!fc_atomic_ptr_cmpexch (&default_langs, NULL, result)) { + FcRefInit (&result->ref, 1); + FcStrSetDestroy (result); + goto retry; + } } - else - FcStrSetAdd (result, (const FcChar8 *) "en"); return result; } +static FcChar8 *default_lang; /* MT-safe */ + FcChar8 * FcGetDefaultLang (void) { - static FcChar8 lang_local[128] = {0}; - FcStrSet *langs; - - if (!lang_local[0]) + FcChar8 *lang; +retry: + lang = fc_atomic_ptr_get (&default_lang); + if (!lang) { - langs = FcGetDefaultLangs (); - strncpy ((char *)lang_local, (const char *)langs->strs[0], 127); - lang_local[127] = 0; + FcStrSet *langs = FcGetDefaultLangs (); + lang = (FcChar8 *) strdup ((const char *) langs->strs[0]); FcStrSetDestroy (langs); + + if (!fc_atomic_ptr_cmpexch (&default_lang, NULL, lang)) { + free (lang); + goto retry; + } } - return lang_local; + return lang; +} + +void +FcDefaultFini (void) +{ + if (default_lang) { + free (default_lang); + default_lang = NULL; + } + if (default_langs) { + FcRefInit (&default_langs->ref, 1); + FcStrSetDestroy (default_langs); + default_langs = NULL; + } } void diff --git a/src/fcinit.c b/src/fcinit.c index 31578ad..75d96a9 100644 --- a/src/fcinit.c +++ b/src/fcinit.c @@ -156,6 +156,7 @@ FcFini (void) FcConfigDestroy (_fcConfig); FcCacheFini (); + FcDefaultFini (); } /* diff --git a/src/fcint.h b/src/fcint.h index ab4a7e1..f678b0c 100644 --- a/src/fcint.h +++ b/src/fcint.h @@ -761,6 +761,9 @@ FcInitDebug (void); FcPrivate FcChar8 * FcGetDefaultLang (void); +FcPrivate void +FcDefaultFini (void); + /* fcdir.c */ FcPrivate FcBool diff --git a/src/fcstr.c b/src/fcstr.c index e72be5e..f278022 100644 --- a/src/fcstr.c +++ b/src/fcstr.c @@ -1234,6 +1234,10 @@ FcStrSetDestroy (FcStrSet *set) { int i; + /* We rely on this in FcGetDefaultLangs for caching. */ + if (FcRefIsConst (&set->ref)) + return; + if (FcRefDec (&set->ref) != 1) return;