fontconfig: Branch 'wip/threadsafe' - 16 commits

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



 COPYING          |    1 
 configure.ac     |   38 ++++++
 m4/ax_pthread.m4 |  309 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/Makefile.am  |    2 
 src/fcarch.c     |    2 
 src/fcatomic.c   |    3 
 src/fcatomic.h   |  123 +++++++++++++++++++++
 src/fccache.c    |   40 +++----
 src/fccfg.c      |   87 +++++++++++----
 src/fccharset.c  |   25 ++--
 src/fcdbg.c      |   20 +--
 src/fcdefault.c  |   88 +++++++++++----
 src/fcformat.c   |    2 
 src/fcfreetype.c |    3 
 src/fcfs.c       |    1 
 src/fcinit.c     |   29 +----
 src/fcint.h      |   39 +++++-
 src/fclang.c     |   43 ++++---
 src/fclist.c     |    1 
 src/fcmatch.c    |    4 
 src/fcmatrix.c   |    2 
 src/fcmutex.h    |  126 ++++++++++++++++++++++
 src/fcname.c     |    4 
 src/fcobjs.c     |    2 
 src/fcpat.c      |   19 +--
 src/fcstr.c      |   39 +++---
 src/fcxml.c      |    4 
 27 files changed, 864 insertions(+), 192 deletions(-)

New commits:
commit fc45f436a3e73bae025cd565638f8898ab5102a3
Author: Behdad Esfahbod <behdad@xxxxxxxxxx>
Date:   Sun Oct 7 17:46:12 2012 -0400

    Minor

diff --git a/src/fccfg.c b/src/fccfg.c
index ecff6d1..4fc6f36 100644
--- a/src/fccfg.c
+++ b/src/fccfg.c
@@ -1702,7 +1702,7 @@ FcConfigSubstitute (FcConfig	*config,
 #  define WIN32_EXTRA_LEAN
 #  include <windows.h>
 
-static FcChar8 fontconfig_path[1000] = "";
+static FcChar8 fontconfig_path[1000] = ""; /* MT-dontcare */
 
 #  if (defined (PIC) || defined (DLL_EXPORT))
 
@@ -1879,7 +1879,7 @@ FcConfigFreePath (FcChar8 **path)
     free (path);
 }
 
-static FcBool	_FcConfigHomeEnabled = FcTrue;
+static FcBool	_FcConfigHomeEnabled = FcTrue; /* MT-goodenough */
 
 FcChar8 *
 FcConfigHome (void)
commit 98b81e0b2a1b10c070ec2b74ca7b254b2e055575
Author: Behdad Esfahbod <behdad@xxxxxxxxxx>
Date:   Sun Oct 7 17:42:18 2012 -0400

    Make FcCacheIsMmapSafe() threadsafe

