Make refcounts, patterns, charsets, strings, and FcLang thread-safe
authorBehdad Esfahbod <behdad@behdad.org>
Sun, 7 Oct 2012 18:41:38 +0000 (14:41 -0400)
committerBehdad Esfahbod <behdad@behdad.org>
Wed, 2 Jan 2013 06:51:00 +0000 (00:51 -0600)
src/fcatomic.h
src/fccfg.c
src/fccharset.c
src/fcdefault.c
src/fcint.h
src/fclang.c
src/fcmatch.c
src/fcmutex.h
src/fcpat.c
src/fcstr.c

index 7479a3d..c066d12 100644 (file)
@@ -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_ */
index ef5f4ff..dd34f5a 100644 (file)
@@ -94,7 +94,7 @@ FcConfigCreate (void)
 
     config->expr_pool = NULL;
 
-    config->ref = 1;
+    FcRefInit (&config->ref, 1);
 
     return config;
 
@@ -221,7 +221,7 @@ FcConfigReference (FcConfig *config)
            return 0;
     }
 
-    config->ref++;
+    FcRefInc (&config->ref);
 
     return config;
 }
@@ -232,7 +232,7 @@ FcConfigDestroy (FcConfig *config)
     FcSetName  set;
     FcExprPage *page;
 
-    if (--config->ref > 0)
+    if (FcRefDec (&config->ref) != 1)
        return;
 
     if (config == _fcConfig)
@@ -662,7 +662,7 @@ typedef struct _FcSubState {
 } FcSubState;
 
 static FcValue
-FcConfigPromote (FcValue v, FcValue u)
+FcConfigPromote (FcValue v, FcValue u, FcValuePromotionBuffer *buf)
 {
     if (v.type == FcTypeInteger)
     {
@@ -674,9 +674,9 @@ FcConfigPromote (FcValue v, FcValue u)
        v.u.m = &FcIdentityMatrix;
        v.type = FcTypeMatrix;
     }
-    else if (v.type == FcTypeString && u.type == FcTypeLangSet)
+    else if (buf && v.type == FcTypeString && u.type == FcTypeLangSet)
     {
-       v.u.l = FcLangSetPromote (v.u.s);
+       v.u.l = FcLangSetPromote (v.u.s, buf);
        v.type = FcTypeLangSet;
     }
     return v;
@@ -692,9 +692,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) {
@@ -893,10 +894,10 @@ FcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e)
          FcMatrix m;
          FcValue xx, xy, yx, yy;
          v.type = FcTypeMatrix;
-         xx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xx), v);
-         xy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xy), v);
-         yx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yx), v);
-         yy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yy), v);
+         xx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xx), v, NULL);
+         xy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xy), v, NULL);
+         yx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yx), v, NULL);
+         yy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yy), v, NULL);
          if (xx.type == FcTypeDouble && xy.type == FcTypeDouble &&
              yx.type == FcTypeDouble && yy.type == FcTypeDouble)
          {
@@ -987,8 +988,8 @@ FcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e)
     case FcOpDivide:
        vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
        vr = FcConfigEvaluate (p, p_pat, kind, 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 ((int) vl.type) {
index df98eb2..c9f928c 100644 (file)
@@ -35,7 +35,7 @@ FcCharSetCreate (void)
     fcs = (FcCharSet *) malloc (sizeof (FcCharSet));
     if (!fcs)
        return 0;
-    fcs->ref = 1;
+    FcRefInit (&fcs->ref, 1);
     fcs->num = 0;
     fcs->leaves_offset = 0;
     fcs->numbers_offset = 0;
@@ -55,12 +55,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++)
            free (FcCharSetLeaf (fcs, i));
@@ -237,7 +237,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)
@@ -253,7 +253,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)
@@ -329,8 +329,8 @@ FcCharSetCopy (FcCharSet *src)
 {
     if (src)
     {
-       if (src->ref != FC_REF_CONSTANT)
-           src->ref++;
+       if (!FcRefIsConst (&src->ref))
+           FcRefInc (&src->ref);
        else
            FcCacheObjectReference (src);
     }
@@ -488,7 +488,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;
@@ -1204,7 +1204,7 @@ FcCharSetFreezeBase (FcCharSetFreezer *freezer, FcCharSet *fcs)
 
     freezer->charsets_allocated++;
 
-    ent->set.ref = FC_REF_CONSTANT;
+    FcRefSetConst (&ent->set.ref);
     ent->set.num = fcs->num;
     if (fcs->num)
     {
@@ -1338,7 +1338,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)
        {
@@ -1377,7 +1377,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)
@@ -1388,7 +1388,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)
index 8ad1b1e..d977857 100644 (file)
@@ -170,7 +170,7 @@ FcDefaultSubstitute (FcPattern *pattern)
        FcPatternObjectAdd (pattern, FC_FULLNAMELANG_OBJECT, namelang, FcTrue);
        FcPatternObjectAddWithBinding (pattern, FC_FULLNAMELANG_OBJECT, v2, FcValueBindingWeak, FcTrue);
     }
-    FcSharedStrFree (v2.u.s);
+    FcSharedStrFree ((char *) v2.u.s);
 }
 #define __fcdefault__
 #include "fcaliastail.h"
