From 64af9e1917114c789ad74dd28b3248f8c0525f45 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sun, 7 Oct 2012 14:41:38 -0400 Subject: [PATCH] Make refcounts, patterns, charsets, strings, and FcLang thread-safe --- src/fcatomic.h | 18 +++++++++--------- src/fccfg.c | 29 +++++++++++++++-------------- src/fccharset.c | 24 ++++++++++++------------ src/fcdefault.c | 2 +- src/fcint.h | 26 ++++++++++++++++++++------ src/fclang.c | 41 +++++++++++++++++++++++------------------ src/fcmatch.c | 4 ---- src/fcmutex.h | 2 ++ src/fcpat.c | 25 ++++++++++++------------- src/fcstr.c | 24 +++++++++++++----------- 10 files changed, 107 insertions(+), 88 deletions(-) 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 -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 ef5f4ff..dd34f5a 100644 --- a/src/fccfg.c +++ b/src/fccfg.c @@ -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) { diff --git a/src/fccharset.c b/src/fccharset.c index df98eb2..c9f928c 100644 --- a/src/fccharset.c +++ b/src/fccharset.c @@ -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) diff --git a/src/fcdefault.c b/src/fcdefault.c index 8ad1b1e..d977857 100644 --- a/src/fcdefault.c +++ b/src/fcdefault.c @@ -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" diff --git a/src/fcint.h b/src/fcint.h index d881a77..ab4a7e1 100644 --- a/src/fcint.h +++ b/src/fcint.h @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -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); diff --git a/src/fclang.c b/src/fclang.c index d1fadf5..8e9b094 100644 --- a/src/fclang.c +++ b/src/fclang.c @@ -22,10 +22,11 @@ * PERFORMANCE OF THIS SOFTWARE. */ -#include #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; + int id; + typedef struct { + FcLangSet ls; + FcStrSet strs; + FcChar8 *str; + } FcLangSetPromotionBuffer; + FcLangSetPromotionBuffer *buf = (FcLangSetPromotionBuffer *) vbuf; - memset (ls.map, '\0', sizeof (ls.map)); - ls.map_size = NUM_LANG_SET_MAP; - ls.extra = 0; + 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 ed245c6..6778967 100644 --- a/src/fcmatch.c +++ b/src/fcmatch.c @@ -23,10 +23,6 @@ */ #include "fcint.h" -#include -#include -#include -#include static double FcCompareNumber (FcValue *value1, FcValue *value2) diff --git a/src/fcmutex.h b/src/fcmutex.h index dd4487d..b10572c 100644 --- a/src/fcmutex.h +++ b/src/fcmutex.h @@ -36,6 +36,8 @@ #include #endif +#define FC_STMT_START do +#define FC_STMT_END while (0) /* mutex */ diff --git a/src/fcpat.c b/src/fcpat.c index 9d95266..c3b90d6 100644 --- a/src/fcpat.c +++ b/src/fcpat.c @@ -22,9 +22,8 @@ #include "fcint.h" #include "fcftint.h" -#include -#include -#include + +/* 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) diff --git a/src/fcstr.c b/src/fcstr.c index 553588f..e72be5e 100644 --- a/src/fcstr.c +++ b/src/fcstr.c @@ -33,6 +33,8 @@ #include #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; }