diff --git a/src/fcinit.c b/src/fcinit.c index db62c21..8375e94 100644 --- a/src/fcinit.c +++ b/src/fcinit.c @@ -180,6 +180,8 @@ FcFini (void) FcConfigFini (); FcCacheFini (); FcDefaultFini (); + FcObjectOtherTypeFini (); + FcIncludeFini (); } /* diff --git a/src/fcint.h b/src/fcint.h index 45dfc6e..cba9dbe 100644 --- a/src/fcint.h +++ b/src/fcint.h @@ -880,6 +880,7 @@ FcPrivate FcConfig * FcInitLoadOwnConfigAndFonts (FcConfig *config); /* fcxml.c */ +void FcIncludeFini(void); FcPrivate void FcTestDestroy (FcTest *test); @@ -1192,6 +1193,7 @@ FcStrSerialize (FcSerialize *serialize, const FcChar8 *str); /* fcobjs.c */ +void FcObjectOtherTypeFini(void); FcPrivate FcObject FcObjectLookupIdByName (const char *str); diff --git a/src/fcobjs.c b/src/fcobjs.c index bad9824..c4e737e 100644 --- a/src/fcobjs.c +++ b/src/fcobjs.c @@ -37,6 +37,7 @@ FcObjectTypeLookup (register const char *str, register unsigned int len); /* The 1000 is to leave some room for future added internal objects, such * that caches from newer fontconfig can still be used with older fontconfig * without getting confused. */ +/* Protected by other_lock below */ static fc_atomic_int_t next_id = FC_MAX_BASE_OBJECT + FC_EXT_OBJ_INDEX; struct FcObjectOtherTypeInfo { struct FcObjectOtherTypeInfo *next; @@ -44,11 +45,85 @@ struct FcObjectOtherTypeInfo { FcObject id; } *other_types; +static FcMutex *other_lock = NULL; + +static void +lock_other (void) +{ + FcMutex *lock; +retry: + lock = fc_atomic_ptr_get (&other_lock); + if (!lock) { + lock = (FcMutex *) malloc (sizeof (FcMutex)); + FcMutexInit (lock); + if (!fc_atomic_ptr_cmpexch (&other_lock, NULL, lock)) { + FcMutexFinish (lock); + goto retry; + } + + FcMutexLock (lock); + /* Initialize random state */ + FcRandom (); + return; + } + FcMutexLock (lock); +} + +static void +unlock_other (void) +{ + FcMutexUnlock (other_lock); +} + +static void +freelock_other (void) +{ + FcMutex *lock; + lock = fc_atomic_ptr_get (&other_lock); + if (lock && fc_atomic_ptr_cmpexch (&other_lock, lock, NULL)) { + FcMutexFinish (lock); + free (lock); + } +} + +void FcObjectOtherTypeFini(void) /* MT-safe */ +{ + struct FcObjectOtherTypeInfo *ots, *ot; + + lock_other (); + + ots = fc_atomic_ptr_get (&other_types); + if (ots && fc_atomic_ptr_cmpexch (&other_types, ots, NULL)) { + ot = ots->next; + while(ot){ + ots->next = ot->next; + if (ot->object.object) { + free(ot->object.object); + } + free (ot); + fc_atomic_int_add (next_id, -1); + ot = ots->next; + } + if (ots->object.object) { + free(ots->object.object); + } + free (ots); + ots = NULL; + fc_atomic_int_add (next_id, -1); + } + + unlock_other (); + + freelock_other (); +} + static FcObjectType * -_FcObjectLookupOtherTypeByName (const char *str, FcObject *id) +_FcObjectLookupOtherTypeByName (const char *str, FcObject *id) /* MT-safe */ { struct FcObjectOtherTypeInfo *ots, *ot; + lock_other (); + retry: ots = fc_atomic_ptr_get (&other_types); @@ -59,16 +134,27 @@ retry: if (!ot) { ot = malloc (sizeof (*ot)); - if (!ot) - return NULL; + if (!ot) { + unlock_other(); + return NULL; + } ot->object.object = (const char *) FcStrdup (str); + if (!ot->object.object) { + free(ot); + unlock_other(); + return NULL; + } ot->object.type = FcTypeUnknown; ot->id = fc_atomic_int_add (next_id, +1); ot->next = ots; if (!fc_atomic_ptr_cmpexch (&other_types, ots, ot)) { + if (ot->object.object) { + FcStrFree (ot->object.object); + } free (ot); + fc_atomic_int_add (next_id, -1); goto retry; } } @@ -76,6 +162,8 @@ retry: if (id) *id = ot->id; + unlock_other(); + return &ot->object; } diff --git a/src/fcxml.c b/src/fcxml.c index 29dd4d6..9d8c792 100644 --- a/src/fcxml.c +++ b/src/fcxml.c @@ -2243,6 +2243,55 @@ FcParseCacheDir (FcConfigParse *parse) FcStrFree (data); } +static FcChar8 *single_userdir = NULL; + +static FcChar8 * +FcGetSingleUserdir (FcChar8 *s) +{ + FcChar8 *userdir = NULL; +retry: + userdir = fc_atomic_ptr_get (&single_userdir); + if (!userdir){ + userdir = FcStrdup(s); + if (!fc_atomic_ptr_cmpexch (&single_userdir, NULL, userdir)) { + FcFree(userdir); + goto retry; + } + } + return userdir; +} + +static FcChar8 *single_userconf = NULL; + +static FcChar8 * +FcGetSingleUserconf (FcChar8 *s) +{ + FcChar8 *userconf = NULL; +retry: + userconf = fc_atomic_ptr_get (&single_userconf); + if(!userconf){ + userconf = FcStrdup(s); + if (!fc_atomic_ptr_cmpexch (&single_userconf, NULL, userconf)) { + FcStrFree(userconf); + goto retry; + } + } + return userconf; +} + +void FcIncludeFini(void) +{ + FcChar8 *userdir, *userconf; + userdir = fc_atomic_ptr_get (&single_userdir); + if (userdir && fc_atomic_ptr_cmpexch (&single_userdir, userdir, NULL)) { + FcFree(userdir); + } + userconf = fc_atomic_ptr_get (&single_userconf); + if (userconf && fc_atomic_ptr_cmpexch (&single_userconf, userconf, NULL)){ + FcFree(userconf); + } +} + static void FcParseInclude (FcConfigParse *parse) { @@ -2251,8 +2300,8 @@ FcParseInclude (FcConfigParse *parse) FcBool ignore_missing = FcFalse; FcBool deprecated = FcFalse; FcChar8 *prefix = NULL, *p; - static FcChar8 *userdir = NULL; - static FcChar8 *userconf = NULL; + FcChar8 *userdir = NULL; + FcChar8 *userconf = NULL; s = FcStrBufDoneStatic (&parse->pstack->str); if (!s) @@ -2295,14 +2344,16 @@ FcParseInclude (FcConfigParse *parse) if (FcFileIsDir (s)) { userdir: - if (!userdir) - userdir = FcStrdup (s); + if(!userdir){ + userdir = FcGetSingleUserdir(s); + } } else if (FcFileIsFile (s)) { userconf: - if (!userconf) - userconf = FcStrdup (s); + if(!userconf){ + userconf = FcGetSingleUserconf(s); + } } else {