index d881a77..ab4a7e1 100644 (file)
@@ -35,6 +35,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <ctype.h>
+#include <assert.h>
 #include <errno.h>
 #include <unistd.h>
 #include <stddef.h>
@@ -108,6 +109,8 @@ extern pfnSHGetFolderPathA pSHGetFolderPathA;
 #define FcPrivate
 #endif
 
+FC_ASSERT_STATIC (sizeof (FcRef) == sizeof (int));
+
 typedef enum _FcValueBinding {
     FcValueBindingWeak, FcValueBindingStrong, FcValueBindingSame
 } FcValueBinding;
@@ -188,7 +191,7 @@ struct _FcPattern {
     int                    num;
     int                    size;
     intptr_t       elts_offset;
-    int                    ref;
+    FcRef          ref;
 };
 
 #define FcPatternElts(p)       FcOffsetMember(p,elts_offset,FcPatternElt)
@@ -296,7 +299,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;
@@ -309,7 +312,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;
@@ -497,7 +500,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 */
 };
@@ -525,6 +528,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 */
@@ -798,7 +812,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);
@@ -952,7 +966,7 @@ FcPrivate const FcChar8 *
 FcSharedStr (const FcChar8 *name);
 
 FcPrivate FcBool
-FcSharedStrFree (const FcChar8 *name);
+FcSharedStrFree (FcChar8 *name);
 
 FcPrivate FcChar32
 FcStringHash (const FcChar8 *s);
index d1fadf5..8e9b094 100644 (file)
  * 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;
@@ -702,34 +703,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
index ed245c6..6778967 100644 (file)
  */
 
 #include "fcint.h"
-#include <assert.h>
-#include <string.h>
-#include <ctype.h>
-#include <stdio.h>
 
 static double
 FcCompareNumber (FcValue *value1, FcValue *value2)
index dd4487d..b10572c 100644 (file)
@@ -36,6 +36,8 @@
 #include <config.h>
 #endif
 
+#define FC_STMT_START do
+#define FC_STMT_END while (0)
 
 /* mutex */
 
index 9d95266..c3b90d6 100644 (file)
@@ -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)
@@ -37,7 +36,7 @@ FcPatternCreate (void)
     p->num = 0;
     p->size = 0;
     p->elts_offset = FcPtrToOffset (p, NULL);
-    p->ref = 1;
+    FcRefInit (&p->ref, 1);
     return p;
 }
 
@@ -362,13 +361,13 @@ FcPatternDestroy (FcPattern *p)
     if (!p)
        return;
 
-    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);
@@ -546,7 +545,7 @@ FcPatternObjectListAdd (FcPattern   *p,
     FcPatternElt   *e;
     FcValueListPtr l, *prev;
 
-    if (p->ref == FC_REF_CONSTANT)
+    if (FcRefIsConst (&p->ref))
        goto bail0;
 
     /*
@@ -598,7 +597,7 @@ FcPatternObjectAddWithBinding  (FcPattern   *p,
     FcPatternElt   *e;
     FcValueListPtr new, *prev;
 
-    if (p->ref == FC_REF_CONSTANT)
+    if (FcRefIsConst (&p->ref))
        goto bail0;
 
     new = FcValueListCreate ();
@@ -1060,8 +1059,8 @@ bail0:
 void
 FcPatternReference (FcPattern *p)
 {
-    if (p->ref != FC_REF_CONSTANT)
-       p->ref++;
+    if (!FcRefIsConst (&p->ref))
+       FcRefInc (&p->ref);
     else
        FcCacheObjectReference (p);
 }
@@ -1153,7 +1152,7 @@ bail0:
  * significant by any means. */
 
 FcBool
-FcSharedStrFree (const FcChar8 *name)
+FcSharedStrFree (FcChar8 *name)
 {
   free (name);
   return FcTrue;
@@ -1162,7 +1161,7 @@ FcSharedStrFree (const FcChar8 *name)
 const FcChar8 *
 FcSharedStr (const FcChar8 *name)
 {
-  return strdup (name);
+  return strdup ((const char *) name);
 }
 
 FcBool
@@ -1195,7 +1194,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)
index 553588f..e72be5e 100644 (file)
@@ -33,6 +33,8 @@
 #include <windows.h>
 #endif
 
+/* Objects MT-safe for readonly access. */
+
 FcChar8 *
 FcStrCopy (const FcChar8 *s)
 {
@@ -1078,7 +1080,7 @@ FcStrSetCreate (void)
     FcStrSet   *set = malloc (sizeof (FcStrSet));
     if (!set)
        return 0;
-    set->ref = 1;
+    FcRefInit (&set->ref, 1);
     set->num = 0;
     set->size = 0;
     set->strs = 0;
@@ -1230,16 +1232,16 @@ 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)
-           free (set->strs);
-       free (set);
-    }
+    if (FcRefDec (&set->ref) != 1)
+       return;
+
+    for (i = 0; i < set->num; i++)
+       FcStrFree (set->strs[i]);
+    if (set->strs)
+       free (set->strs);
+    free (set);
 }
 
 FcStrList *
@@ -1251,7 +1253,7 @@ FcStrListCreate (FcStrSet *set)
     if (!list)
        return 0;
     list->set = set;
-    set->ref++;
+    FcRefInc (&set->ref);
     list->n = 0;
     return list;
 }