diff --git a/src/fccache.c b/src/fccache.c
index 8c449a9..bf50f56 100644
--- a/src/fccache.c
+++ b/src/fccache.c
@@ -57,26 +57,32 @@ static void MD5Transform(FcChar32 buf[4], FcChar32 in[16]);
 static FcBool
 FcCacheIsMmapSafe (int fd)
 {
-    static FcBool is_initialized = FcFalse;
-    static FcBool is_env_available = FcFalse;
-    static FcBool use_mmap = FcFalse;
+    enum {
+      MMAP_NOT_INITIALIZED = 0,
+      MMAP_USE,
+      MMAP_DONT_USE,
+      MMAP_CHECK_FS,
+    } status;
+    static void *static_status;
 
-    if (!is_initialized)
-    {
-	const char *env;
+    status = (int) fc_atomic_ptr_get (&static_status);
 
-	env = getenv ("FONTCONFIG_USE_MMAP");
-	if (env)
-	{
-	    if (FcNameBool ((const FcChar8 *)env, &use_mmap))
-		is_env_available = FcTrue;
-	}
-	is_initialized = FcTrue;
+    if (status == MMAP_NOT_INITIALIZED)
+    {
+	const char *env = getenv ("FONTCONFIG_USE_MMAP");
+	FcBool use;
+	if (env && FcNameBool ((const FcChar8 *) env, &use))
+	    status =  use ? MMAP_USE : MMAP_DONT_USE;
+	else
+	    status = MMAP_CHECK_FS;
+	fc_atomic_ptr_cmpexch (&static_status, NULL, (void *) status);
     }
-    if (is_env_available)
-	return use_mmap;
 
-    return FcIsFsMmapSafe (fd);
+    if (status == MMAP_CHECK_FS)
+	return FcIsFsMmapSafe (fd);
+    else
+	return status == MMAP_USE;
+
 }
 
 static const char bin2hex[] = { '0', '1', '2', '3',
commit 6fd40c71fa138ce6e90136dd0c1dbea4284c8956
Author: Behdad Esfahbod <behdad@xxxxxxxxxx>
Date:   Sun Oct 7 17:41:58 2012 -0400

    Fix FcDefaultFini()
    
    Oops.

diff --git a/src/fcdefault.c b/src/fcdefault.c
index 00caee3..88e6142 100644
--- a/src/fcdefault.c
+++ b/src/fcdefault.c
@@ -110,12 +110,12 @@ FcDefaultFini (void)
     FcStrSet *langs;
 
     lang = fc_atomic_ptr_get (&default_lang);
-    if (fc_atomic_ptr_cmpexch (&default_lang, lang, NULL)) {
+    if (lang && fc_atomic_ptr_cmpexch (&default_lang, lang, NULL)) {
 	free (lang);
     }
 
     langs = fc_atomic_ptr_get (&default_langs);
-    if (fc_atomic_ptr_cmpexch (&default_langs, langs, NULL)) {
+    if (langs && fc_atomic_ptr_cmpexch (&default_langs, langs, NULL)) {
 	FcRefInit (&langs->ref, 1);
 	FcStrSetDestroy (langs);
     }
commit 9ea420ea0ff230e2a7131dbb67c68a0180507863
Author: Behdad Esfahbod <behdad@xxxxxxxxxx>
Date:   Sun Oct 7 17:29:45 2012 -0400

    Minor

diff --git a/src/fcinit.c b/src/fcinit.c
index ecb28e4..ea24ec9 100644
--- a/src/fcinit.c
+++ b/src/fcinit.c
@@ -159,8 +159,7 @@ FcInitReinitialize (void)
     config = FcInitLoadConfigAndFonts ();
     if (!config)
 	return FcFalse;
-    FcConfigSetCurrent (config);
-    return FcTrue;
+    return FcConfigSetCurrent (config);
 }
 
 FcBool
commit e16aa7370aa13482bd5259fd45804a5fb6564029
Author: Behdad Esfahbod <behdad@xxxxxxxxxx>
Date:   Sun Oct 7 17:02:50 2012 -0400

    Make default-FcConfig threadsafe

diff --git a/src/fccfg.c b/src/fccfg.c
index 97f595a..ecff6d1 100644
--- a/src/fccfg.c
+++ b/src/fccfg.c
@@ -22,6 +22,8 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
+/* Objects MT-safe for readonly access. */
+
 #include "fcint.h"
 #include <dirent.h>
 #include <sys/types.h>
@@ -36,29 +38,40 @@
 #define R_OK 4
 #endif
 
-static FcConfig    *_fcConfig;
+static FcConfig    *_fcConfig; /* MT-safe */
 
-FcBool
-FcConfigInit (void)
+static FcConfig *
+FcConfigEnsure (void)
 {
     FcConfig	*config;
-
-    if (_fcConfig)
-	return FcTrue;
-    config = FcInitLoadConfigAndFonts ();
+retry:
+    config = fc_atomic_ptr_get (&_fcConfig);
     if (!config)
-	return FcFalse;
-    FcConfigSetCurrent (config);
-    if (FcDebug() & FC_DBG_MEMORY)
-	FcMemReport ();
-    return FcTrue;
+    {
+	config = FcInitLoadConfigAndFonts ();
+	if (FcDebug() & FC_DBG_MEMORY)
+	    FcMemReport ();
+
+	if (!fc_atomic_ptr_cmpexch (&_fcConfig, NULL, config)) {
+	    FcConfigDestroy (config);
+	    goto retry;
+	}
+    }
+    return config;
+}
+
+FcBool
+FcConfigInit (void)
+{
+  return FcConfigEnsure ? FcTrue : FcFalse;
 }
 
 void
 FcConfigFini (void)
 {
-    if (_fcConfig)
-	FcConfigDestroy (_fcConfig);
+    FcConfig *cfg = fc_atomic_ptr_get (&_fcConfig);
+    if (cfg && fc_atomic_ptr_cmpexch (&_fcConfig, cfg, NULL))
+	FcConfigDestroy (cfg);
 }
 
 
@@ -263,8 +276,7 @@ FcConfigDestroy (FcConfig *config)
     if (FcRefDec (&config->ref) != 1)
 	return;
 
-    if (config == _fcConfig)
-	_fcConfig = 0;
+    fc_atomic_ptr_cmpexch (&_fcConfig, config, NULL);
 
     FcStrSetDestroy (config->configDirs);
     FcStrSetDestroy (config->fontDirs);
@@ -419,25 +431,31 @@ FcConfigBuildFonts (FcConfig *config)
 FcBool
 FcConfigSetCurrent (FcConfig *config)
 {
-    if (config == _fcConfig)
+    FcConfig *cfg;
+
+retry:
+    cfg = fc_atomic_ptr_get (&_fcConfig);
+
+    if (config == cfg)
 	return FcTrue;
 
     if (!config->fonts)
 	if (!FcConfigBuildFonts (config))
 	    return FcFalse;
 
-    if (_fcConfig)
-	FcConfigDestroy (_fcConfig);
-    _fcConfig = config;
+    if (!fc_atomic_ptr_cmpexch (&_fcConfig, cfg, config))
+	goto retry;
+
+    if (cfg)
+	FcConfigDestroy (cfg);
+
     return FcTrue;
 }
 
 FcConfig *
 FcConfigGetCurrent (void)
 {
-    if (!_fcConfig)
-	FcConfigInit ();
-    return _fcConfig;
+    return FcConfigEnsure ();
 }
 
 FcBool
diff --git a/src/fcdefault.c b/src/fcdefault.c
index 6c4eed2..00caee3 100644
--- a/src/fcdefault.c
+++ b/src/fcdefault.c
@@ -118,7 +118,6 @@ FcDefaultFini (void)
     if (fc_atomic_ptr_cmpexch (&default_langs, langs, NULL)) {
 	FcRefInit (&langs->ref, 1);
 	FcStrSetDestroy (langs);
-	langs = NULL;
     }
 }
 
commit baa5e7c3c94a2b5b1785b2177aafa1eba316fae8
Author: Behdad Esfahbod <behdad@xxxxxxxxxx>
Date:   Sun Oct 7 16:42:36 2012 -0400

    Minor

diff --git a/src/fccfg.c b/src/fccfg.c
index 7ad0da5..97f595a 100644
--- a/src/fccfg.c
+++ b/src/fccfg.c
@@ -436,8 +436,7 @@ FcConfig *
 FcConfigGetCurrent (void)
 {
     if (!_fcConfig)
-	if (!FcConfigInit ())
-	    return 0;
+	FcConfigInit ();
     return _fcConfig;
 }
 
commit eea5a914375e97b979c5cc247b95b3977f02329b
Author: Behdad Esfahbod <behdad@xxxxxxxxxx>
Date:   Sun Oct 7 16:37:03 2012 -0400

    Refactor; contain default config in fccfg.c

diff --git a/src/fccfg.c b/src/fccfg.c
index 7090090..7ad0da5 100644
--- a/src/fccfg.c
+++ b/src/fccfg.c
@@ -36,7 +36,31 @@
 #define R_OK 4
 #endif
 
-FcConfig    *_fcConfig;
+static FcConfig    *_fcConfig;
+
+FcBool
+FcConfigInit (void)
+{
+    FcConfig	*config;
+
+    if (_fcConfig)
+	return FcTrue;
+    config = FcInitLoadConfigAndFonts ();
+    if (!config)
+	return FcFalse;
+    FcConfigSetCurrent (config);
+    if (FcDebug() & FC_DBG_MEMORY)
+	FcMemReport ();
+    return FcTrue;
+}
+
+void
+FcConfigFini (void)
+{
+    if (_fcConfig)
+	FcConfigDestroy (_fcConfig);
+}
+
 
 FcConfig *
 FcConfigCreate (void)
@@ -412,7 +436,7 @@ FcConfig *
 FcConfigGetCurrent (void)
 {
     if (!_fcConfig)
-	if (!FcInit ())
+	if (!FcConfigInit ())
 	    return 0;
     return _fcConfig;
 }
diff --git a/src/fcinit.c b/src/fcinit.c
index f6919ed..ecb28e4 100644
--- a/src/fcinit.c
+++ b/src/fcinit.c
@@ -132,17 +132,7 @@ FcInitLoadConfigAndFonts (void)
 FcBool
 FcInit (void)
 {
-    FcConfig	*config;
-
-    if (_fcConfig)
-	return FcTrue;
-    config = FcInitLoadConfigAndFonts ();
-    if (!config)
-	return FcFalse;
-    FcConfigSetCurrent (config);
-    if (FcDebug() & FC_DBG_MEMORY)
-	FcMemReport ();
-    return FcTrue;
+    return FcConfigInit ();
 }
 
 /*
@@ -151,9 +141,7 @@ FcInit (void)
 void
 FcFini (void)
 {
-    if (_fcConfig)
-	FcConfigDestroy (_fcConfig);
-
+    FcConfigFini ();
     FcCacheFini ();
     FcDefaultFini ();
     if (FcDebug() & FC_DBG_MEMORY)
diff --git a/src/fcint.h b/src/fcint.h
index 8b2225b..795784c 100644
--- a/src/fcint.h
+++ b/src/fcint.h
@@ -528,8 +528,6 @@ struct _FcConfig {
     FcExprPage *expr_pool;	    /* pool of FcExpr's */
 };
 
-extern FcPrivate FcConfig	*_fcConfig;
-
 typedef struct _FcFileTime {
     time_t  time;
     FcBool  set;
@@ -592,6 +590,12 @@ FcDirCacheReference (FcCache *cache, int nref);
 
 /* fccfg.c */
 
+FcPrivate FcBool
+FcConfigInit (void);
+
+FcPrivate void
+FcConfigFini (void);
+
 FcPrivate FcChar8 *
 FcConfigXdgCacheHome (void);
 
diff --git a/src/fcxml.c b/src/fcxml.c
index 5edc867..befcf50 100644
--- a/src/fcxml.c
+++ b/src/fcxml.c
@@ -1068,7 +1068,7 @@ FcPStackPop (FcConfigParse *parse)
 }
 
 static FcBool
-FcConfigInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser)
+FcConfigParseInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser)
 {
     parse->pstack = 0;
     parse->pstack_static_used = 0;
@@ -2932,7 +2932,7 @@ FcConfigParseAndLoad (FcConfig	    *config,
     if (!p)
 	goto bail1;
 
-    if (!FcConfigInit (&parse, name, config, p))
+    if (!FcConfigParseInit (&parse, name, config, p))
 	goto bail2;
 
 #ifndef ENABLE_LIBXML2
commit 1ea981331bcd7e7913c1cdd76a66fef52816dda2
Author: Behdad Esfahbod <behdad@xxxxxxxxxx>
Date:   Sun Oct 7 16:26:53 2012 -0400

    Make FcDefaultFini() threadsafe

diff --git a/src/fcdefault.c b/src/fcdefault.c
index 3066f13..6c4eed2 100644
--- a/src/fcdefault.c
+++ b/src/fcdefault.c
@@ -106,14 +106,19 @@ retry:
 void
 FcDefaultFini (void)
 {
-    if (default_lang) {
-	free (default_lang);
-	default_lang = NULL;
+    FcChar8  *lang;
+    FcStrSet *langs;
+
+    lang = fc_atomic_ptr_get (&default_lang);
+    if (fc_atomic_ptr_cmpexch (&default_lang, lang, NULL)) {
+	free (lang);
     }
-    if (default_langs) {
-	FcRefInit (&default_langs->ref, 1);
-	FcStrSetDestroy (default_langs);
-	default_langs = NULL;
+
+    langs = fc_atomic_ptr_get (&default_langs);
+    if (fc_atomic_ptr_cmpexch (&default_langs, langs, NULL)) {
+	FcRefInit (&langs->ref, 1);
+	FcStrSetDestroy (langs);
+	langs = NULL;
     }
 }
 
commit 180b4203d781e93f2bc322240353bd36d4f65df1
Author: Behdad Esfahbod <behdad@xxxxxxxxxx>
Date:   Sun Oct 7 16:09:35 2012 -0400

    Make FcInitDebug() idempotent

diff --git a/src/fcdbg.c b/src/fcdbg.c
index ba1c35b..aa519e4 100644
--- a/src/fcdbg.c
+++ b/src/fcdbg.c
@@ -430,15 +430,17 @@ int FcDebugVal;
 void
 FcInitDebug (void)
 {
-    char    *e;
+    if (!FcDebugVal) {
+	char    *e;
 
-    e = getenv ("FC_DEBUG");
-    if (e)
-    {
-        printf ("FC_DEBUG=%s\n", e);
-        FcDebugVal = atoi (e);
-        if (FcDebugVal < 0)
-   	    FcDebugVal = 0;
+	e = getenv ("FC_DEBUG");
+	if (e)
+	{
+	    printf ("FC_DEBUG=%s\n", e);
+	    FcDebugVal = atoi (e);
+	    if (FcDebugVal < 0)
+		FcDebugVal = 0;
+	}
     }
 }
 #define __fcdbg__
commit 13d3438ba6a62cadeed2874ffb6da5f318c2a0e6
Author: Behdad Esfahbod <behdad@xxxxxxxxxx>
Date:   Sun Oct 7 16:07:57 2012 -0400

    Mark some vars as MT-dontcare

diff --git a/src/fcinit.c b/src/fcinit.c
index f4ba31d..f6919ed 100644
--- a/src/fcinit.c
+++ b/src/fcinit.c
@@ -239,12 +239,12 @@ static struct {
     { "sharedstr" },
 };
 
-static int  FcAllocCount, FcAllocMem;
-static int  FcFreeCount, FcFreeMem;
+static int  FcAllocCount, FcAllocMem; /* MT-dontcare */
+static int  FcFreeCount, FcFreeMem; /* MT-dontcare */
 
-static int  FcMemNotice = 1*1024*1024;
+static const int  FcMemNotice = 1*1024*1024;
 
-static int  FcAllocNotify, FcFreeNotify;
+static int  FcAllocNotify, FcFreeNotify; /* MT-dontcare */
 
 void
 FcMemReport (void)
commit 8e9ec4c5014372223a138ffc5a8816d018db4059
Author: Behdad Esfahbod <behdad@xxxxxxxxxx>
Date:   Sun Oct 7 16:04:49 2012 -0400

    Remove unused macro

diff --git a/src/fcstr.c b/src/fcstr.c
index d1d3be6..866beb7 100644
--- a/src/fcstr.c
+++ b/src/fcstr.c
@@ -78,8 +78,6 @@ FcStrFree (FcChar8 *s)
 #define FcCaseFoldUpperCount(cf) \
     ((cf)->method == FC_CASE_FOLD_FULL ? 1 : (cf)->count)
 
-#define FC_STR_CANON_BUF_LEN	1024
-
 typedef struct _FcCaseWalker {
     const FcChar8   *read;
     const FcChar8   *src;
commit afbf466854bd1d6e2dee2998cd66c82b6dda4e66
Author: Behdad Esfahbod <behdad@xxxxxxxxxx>
Date:   Sun Oct 7 15:52:25 2012 -0400

    Make FcGetDefaultLang and FcGetDefaultLangs thread-safe

diff --git a/src/fcdefault.c b/src/fcdefault.c
index 2b26bce..3066f13 100644
--- a/src/fcdefault.c
+++ b/src/fcdefault.c
@@ -24,6 +24,8 @@
 
 #include "fcint.h"
 
+/* MT-safe */
+
 static const struct {
     FcObject	field;
     FcBool	value;
@@ -31,7 +33,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	},
@@ -39,45 +40,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 69b17ff..f4ba31d 100644
--- a/src/fcinit.c
+++ b/src/fcinit.c
@@ -155,6 +155,7 @@ FcFini (void)
 	FcConfigDestroy (_fcConfig);
 
     FcCacheFini ();
+    FcDefaultFini ();
     if (FcDebug() & FC_DBG_MEMORY)
 	FcMemReport ();
 }
diff --git a/src/fcint.h b/src/fcint.h
index a4ca8a9..8b2225b 100644
--- a/src/fcint.h
+++ b/src/fcint.h
@@ -780,6 +780,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 842f85c..d1d3be6 100644
--- a/src/fcstr.c
+++ b/src/fcstr.c
@@ -1245,6 +1245,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;
 
commit 336916dce0ef11ed08d61b6dd24e8b8de0c0d36c
Author: Behdad Esfahbod <behdad@xxxxxxxxxx>
Date:   Sun Oct 7 15:35:47 2012 -0400

    Minor include cleanup

diff --git a/src/fcarch.c b/src/fcarch.c
index 44548fc..c79f051 100644
--- a/src/fcarch.c
+++ b/src/fcarch.c
@@ -21,8 +21,6 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <stdio.h>
-
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
diff --git a/src/fcatomic.c b/src/fcatomic.c
index 350744a..46217d5 100644
--- a/src/fcatomic.c
+++ b/src/fcatomic.c
@@ -51,9 +51,6 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <time.h>
 
 #ifdef _WIN32
 #define mkdir(path,mode) _mkdir(path)
diff --git a/src/fccache.c b/src/fccache.c
index 81985df..8c449a9 100644
--- a/src/fccache.c
+++ b/src/fccache.c
@@ -25,8 +25,6 @@
 #endif
 #include "fcint.h"
 #include "fcarch.h"
-#include <stdio.h>
-#include <stdlib.h>
 #include <fcntl.h>
 #include <dirent.h>
 #include <string.h>
diff --git a/src/fccharset.c b/src/fccharset.c
index a03e546..f6d2194 100644
--- a/src/fccharset.c
+++ b/src/fccharset.c
@@ -23,7 +23,6 @@
  */
 
 #include "fcint.h"
-#include <stdlib.h>
 
 /* #define CHECK */
 
diff --git a/src/fcdbg.c b/src/fcdbg.c
index a1ed2b2..ba1c35b 100644
--- a/src/fcdbg.c
+++ b/src/fcdbg.c
@@ -23,8 +23,6 @@
  */
 
 #include "fcint.h"
-#include <stdio.h>
-#include <stdlib.h>
 
 static void
 _FcValuePrint (const FcValue v)
diff --git a/src/fcdefault.c b/src/fcdefault.c
index 8ad1b1e..2b26bce 100644
--- a/src/fcdefault.c
+++ b/src/fcdefault.c
@@ -23,7 +23,6 @@
  */
 
 #include "fcint.h"
-#include <string.h>
 
 static const struct {
     FcObject	field;
diff --git a/src/fcformat.c b/src/fcformat.c
index 8eef7bb..10f9a18 100644
--- a/src/fcformat.c
+++ b/src/fcformat.c
@@ -23,8 +23,6 @@
  */
 
 #include "fcint.h"
-#include <stdlib.h>
-#include <string.h>
 #include <stdarg.h>
 
 
diff --git a/src/fcfreetype.c b/src/fcfreetype.c
index fb2b0f2..58ee7cf 100644
--- a/src/fcfreetype.c
+++ b/src/fcfreetype.c
@@ -46,9 +46,6 @@
 
 #include "fcint.h"
 #include "fcftint.h"
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
 #include <ft2build.h>
 #include FT_FREETYPE_H
 #include FT_TRUETYPE_TABLES_H
diff --git a/src/fcfs.c b/src/fcfs.c
index 6625687..fb55d07 100644
--- a/src/fcfs.c
+++ b/src/fcfs.c
@@ -23,7 +23,6 @@
  */
 
 #include "fcint.h"
-#include <stdlib.h>
 
 FcFontSet *
 FcFontSetCreate (void)
diff --git a/src/fcinit.c b/src/fcinit.c
index 9c3adb5..69b17ff 100644
--- a/src/fcinit.c
+++ b/src/fcinit.c
@@ -23,7 +23,6 @@
  */
 
 #include "fcint.h"
-#include <stdlib.h>
 
 static FcConfig *
 FcInitFallbackConfig (void)
diff --git a/src/fclist.c b/src/fclist.c
index 56f0432..9790593 100644
--- a/src/fclist.c
+++ b/src/fclist.c
@@ -23,7 +23,6 @@
  */
 
 #include "fcint.h"
-#include <stdlib.h>
 
 FcObjectSet *
 FcObjectSetCreate (void)
diff --git a/src/fcmatrix.c b/src/fcmatrix.c
index f0c6139..1e7129c 100644
--- a/src/fcmatrix.c
+++ b/src/fcmatrix.c
@@ -24,8 +24,6 @@
 
 #include "fcint.h"
 #include <math.h>
-#include <stdlib.h>
-#include <ctype.h>
 
 const FcMatrix    FcIdentityMatrix = { 1, 0, 0, 1 };
 
diff --git a/src/fcname.c b/src/fcname.c
index e85ff76..272e37e 100644
--- a/src/fcname.c
+++ b/src/fcname.c
@@ -23,10 +23,6 @@
  */
 
 #include "fcint.h"
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
 
 static const FcObjectType FcObjects[] = {
 #define FC_OBJECT(NAME, Type) { FC_##NAME, Type },
diff --git a/src/fcobjs.c b/src/fcobjs.c
index 0e80b49..75bb848 100644
--- a/src/fcobjs.c
+++ b/src/fcobjs.c
@@ -26,8 +26,6 @@
 
 #include "fcobjshash.h"
 
-#include <string.h>
-
 int
 FcObjectLookupIdByName (const char *str)
 {
diff --git a/src/fcstr.c b/src/fcstr.c
index bbf42cc..842f85c 100644
--- a/src/fcstr.c
+++ b/src/fcstr.c
@@ -23,9 +23,6 @@
  */
 
 #include "fcint.h"
-#include <stdlib.h>
-#include <ctype.h>
-#include <string.h>
 #ifdef HAVE_REGEX_H
 #include <regex.h>
 #endif
commit b9c06fd6272b2960c0d62560a2f051c3036e1ff6
Author: Behdad Esfahbod <behdad@xxxxxxxxxx>
Date:   Sun Oct 7 14:41:38 2012 -0400

    Make refcounts, patterns, charsets, strings, and FcLang thread-safe

diff --git a/src/fcatomic.h b/src/fcatomic.h
index 7479a3d..c066d12 100644
--- a/src/fcatomic.h
+++ b/src/fcatomic.h
@@ -63,7 +63,7 @@ static inline void HBMemoryBarrier (void) {
 }
 #endif
 
-typedef long fc_atomic_int_t;
+typedef int fc_atomic_int_t;
 #define fc_atomic_int_add(AI, V)	InterlockedExchangeAdd (&(AI), (V))
 
 #define fc_atomic_ptr_get(P)		(HBMemoryBarrier (), (void *) *(P))
@@ -74,7 +74,7 @@ typedef long fc_atomic_int_t;
 
 #include <libkern/OSAtomic.h>
 
-typedef int32_t fc_atomic_int_t;
+typedef int fc_atomic_int_t;
 #define fc_atomic_int_add(AI, V)	(OSAtomicAdd32Barrier ((V), &(AI)) - (V))
 
 #define fc_atomic_ptr_get(P)		(OSMemoryBarrier (), (void *) *(P))
@@ -111,13 +111,13 @@ typedef int fc_atomic_int_t;
 #endif
 
 /* reference count */
-#define FC_REF_CONSTANT ((fc_atomic_int_t) -1)
-#define FC_REF_CONSTANT_INIT {FC_REF_CONSTANT}
+#define FC_REF_CONSTANT_VALUE ((fc_atomic_int_t) -1)
+#define FC_REF_CONSTANT {FC_REF_CONSTANT_VALUE}
 typedef struct _FcRef { fc_atomic_int_t count; } FcRef;
-static inline void   FcRefInit    (FcRef *r, int v) { r->count = v; }
-static inline int    FcRefInc     (FcRef *r) { return fc_atomic_int_add (r->count, +1); }
-static inline int    FcRefDec     (FcRef *r) { return fc_atomic_int_add (r->count, -1); }
-static inline void   FcRefFinish  (FcRef *r) { r->count = FC_REF_CONSTANT; }
-static inline FcBool FcRefIsConst (FcRef *r) { return r->count == FC_REF_CONSTANT; }
+static inline void   FcRefInit     (FcRef *r, int v) { r->count = v; }
+static inline int    FcRefInc      (FcRef *r) { return fc_atomic_int_add (r->count, +1); }
+static inline int    FcRefDec      (FcRef *r) { return fc_atomic_int_add (r->count, -1); }
+static inline void   FcRefSetConst (FcRef *r) { r->count = FC_REF_CONSTANT_VALUE; }
+static inline FcBool FcRefIsConst  (const FcRef *r) { return r->count == FC_REF_CONSTANT_VALUE; }
 
 #endif /* _FCATOMIC_H_ */
diff --git a/src/fccfg.c b/src/fccfg.c
index d3752e5..7090090 100644
--- a/src/fccfg.c
+++ b/src/fccfg.c
@@ -95,7 +95,7 @@ FcConfigCreate (void)
 
     config->expr_pool = NULL;
 
-    config->ref = 1;
+    FcRefInit (&config->ref, 1);
 
     return config;
 
@@ -225,7 +225,7 @@ FcConfigReference (FcConfig *config)
 	    return 0;
     }
 
-    config->ref++;
+    FcRefInc (&config->ref);
 
     return config;
 }
@@ -236,7 +236,7 @@ FcConfigDestroy (FcConfig *config)
     FcSetName	set;
     FcExprPage	*page;
 
-    if (--config->ref > 0)
+    if (FcRefDec (&config->ref) != 1)
 	return;
 
     if (config == _fcConfig)
@@ -669,7 +669,7 @@ typedef struct _FcSubState {
 } FcSubState;
 
 static FcValue
-FcConfigPromote (FcValue v, FcValue u)
+FcConfigPromote (FcValue v, FcValue u, FcValuePromotionBuffer *buf)
 {
     if (v.type == FcTypeInteger)
     {
@@ -683,7 +683,8 @@ FcConfigPromote (FcValue v, FcValue u)
     }
     else if (v.type == FcTypeString && u.type == FcTypeLangSet)
     {
-	v.u.l = FcLangSetPromote (v.u.s);
+	assert (buf != NULL);
+	v.u.l = FcLangSetPromote (v.u.s, buf);
 	v.type = FcTypeLangSet;
     }
     return v;
@@ -699,9 +700,10 @@ FcConfigCompareValue (const FcValue	*left_o,
     FcBool	ret = FcFalse;
     FcOp	op = FC_OP_GET_OP (op_);
     int		flags = FC_OP_GET_FLAGS (op_);
+    FcValuePromotionBuffer buf1, buf2;
 
-    left = FcConfigPromote (left, right);
-    right = FcConfigPromote (right, left);
+    left = FcConfigPromote (left, right, &buf1);
+    right = FcConfigPromote (right, left, &buf2);
     if (left.type == right.type)
     {
 	switch (left.type) {
@@ -964,8 +966,8 @@ FcConfigEvaluate (FcPattern *p, FcExpr *e)
     case FcOpDivide:
 	vl = FcConfigEvaluate (p, e->u.tree.left);
 	vr = FcConfigEvaluate (p, e->u.tree.right);
-	vl = FcConfigPromote (vl, vr);
-	vr = FcConfigPromote (vr, vl);
+	vl = FcConfigPromote (vl, vr, NULL);
+	vr = FcConfigPromote (vr, vl, NULL);
 	if (vl.type == vr.type)
 	{
 	    switch (vl.type) {
diff --git a/src/fccharset.c b/src/fccharset.c
index 8c1d858..a03e546 100644
--- a/src/fccharset.c
+++ b/src/fccharset.c
@@ -36,7 +36,7 @@ FcCharSetCreate (void)
     if (!fcs)
 	return 0;
     FcMemAlloc (FC_MEM_CHARSET, sizeof (FcCharSet));
-    fcs->ref = 1;
+    FcRefInit (&fcs->ref, 1);
     fcs->num = 0;
     fcs->leaves_offset = 0;
     fcs->numbers_offset = 0;
@@ -56,12 +56,12 @@ FcCharSetDestroy (FcCharSet *fcs)
 
     if (fcs)
     {
-	if (fcs->ref == FC_REF_CONSTANT)
+	if (FcRefIsConst (&fcs->ref))
 	{
 	    FcCacheObjectDereference (fcs);
 	    return;
 	}
-	if (--fcs->ref > 0)
+	if (FcRefDec (&fcs->ref) != 1)
 	    return;
 	for (i = 0; i < fcs->num; i++)
 	{
@@ -255,7 +255,7 @@ FcCharSetAddChar (FcCharSet *fcs, FcChar32 ucs4)
     FcCharLeaf	*leaf;
     FcChar32	*b;
 
-    if (fcs == NULL || fcs->ref == FC_REF_CONSTANT)
+    if (fcs == NULL || FcRefIsConst (&fcs->ref))
 	return FcFalse;
     leaf = FcCharSetFindLeafCreate (fcs, ucs4);
     if (!leaf)
@@ -271,7 +271,7 @@ FcCharSetDelChar (FcCharSet *fcs, FcChar32 ucs4)
     FcCharLeaf	*leaf;
     FcChar32	*b;
 
-    if (fcs == NULL || fcs->ref == FC_REF_CONSTANT)
+    if (fcs == NULL || FcRefIsConst (&fcs->ref))
 	return FcFalse;
     leaf = FcCharSetFindLeaf (fcs, ucs4);
     if (!leaf)
@@ -347,8 +347,8 @@ FcCharSetCopy (FcCharSet *src)
 {
     if (src)
     {
-	if (src->ref != FC_REF_CONSTANT)
-	    src->ref++;
+	if (!FcRefIsConst (&src->ref))
+	    FcRefInc (&src->ref);
 	else
 	    FcCacheObjectReference (src);
     }
@@ -506,7 +506,7 @@ FcCharSetMerge (FcCharSet *a, const FcCharSet *b, FcBool *changed)
     if (!a || !b)
 	return FcFalse;
 
-    if (a->ref == FC_REF_CONSTANT) {
+    if (FcRefIsConst (&a->ref)) {
 	if (changed)
 	    *changed = FcFalse;
 	return FcFalse;
@@ -1227,7 +1227,7 @@ FcCharSetFreezeBase (FcCharSetFreezer *freezer, FcCharSet *fcs, const FcCharSet
 
     freezer->charsets_allocated++;
 
-    ent->set.ref = FC_REF_CONSTANT;
+    FcRefSetConst (&ent->set.ref);
     ent->set.num = fcs->num;
     if (fcs->num)
     {
@@ -1374,7 +1374,7 @@ FcCharSetSerializeAlloc (FcSerialize *serialize, const FcCharSet *cs)
     FcChar16	    *numbers;
     int		    i;
 
-    if (cs->ref != FC_REF_CONSTANT)
+    if (!FcRefIsConst (&cs->ref))
     {
 	if (!serialize->cs_freezer)
 	{
@@ -1413,7 +1413,7 @@ FcCharSetSerialize(FcSerialize *serialize, const FcCharSet *cs)
     FcCharLeaf	*leaf, *leaf_serialized;
     int		i;
 
-    if (cs->ref != FC_REF_CONSTANT && serialize->cs_freezer)
+    if (!FcRefIsConst (&cs->ref) && serialize->cs_freezer)
     {
 	cs = FcCharSetFindFrozen (serialize->cs_freezer, cs);
 	if (!cs)
@@ -1424,7 +1424,7 @@ FcCharSetSerialize(FcSerialize *serialize, const FcCharSet *cs)
     if (!cs_serialized)
 	return NULL;
 
-    cs_serialized->ref = FC_REF_CONSTANT;
+    FcRefSetConst (&cs_serialized->ref);
     cs_serialized->num = cs->num;
 
     if (cs->num)
diff --git a/src/fcint.h b/src/fcint.h
index 09cc448..a4ca8a9 100644
--- a/src/fcint.h
+++ b/src/fcint.h
@@ -40,6 +40,7 @@
 #endif
 #include <string.h>
 #include <ctype.h>
+#include <assert.h>
 #include <errno.h>
 #include <unistd.h>
 #include <stddef.h>
@@ -142,6 +143,8 @@ extern pfnSHGetFolderPathA pSHGetFolderPathA;
 #define FcPrivate
 #endif
 
+FC_ASSERT_STATIC (sizeof (FcRef) == sizeof (int));
+
 typedef enum _FcValueBinding {
     FcValueBindingWeak, FcValueBindingStrong, FcValueBindingSame
 } FcValueBinding;
@@ -222,7 +225,7 @@ struct _FcPattern {
     int		    num;
     int		    size;
     intptr_t	    elts_offset;
-    int		    ref;
+    FcRef	    ref;
 };
 
 #define FcPatternElts(p)	FcOffsetMember(p,elts_offset,FcPatternElt)
@@ -319,7 +322,7 @@ typedef struct _FcCharLeaf {
 } FcCharLeaf;
 
 struct _FcCharSet {
-    int		    ref;	/* reference count */
+    FcRef	    ref;	/* reference count */
     int		    num;	/* size of leaves and numbers arrays */
     intptr_t	    leaves_offset;
     intptr_t	    numbers_offset;
@@ -332,7 +335,7 @@ struct _FcCharSet {
 #define FcCharSetNumbers(c)	FcOffsetMember(c,numbers_offset,FcChar16)
 
 struct _FcStrSet {
-    int		    ref;	/* reference count */
+    FcRef	    ref;	/* reference count */
     int		    num;
     int		    size;
     FcChar8	    **strs;
@@ -520,7 +523,7 @@ struct _FcConfig {
     time_t	rescanTime;	    /* last time information was scanned */
     int		rescanInterval;	    /* interval between scans */
 
-    int		ref;                /* reference count */
+    FcRef	ref;                /* reference count */
 
     FcExprPage *expr_pool;	    /* pool of FcExpr's */
 };
@@ -548,6 +551,17 @@ struct _FcStatFS {
     FcBool is_mtime_broken;
 };
 
+typedef struct _FcValuePromotionBuffer FcValuePromotionBuffer;
+
+struct _FcValuePromotionBuffer {
+  union {
+    double d;
+    int i;
+    long l;
+    char c[256]; /* Enlarge as needed */
+  } u;
+};
+
 /* fcblanks.c */
 
 /* fccache.c */
@@ -825,7 +839,7 @@ FcPrivate FcLangResult
 FcLangCompare (const FcChar8 *s1, const FcChar8 *s2);
 
 FcPrivate FcLangSet *
-FcLangSetPromote (const FcChar8 *lang);
+FcLangSetPromote (const FcChar8 *lang, FcValuePromotionBuffer *buf);
 
 FcPrivate FcLangSet *
 FcNameParseLangSet (const FcChar8 *string);
diff --git a/src/fclang.c b/src/fclang.c
index b7e70fc..caa4068 100644
--- a/src/fclang.c
+++ b/src/fclang.c
@@ -22,10 +22,11 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <string.h>
 #include "fcint.h"
 #include "fcftint.h"
 
+/* Objects MT-safe for readonly access. */
+
 typedef struct {
     const FcChar8    	lang[8];
     const FcCharSet	charset;
@@ -695,34 +696,38 @@ FcLangSetCompare (const FcLangSet *lsa, const FcLangSet *lsb)
 
 /*
  * Used in computing values -- mustn't allocate any storage
- * XXX Not thread-safe
  */
 FcLangSet *
-FcLangSetPromote (const FcChar8 *lang)
+FcLangSetPromote (const FcChar8 *lang, FcValuePromotionBuffer *vbuf)
 {
-    static FcLangSet	ls;
-    static FcStrSet	strs;
-    static FcChar8	*str;
-    int			id;
-
-    memset (ls.map, '\0', sizeof (ls.map));
-    ls.map_size = NUM_LANG_SET_MAP;
-    ls.extra = 0;
+    int		id;
+    typedef struct {
+	FcLangSet  ls;
+	FcStrSet   strs;
+	FcChar8   *str;
+    } FcLangSetPromotionBuffer;
+    FcLangSetPromotionBuffer *buf = (FcLangSetPromotionBuffer *) vbuf;
+
+    FC_ASSERT_STATIC (sizeof (FcLangSetPromotionBuffer) <= sizeof (FcValuePromotionBuffer));
+
+    memset (buf->ls.map, '\0', sizeof (buf->ls.map));
+    buf->ls.map_size = NUM_LANG_SET_MAP;
+    buf->ls.extra = 0;
     id = FcLangSetIndex (lang);
     if (id > 0)
     {
-	FcLangSetBitSet (&ls, id);
+	FcLangSetBitSet (&buf->ls, id);
     }
     else
     {
-	ls.extra = &strs;
-	strs.num = 1;
-	strs.size = 1;
-	strs.strs = &str;
-	strs.ref = 1;
-	str = (FcChar8 *) lang;
+	buf->ls.extra = &buf->strs;
+	buf->strs.num = 1;
+	buf->strs.size = 1;
+	buf->strs.strs = &buf->str;
+	FcRefInit (&buf->strs.ref, 1);
+	buf->str = (FcChar8 *) lang;
     }
-    return &ls;
+    return &buf->ls;
 }
 
 FcChar32
diff --git a/src/fcmatch.c b/src/fcmatch.c
index 623538b..0d69143 100644
--- a/src/fcmatch.c
+++ b/src/fcmatch.c
@@ -23,10 +23,6 @@
  */
 
 #include "fcint.h"
-#include <assert.h>
-#include <string.h>
-#include <ctype.h>
-#include <stdio.h>
 
 static double
 FcCompareNumber (FcValue *value1, FcValue *value2)
diff --git a/src/fcpat.c b/src/fcpat.c
index 92b4cc4..05b307c 100644
--- a/src/fcpat.c
+++ b/src/fcpat.c
@@ -22,9 +22,8 @@
 
 #include "fcint.h"
 #include "fcftint.h"
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
+
+/* Objects MT-safe for readonly access. */
 
 FcPattern *
 FcPatternCreate (void)
@@ -38,7 +37,7 @@ FcPatternCreate (void)
     p->num = 0;
     p->size = 0;
     p->elts_offset = FcPtrToOffset (p, NULL);
-    p->ref = 1;
+    FcRefInit (&p->ref, 1);
     return p;
 }
 
@@ -280,13 +279,13 @@ FcPatternDestroy (FcPattern *p)
     int		    i;
     FcPatternElt    *elts;
 
-    if (p->ref == FC_REF_CONSTANT)
+    if (FcRefIsConst (&p->ref))
     {
 	FcCacheObjectDereference (p);
 	return;
     }
 	
-    if (--p->ref > 0)
+    if (FcRefDec (&p->ref) != 1)
 	return;
 
     elts = FcPatternElts (p);
@@ -470,7 +469,7 @@ FcPatternObjectAddWithBinding  (FcPattern	*p,
     FcPatternElt   *e;
     FcValueListPtr new, *prev;
 
-    if (p->ref == FC_REF_CONSTANT)
+    if (FcRefIsConst (&p->ref))
 	goto bail0;
 
     new = malloc (sizeof (FcValueList));
@@ -936,8 +935,8 @@ bail0:
 void
 FcPatternReference (FcPattern *p)
 {
-    if (p->ref != FC_REF_CONSTANT)
-	p->ref++;
+    if (!FcRefIsConst (&p->ref))
+	FcRefInc (&p->ref);
     else
 	FcCacheObjectReference (p);
 }
@@ -1073,7 +1072,7 @@ FcPatternSerialize (FcSerialize *serialize, const FcPattern *pat)
 	return NULL;
     *pat_serialized = *pat;
     pat_serialized->size = pat->num;
-    pat_serialized->ref = FC_REF_CONSTANT;
+    FcRefSetConst (&pat_serialized->ref);
 
     elts_serialized = FcSerializePtr (serialize, elts);
     if (!elts_serialized)
diff --git a/src/fcstr.c b/src/fcstr.c
index f505ea6..bbf42cc 100644
--- a/src/fcstr.c
+++ b/src/fcstr.c
@@ -33,6 +33,8 @@
 #include <windows.h>
 #endif
 
+/* Objects MT-safe for readonly access. */
+
 FcChar8 *
 FcStrCopy (const FcChar8 *s)
 {
@@ -1088,7 +1090,7 @@ FcStrSetCreate (void)
     if (!set)
 	return 0;
     FcMemAlloc (FC_MEM_STRSET, sizeof (FcStrSet));
-    set->ref = 1;
+    FcRefInit (&set->ref, 1);
     set->num = 0;
     set->size = 0;
     set->strs = 0;
@@ -1244,20 +1246,20 @@ FcStrSetDel (FcStrSet *set, const FcChar8 *s)
 void
 FcStrSetDestroy (FcStrSet *set)
 {
-    if (--set->ref == 0)
-    {
-	int	i;
+    int	i;
 
-	for (i = 0; i < set->num; i++)
-	    FcStrFree (set->strs[i]);
-	if (set->strs)
-	{
-	    FcMemFree (FC_MEM_STRSET, (set->size + 1) * sizeof (FcChar8 *));
-	    free (set->strs);
-	}
-	FcMemFree (FC_MEM_STRSET, sizeof (FcStrSet));
-	free (set);
+    if (FcRefDec (&set->ref) != 1)
+	return;
+
+    for (i = 0; i < set->num; i++)
+	FcStrFree (set->strs[i]);
+    if (set->strs)
+    {
+	FcMemFree (FC_MEM_STRSET, (set->size + 1) * sizeof (FcChar8 *));
+	free (set->strs);
     }
+    FcMemFree (FC_MEM_STRSET, sizeof (FcStrSet));
+    free (set);
 }
 
 FcStrList *
@@ -1270,7 +1272,7 @@ FcStrListCreate (FcStrSet *set)
 	return 0;
     FcMemAlloc (FC_MEM_STRLIST, sizeof (FcStrList));
     list->set = set;
-    set->ref++;
+    FcRefInc (&set->ref);
     list->n = 0;
     return list;
 }
commit 7d36ebb500ed0263206c4b4885d2851b982c5e9f
Author: Behdad Esfahbod <behdad@xxxxxxxxxx>
Date:   Sun Oct 7 14:24:28 2012 -0400

    Add thread-safety primitives

diff --git a/COPYING b/COPYING
index 2a5d777..66392b1 100644
--- a/COPYING
+++ b/COPYING
@@ -5,6 +5,7 @@ Copyright © 2005 Patrick Lam
 Copyright © 2009 Roozbeh Pournader
 Copyright © 2008,2009 Red Hat, Inc.
 Copyright © 2008 Danilo Šegan
+Copyright © 2012 Google, Inc.
 
 
 Permission to use, copy, modify, distribute, and sell this software and its
diff --git a/src/Makefile.am b/src/Makefile.am
index 3d83d3c..41633ba 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -122,6 +122,7 @@ EXTRA_DIST += \
 libfontconfig_la_SOURCES = \
 	fcarch.h \
 	fcatomic.c \
+	fcatomic.h \
 	fcblanks.c \
 	fccache.c \
 	fccfg.c \
@@ -137,6 +138,7 @@ libfontconfig_la_SOURCES = \
 	fclist.c \
 	fcmatch.c \
 	fcmatrix.c \
+	fcmutex.h \
 	fcname.c \
 	fcobjs.c \
 	fcobjs.h \
diff --git a/src/fcatomic.h b/src/fcatomic.h
new file mode 100644
index 0000000..7479a3d
--- /dev/null
+++ b/src/fcatomic.h
@@ -0,0 +1,123 @@
+/*
+ * Mutex operations.  Originally copied from HarfBuzz.
+ *
+ * Copyright © 2007  Chris Wilson
+ * Copyright © 2009,2010  Red Hat, Inc.
+ * Copyright © 2011,2012  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Contributor(s):
+ *	Chris Wilson <chris@xxxxxxxxxxxxxxxxxx>
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef _FCATOMIC_H_
+#define _FCATOMIC_H_
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+/* atomic_int */
+
+/* We need external help for these */
+
+#if 0
+
+
+#elif !defined(FC_NO_MT) && defined(_MSC_VER) || defined(__MINGW32__)
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+/* mingw32 does not have MemoryBarrier.
+ * MemoryBarrier may be defined as a macro or a function.
+ * Just make a failsafe version for ourselves. */
+#ifdef MemoryBarrier
+#define HBMemoryBarrier MemoryBarrier
+#else
+static inline void HBMemoryBarrier (void) {
+  long dummy = 0;
+  InterlockedExchange (&dummy, 1);
+}
+#endif
+
+typedef long fc_atomic_int_t;
+#define fc_atomic_int_add(AI, V)	InterlockedExchangeAdd (&(AI), (V))
+
+#define fc_atomic_ptr_get(P)		(HBMemoryBarrier (), (void *) *(P))
+#define fc_atomic_ptr_cmpexch(P,O,N)	(InterlockedCompareExchangePointer ((void **) (P), (void *) (N), (void *) (O)) == (void *) (O))
+
+
+#elif !defined(FC_NO_MT) && defined(__APPLE__)
+
+#include <libkern/OSAtomic.h>
+
+typedef int32_t fc_atomic_int_t;
+#define fc_atomic_int_add(AI, V)	(OSAtomicAdd32Barrier ((V), &(AI)) - (V))
+
+#define fc_atomic_ptr_get(P)		(OSMemoryBarrier (), (void *) *(P))
+#define fc_atomic_ptr_cmpexch(P,O,N)	OSAtomicCompareAndSwapPtrBarrier ((void *) (O), (void *) (N), (void **) (P))
+
+
+#elif !defined(FC_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
+
+typedef int fc_atomic_int_t;
+#define fc_atomic_int_add(AI, V)	__sync_fetch_and_add (&(AI), (V))
+
+#define fc_atomic_ptr_get(P)		(void *) (__sync_synchronize (), *(P))
+#define fc_atomic_ptr_cmpexch(P,O,N)	__sync_bool_compare_and_swap ((P), (O), (N))
+
+
+#elif !defined(FC_NO_MT)
+
+#define FC_ATOMIC_INT_NIL 1 /* Warn that fallback implementation is in use. */
+typedef volatile int fc_atomic_int_t;
+#define fc_atomic_int_add(AI, V)	(((AI) += (V)) - (V))
+
+#define fc_atomic_ptr_get(P)		((void *) *(P))
+#define fc_atomic_ptr_cmpexch(P,O,N)	(* (void * volatile *) (P) == (void *) (O) ? (* (void * volatile *) (P) = (void *) (N), true) : false)
+
+
+#else /* FC_NO_MT */
+
+typedef int fc_atomic_int_t;
+#define fc_atomic_int_add(AI, V)	(((AI) += (V)) - (V))
+
+#define fc_atomic_ptr_get(P)		((void *) *(P))
+#define fc_atomic_ptr_cmpexch(P,O,N)	(* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false)
+
+#endif
+
+/* reference count */
+#define FC_REF_CONSTANT ((fc_atomic_int_t) -1)
+#define FC_REF_CONSTANT_INIT {FC_REF_CONSTANT}
+typedef struct _FcRef { fc_atomic_int_t count; } FcRef;
+static inline void   FcRefInit    (FcRef *r, int v) { r->count = v; }
+static inline int    FcRefInc     (FcRef *r) { return fc_atomic_int_add (r->count, +1); }
+static inline int    FcRefDec     (FcRef *r) { return fc_atomic_int_add (r->count, -1); }
+static inline void   FcRefFinish  (FcRef *r) { r->count = FC_REF_CONSTANT; }
+static inline FcBool FcRefIsConst (FcRef *r) { return r->count == FC_REF_CONSTANT; }
+
+#endif /* _FCATOMIC_H_ */
diff --git a/src/fcint.h b/src/fcint.h
index 74646c7..09cc448 100644
--- a/src/fcint.h
+++ b/src/fcint.h
@@ -49,6 +49,8 @@
 #include <fontconfig/fontconfig.h>
 #include <fontconfig/fcprivate.h>
 #include "fcdeprecate.h"
+#include "fcmutex.h"
+#include "fcatomic.h"
 
 #ifndef FC_CONFIG_PATH
 #define FC_CONFIG_PATH "fonts.conf"
@@ -316,8 +318,6 @@ typedef struct _FcCharLeaf {
     FcChar32	map[256/32];
 } FcCharLeaf;
 
-#define FC_REF_CONSTANT	    -1
-
 struct _FcCharSet {
     int		    ref;	/* reference count */
     int		    num;	/* size of leaves and numbers arrays */
diff --git a/src/fcmutex.h b/src/fcmutex.h
new file mode 100644
index 0000000..dd4487d
--- /dev/null
+++ b/src/fcmutex.h
@@ -0,0 +1,126 @@
+/*
+ * Atomic int and pointer operations.  Originally copied from HarfBuzz.
+ *
+ * Copyright © 2007  Chris Wilson
+ * Copyright © 2009,2010  Red Hat, Inc.
+ * Copyright © 2011,2012  Google, Inc.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Contributor(s):
+ *	Chris Wilson <chris@xxxxxxxxxxxxxxxxxx>
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef _FCMUTEX_H_
+#define _FCMUTEX_H_
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+/* mutex */
+
+/* We need external help for these */
+
+#if 0
+
+
+#elif !defined(FC_NO_MT) && defined(_MSC_VER) || defined(__MINGW32__)
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+typedef CRITICAL_SECTION fc_mutex_impl_t;
+#define FC_MUTEX_IMPL_INIT	{ NULL, 0, 0, NULL, NULL, 0 }
+#define fc_mutex_impl_init(M)	InitializeCriticalSection (M)
+#define fc_mutex_impl_lock(M)	EnterCriticalSection (M)
+#define fc_mutex_impl_unlock(M)	LeaveCriticalSection (M)
+#define fc_mutex_impl_finish(M)	DeleteCriticalSection (M)
+
+
+#elif !defined(FC_NO_MT) && (defined(HAVE_PTHREAD) || defined(__APPLE__))
+
+#include <pthread.h>
+typedef pthread_mutex_t fc_mutex_impl_t;
+#define FC_MUTEX_IMPL_INIT	PTHREAD_MUTEX_INITIALIZER
+#define fc_mutex_impl_init(M)	pthread_mutex_init (M, NULL)
+#define fc_mutex_impl_lock(M)	pthread_mutex_lock (M)
+#define fc_mutex_impl_unlock(M)	pthread_mutex_unlock (M)
+#define fc_mutex_impl_finish(M)	pthread_mutex_destroy (M)
+
+
+#elif !defined(FC_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
+
+#if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD)
+# include <sched.h>
+# define FC_SCHED_YIELD() sched_yield ()
+#else
+# define FC_SCHED_YIELD() FC_STMT_START {} FC_STMT_END
+#endif
+
+/* This actually is not a totally awful implementation. */
+typedef volatile int fc_mutex_impl_t;
+#define FC_MUTEX_IMPL_INIT	0
+#define fc_mutex_impl_init(M)	*(M) = 0
+#define fc_mutex_impl_lock(M)	FC_STMT_START { while (__sync_lock_test_and_set((M), 1)) FC_SCHED_YIELD (); } FC_STMT_END
+#define fc_mutex_impl_unlock(M)	__sync_lock_release (M)
+#define fc_mutex_impl_finish(M)	FC_STMT_START {} FC_STMT_END
+
+
+#elif !defined(FC_NO_MT)
+
+#if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD)
+# include <sched.h>
+# define FC_SCHED_YIELD() sched_yield ()
+#else
+# define FC_SCHED_YIELD() FC_STMT_START {} FC_STMT_END
+#endif
+
+#define FC_MUTEX_INT_NIL 1 /* Warn that fallback implementation is in use. */
+typedef volatile int fc_mutex_impl_t;
+#define FC_MUTEX_IMPL_INIT	0
+#define fc_mutex_impl_init(M)	*(M) = 0
+#define fc_mutex_impl_lock(M)	FC_STMT_START { while (*(M)) FC_SCHED_YIELD (); (*(M))++; } FC_STMT_END
+#define fc_mutex_impl_unlock(M)	(*(M))--;
+#define fc_mutex_impl_finish(M)	FC_STMT_START {} FC_STMT_END
+
+
+#else /* FC_NO_MT */
+
+typedef int fc_mutex_impl_t;
+#define FC_MUTEX_IMPL_INIT	0
+#define fc_mutex_impl_init(M)	FC_STMT_START {} FC_STMT_END
+#define fc_mutex_impl_lock(M)	FC_STMT_START {} FC_STMT_END
+#define fc_mutex_impl_unlock(M)	FC_STMT_START {} FC_STMT_END
+#define fc_mutex_impl_finish(M)	FC_STMT_START {} FC_STMT_END
+
+#endif
+
+
+#define FC_MUTEX_INIT		{FC_MUTEX_IMPL_INIT}
+typedef fc_mutex_impl_t FcMutex;
+static inline void FcMutexInit   (FcMutex *m) { fc_mutex_impl_init (m);   }
+static inline void FcMutexLock   (FcMutex *m) { fc_mutex_impl_lock (m);   }
+static inline void FcMutexUnlock (FcMutex *m) { fc_mutex_impl_unlock (m); }
+static inline void FcMutexFinish (FcMutex *m) { fc_mutex_impl_finish (m); }
+
+
+#endif /* _FCMUTEX_H_ */
commit b3a3c1d4599b9dc5412bb1dc0e57b6da75b8821f
Author: Behdad Esfahbod <behdad@xxxxxxxxxx>
Date:   Sun Oct 7 13:49:45 2012 -0400

    Add build stuff for threadsafety primitives
    
    Copied over from HarfBuzz.

diff --git a/configure.ac b/configure.ac
index 870979d..6796863 100644
--- a/configure.ac
+++ b/configure.ac
@@ -150,7 +150,7 @@ AC_LINK_IFELSE([AC_LANG_SOURCE([[
 	}
 	]])],[
 		AC_MSG_RESULT([yes])
-		AC_DEFINE([HAVE_POSIX_FADVISE], [1], [Define to 1 if you have the `posix_fadvise' function.])
+		AC_DEFINE([HAVE_POSIX_FADVISE], [1], [Define to 1 if you have the 'posix_fadvise' function.])
 	],[AC_MSG_RESULT([no])])
 CFLAGS="$fc_saved_CFLAGS"
 
@@ -566,6 +566,42 @@ AC_SUBST(CONFIGDIR)
 AC_SUBST(xmldir)
 AC_SUBST(XMLDIR)
 
+
+dnl ===========================================================================
+
+#
+# Thread-safety primitives
+#
+
+AC_CACHE_CHECK([for Intel atomic primitives], fc_cv_have_intel_atomic_primitives, [
+	fc_cv_have_intel_atomic_primitives=false
+	AC_TRY_LINK([
+		void memory_barrier (void) { __sync_synchronize (); }
+		int atomic_add (int *i) { return __sync_fetch_and_add (i, 1); }
+		int mutex_trylock (int *m) { return __sync_lock_test_and_set (m, 1); }
+		void mutex_unlock (int *m) { __sync_lock_release (m); }
+		], [], fc_cv_have_intel_atomic_primitives=true
+	)
+])
+if $fc_cv_have_intel_atomic_primitives; then
+	AC_DEFINE(HAVE_INTEL_ATOMIC_PRIMITIVES, 1, [Have Intel __sync_* atomic primitives])
+fi
+
+AC_CHECK_HEADERS(sched.h)
+AC_CHECK_FUNCS(sched_yield)
+
+have_pthread=false
+if test "$os_win32" = no; then
+	AX_PTHREAD([have_pthread=true])
+fi
+if $have_pthread; then
+	AC_DEFINE(HAVE_PTHREAD, 1, [Have POSIX threads])
+fi
+AM_CONDITIONAL(HAVE_PTHREAD, $have_pthread)
+
+
+dnl ===========================================================================
+
 #
 # Let people not build/install docs if they don't have docbook
 #
diff --git a/m4/ax_pthread.m4 b/m4/ax_pthread.m4
new file mode 100644
index 0000000..d90de34
--- /dev/null
+++ b/m4/ax_pthread.m4
@@ -0,0 +1,309 @@
+# ===========================================================================
+#        http://www.gnu.org/software/autoconf-archive/ax_pthread.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
+#
+# DESCRIPTION
+#
+#   This macro figures out how to build C programs using POSIX threads. It
+#   sets the PTHREAD_LIBS output variable to the threads library and linker
+#   flags, and the PTHREAD_CFLAGS output variable to any special C compiler
+#   flags that are needed. (The user can also force certain compiler
+#   flags/libs to be tested by setting these environment variables.)
+#
+#   Also sets PTHREAD_CC to any special C compiler that is needed for
+#   multi-threaded programs (defaults to the value of CC otherwise). (This
+#   is necessary on AIX to use the special cc_r compiler alias.)
+#
+#   NOTE: You are assumed to not only compile your program with these flags,
+#   but also link it with them as well. e.g. you should link with
+#   $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
+#
+#   If you are only building threads programs, you may wish to use these
+#   variables in your default LIBS, CFLAGS, and CC:
+#
+#     LIBS="$PTHREAD_LIBS $LIBS"
+#     CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+#     CC="$PTHREAD_CC"
+#
+#   In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
+#   has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name
+#   (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
+#
+#   Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
+#   PTHREAD_PRIO_INHERIT symbol is defined when compiling with
+#   PTHREAD_CFLAGS.
+#
+#   ACTION-IF-FOUND is a list of shell commands to run if a threads library
+#   is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it
+#   is not found. If ACTION-IF-FOUND is not specified, the default action
+#   will define HAVE_PTHREAD.
+#
+#   Please let the authors know if this macro fails on any platform, or if
+#   you have any other suggestions or comments. This macro was based on work
+#   by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help
+#   from M. Frigo), as well as ac_pthread and hb_pthread macros posted by
+#   Alejandro Forero Cuervo to the autoconf macro repository. We are also
+#   grateful for the helpful feedback of numerous users.
+#
+#   Updated for Autoconf 2.68 by Daniel Richard G.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Steven G. Johnson <stevenj@xxxxxxxxxxxx>
+#   Copyright (c) 2011 Daniel Richard G. <skunk@xxxxxxxxxx>
+#
+#   This program is free software: you can redistribute it and/or modify it
+#   under the terms of the GNU General Public License as published by the
+#   Free Software Foundation, either version 3 of the License, or (at your
+#   option) any later version.
+#
+#   This program 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 General
+#   Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License along
+#   with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+#   As a special exception, the respective Autoconf Macro's copyright owner
+#   gives unlimited permission to copy, distribute and modify the configure
+#   scripts that are the output of Autoconf when processing the Macro. You
+#   need not follow the terms of the GNU General Public License when using
+#   or distributing such scripts, even though portions of the text of the
+#   Macro appear in them. The GNU General Public License (GPL) does govern
+#   all other use of the material that constitutes the Autoconf Macro.
+#
+#   This special exception to the GPL applies to versions of the Autoconf
+#   Macro released by the Autoconf Archive. When you make and distribute a
+#   modified version of the Autoconf Macro, you may extend this special
+#   exception to the GPL to apply to your modified version as well.
+
+#serial 18
+
+AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
+AC_DEFUN([AX_PTHREAD], [
+AC_REQUIRE([AC_CANONICAL_HOST])
+AC_LANG_PUSH([C])
+ax_pthread_ok=no
+
+# We used to check for pthread.h first, but this fails if pthread.h
+# requires special compiler flags (e.g. on True64 or Sequent).
+# It gets checked for in the link test anyway.
+
+# First of all, check if the user has set any of the PTHREAD_LIBS,
+# etcetera environment variables, and if threads linking works using
+# them:
+if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
+        save_CFLAGS="$CFLAGS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+        save_LIBS="$LIBS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
+        AC_TRY_LINK_FUNC(pthread_join, ax_pthread_ok=yes)
+        AC_MSG_RESULT($ax_pthread_ok)
+        if test x"$ax_pthread_ok" = xno; then
+                PTHREAD_LIBS=""
+                PTHREAD_CFLAGS=""
+        fi
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+fi
+
+# We must check for the threads library under a number of different
+# names; the ordering is very important because some systems
+# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
+# libraries is broken (non-POSIX).
+
+# Create a list of thread flags to try.  Items starting with a "-" are
+# C compiler flags, and other items are library names, except for "none"
+# which indicates that we try without any flags at all, and "pthread-config"
+# which is a program returning the flags for the Pth emulation library.
+
+ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
+
+# The ordering *is* (sometimes) important.  Some notes on the
+# individual items follow:
+
+# pthreads: AIX (must check this before -lpthread)
+# none: in case threads are in libc; should be tried before -Kthread and
+#       other compiler flags to prevent continual compiler warnings
+# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
+# -pthreads: Solaris/gcc
+# -mthreads: Mingw32/gcc, Lynx/gcc
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+#      doesn't hurt to check since this sometimes defines pthreads too;
+#      also defines -D_REENTRANT)
+#      ... -mt is also the pthreads flag for HP/aCC
+# pthread: Linux, etcetera
+# --thread-safe: KAI C++
+# pthread-config: use pthread-config program (for GNU Pth library)
+
+case ${host_os} in
+        solaris*)
+
+        # On Solaris (at least, for some versions), libc contains stubbed
+        # (non-functional) versions of the pthreads routines, so link-based
+        # tests will erroneously succeed.  (We need to link with -pthreads/-mt/
+        # -lpthread.)  (The stubs are missing pthread_cleanup_push, or rather
+        # a function called by this macro, so we could check for that, but
+        # who knows whether they'll stub that too in a future libc.)  So,
+        # we'll just look for -pthreads and -lpthread first:
+
+        ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags"
+        ;;
+
+        darwin*)
+        ax_pthread_flags="-pthread $ax_pthread_flags"
+        ;;
+esac
+
+if test x"$ax_pthread_ok" = xno; then
+for flag in $ax_pthread_flags; do
+
+        case $flag in
+                none)
+                AC_MSG_CHECKING([whether pthreads work without any flags])
+                ;;
+
+                -*)
+                AC_MSG_CHECKING([whether pthreads work with $flag])
+                PTHREAD_CFLAGS="$flag"
+                ;;
+
+                pthread-config)
+                AC_CHECK_PROG(ax_pthread_config, pthread-config, yes, no)
+                if test x"$ax_pthread_config" = xno; then continue; fi
+                PTHREAD_CFLAGS="`pthread-config --cflags`"
+                PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+                ;;
+
+                *)
+                AC_MSG_CHECKING([for the pthreads library -l$flag])
+                PTHREAD_LIBS="-l$flag"
+                ;;
+        esac
+
+        save_LIBS="$LIBS"
+        save_CFLAGS="$CFLAGS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+        # Check for various functions.  We must include pthread.h,
+        # since some functions may be macros.  (On the Sequent, we
+        # need a special flag -Kthread to make this header compile.)
+        # We check for pthread_join because it is in -lpthread on IRIX
+        # while pthread_create is in libc.  We check for pthread_attr_init
+        # due to DEC craziness with -lpthreads.  We check for
+        # pthread_cleanup_push because it is one of the few pthread
+        # functions on Solaris that doesn't have a non-functional libc stub.
+        # We try pthread_create on general principles.
+        AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
+                        static void routine(void *a) { a = 0; }
+                        static void *start_routine(void *a) { return a; }],
+                       [pthread_t th; pthread_attr_t attr;
+                        pthread_create(&th, 0, start_routine, 0);
+                        pthread_join(th, 0);
+                        pthread_attr_init(&attr);
+                        pthread_cleanup_push(routine, 0);
+                        pthread_cleanup_pop(0) /* ; */])],
+                [ax_pthread_ok=yes],
+                [])
+
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+
+        AC_MSG_RESULT($ax_pthread_ok)
+        if test "x$ax_pthread_ok" = xyes; then
+                break;
+        fi
+
+        PTHREAD_LIBS=""
+        PTHREAD_CFLAGS=""
+done
+fi
+
+# Various other checks:
+if test "x$ax_pthread_ok" = xyes; then
+        save_LIBS="$LIBS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        save_CFLAGS="$CFLAGS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+        # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
+        AC_MSG_CHECKING([for joinable pthread attribute])
+        attr_name=unknown
+        for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+            AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
+                           [int attr = $attr; return attr /* ; */])],
+                [attr_name=$attr; break],
+                [])
+        done
+        AC_MSG_RESULT($attr_name)
+        if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
+            AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
+                               [Define to necessary symbol if this constant
+                                uses a non-standard name on your system.])
+        fi
+
+        AC_MSG_CHECKING([if more special flags are required for pthreads])
+        flag=no
+        case ${host_os} in
+            aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";;
+            osf* | hpux*) flag="-D_REENTRANT";;
+            solaris*)
+            if test "$GCC" = "yes"; then
+                flag="-D_REENTRANT"
+            else
+                flag="-mt -D_REENTRANT"
+            fi
+            ;;
+        esac
+        AC_MSG_RESULT(${flag})
+        if test "x$flag" != xno; then
+            PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
+        fi
+
+        AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
+            ax_cv_PTHREAD_PRIO_INHERIT, [
+                AC_LINK_IFELSE([
+                    AC_LANG_PROGRAM([[#include <pthread.h>]], [[int i = PTHREAD_PRIO_INHERIT;]])],
+                    [ax_cv_PTHREAD_PRIO_INHERIT=yes],
+                    [ax_cv_PTHREAD_PRIO_INHERIT=no])
+            ])
+        AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"],
+            AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], 1, [Have PTHREAD_PRIO_INHERIT.]))
+
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+
+        # More AIX lossage: must compile with xlc_r or cc_r
+        if test x"$GCC" != xyes; then
+          AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC})
+        else
+          PTHREAD_CC=$CC
+        fi
+else
+        PTHREAD_CC="$CC"
+fi
+
+AC_SUBST(PTHREAD_LIBS)
+AC_SUBST(PTHREAD_CFLAGS)
+AC_SUBST(PTHREAD_CC)
+
+# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+if test x"$ax_pthread_ok" = xyes; then
+        ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
+        :
+else
+        ax_pthread_ok=no
+        $2
+fi
+AC_LANG_POP
+])dnl AX_PTHREAD
_______________________________________________
Fontconfig mailing list
Fontconfig@xxxxxxxxxxxxxxxxxxxxx
http://lists.freedesktop.org/mailman/listinfo/fontconfig

[Index of Archives]     [Fedora Fonts]     [Fedora Users]     [Fedora Cloud]     [Kernel]     [Fedora Packaging]     [Fedora Desktop]     [PAM]     [Gimp Graphics Editor]     [Yosemite News]

  Powered by Linux