Make FcGetDefaultLang and FcGetDefaultLangs thread-safe

This commit is contained in:
Behdad Esfahbod 2012-10-07 15:52:25 -04:00
parent 64af9e1917
commit b97ab0c949
4 changed files with 68 additions and 23 deletions

View File

@ -25,6 +25,8 @@
#include "fcint.h"
#include <string.h>
/* 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

View File

@ -156,6 +156,7 @@ FcFini (void)
FcConfigDestroy (_fcConfig);
FcCacheFini ();
FcDefaultFini ();
}
/*

View File

@ -761,6 +761,9 @@ FcInitDebug (void);
FcPrivate FcChar8 *
FcGetDefaultLang (void);
FcPrivate void
FcDefaultFini (void);
/* fcdir.c */
FcPrivate FcBool

View File

@ -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;