Akira, After some (very light) testing, I think this branch is ready to be merged. behdad -------- Original Message -------- Subject: fontconfig: Branch 'wip/threadsafe' - 4 commits Date: Wed, 10 Oct 2012 12:28:41 -0700 (PDT) From: behdad@xxxxxxxxxxxxxxxxxxxxxx (Behdad Esfahbod) To: fontconfig@xxxxxxxxxxxxxx src/fccache.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- src/fccfg.c | 2 - 2 files changed, 77 insertions(+), 8 deletions(-) New commits: commit 887bbf9984a26077105d280e8134bde9b97b34ee Author: Behdad Esfahbod <behdad@xxxxxxxxxx> Date: Wed Oct 10 15:24:31 2012 -0400 Make cache hash threadsafe This concludes my first pass at making fontconfig threadsafe. Now to testing and actually fixing it! diff --git a/src/fccache.c b/src/fccache.c index 350c927..611c0de 100644 --- a/src/fccache.c +++ b/src/fccache.c @@ -246,6 +246,7 @@ struct _FcCacheSkip { #define FC_CACHE_MAX_LEVEL 16 +/* Protected by cache_lock below */ static FcCacheSkip *fcCacheChains[FC_CACHE_MAX_LEVEL]; static int fcCacheMaxLevel; @@ -381,6 +382,8 @@ FcCacheInsert (FcCache *cache, struct stat *cache_stat) FcCacheSkip *s, **next; int i, level; + lock_cache (); + /* * Find links along each chain */ @@ -432,11 +435,13 @@ FcCacheInsert (FcCache *cache, struct stat *cache_stat) s->next[i] = *update[i]; *update[i] = s; } + + unlock_cache (); return FcTrue; } static FcCacheSkip * -FcCacheFindByAddr (void *object) +FcCacheFindByAddrUnlocked (void *object) { int i; FcCacheSkip **next = fcCacheChains; @@ -457,6 +462,16 @@ FcCacheFindByAddr (void *object) return NULL; } +static FcCacheSkip * +FcCacheFindByAddr (void *object) +{ + FcCacheSkip *ret; + lock_cache (); + ret = FcCacheFindByAddrUnlocked (object); + unlock_cache (); + return ret; +} + static void FcCacheRemove (FcCache *cache) { @@ -467,6 +482,7 @@ FcCacheRemove (FcCache *cache) /* * Find links along each chain */ + lock_cache (); next = fcCacheChains; for (i = fcCacheMaxLevel; --i >= 0; ) { @@ -480,6 +496,7 @@ FcCacheRemove (FcCache *cache) *update[i] = s->next[i]; while (fcCacheMaxLevel > 0 && fcCacheChains[fcCacheMaxLevel - 1] == NULL) fcCacheMaxLevel--; + unlock_cache (); free (s); } @@ -488,14 +505,17 @@ FcCacheFindByStat (struct stat *cache_stat) { FcCacheSkip *s; + lock_cache (); for (s = fcCacheChains[0]; s; s = s->next[0]) if (s->cache_dev == cache_stat->st_dev && s->cache_ino == cache_stat->st_ino && s->cache_mtime == cache_stat->st_mtime) { FcRefInc (&s->ref); + unlock_cache (); return s->cache; } + unlock_cache (); return NULL; } @@ -985,13 +1005,16 @@ FcDirCacheWrite (FcCache *cache, FcConfig *config) * new cache file is not read again. If it's large, we don't do that * such that we reload it, using mmap, which is shared across processes. */ - if (cache->size < FC_CACHE_MIN_MMAP && - (skip = FcCacheFindByAddr (cache)) && - FcStat (cache_hashed, &cache_stat)) + if (cache->size < FC_CACHE_MIN_MMAP && FcStat (cache_hashed, &cache_stat)) { - skip->cache_dev = cache_stat.st_dev; - skip->cache_ino = cache_stat.st_ino; - skip->cache_mtime = cache_stat.st_mtime; + lock_cache (); + if (skip = FcCacheFindByAddrUnlocked (cache)) + { + skip->cache_dev = cache_stat.st_dev; + skip->cache_ino = cache_stat.st_ino; + skip->cache_mtime = cache_stat.st_mtime; + } + unlock_cache (); } FcStrFree (cache_hashed); commit 7ddb50f0af17d8cb46893640c3f3e62717eae5e5 Author: Behdad Esfahbod <behdad@xxxxxxxxxx> Date: Mon Oct 8 20:03:35 2012 -0400 Make random-state initialization threadsafe diff --git a/src/fccache.c b/src/fccache.c index 9121819..350c927 100644 --- a/src/fccache.c +++ b/src/fccache.c @@ -321,6 +321,11 @@ retry: FcMutexFinish (lock); goto retry; } + + FcMutexLock (lock); + /* Initialize random state */ + FcRandom (); + return; } FcMutexLock (lock); } commit 8a975a9d1bc9f02baab0640c4f4f45509b3c9bcc Author: Behdad Esfahbod <behdad@xxxxxxxxxx> Date: Mon Oct 8 20:02:05 2012 -0400 Add a big cache lock Not used yet. diff --git a/src/fccache.c b/src/fccache.c index 91d290a..9121819 100644 --- a/src/fccache.c +++ b/src/fccache.c @@ -305,6 +305,45 @@ FcRandom(void) return result; } + +static FcMutex *cache_lock; + +static void +lock_cache (void) +{ + FcMutex *lock; +retry: + lock = fc_atomic_ptr_get (&cache_lock); + if (!lock) { + lock = (FcMutex *) malloc (sizeof (FcMutex)); + FcMutexInit (lock); + if (!fc_atomic_ptr_cmpexch (&cache_lock, NULL, lock)) { + FcMutexFinish (lock); + goto retry; + } + } + FcMutexLock (lock); +} + +static void +unlock_cache (void) +{ + FcMutexUnlock (cache_lock); +} + +static void +free_lock (void) +{ + FcMutex *lock; + lock = fc_atomic_ptr_get (&cache_lock); + if (lock && fc_atomic_ptr_cmpexch (&cache_lock, lock, NULL)) { + FcMutexFinish (lock); + free (lock); + } +} + + + /* * Generate a random level number, distributed * so that each level is 1/4 as likely as the one before @@ -502,6 +541,8 @@ FcCacheFini (void) for (i = 0; i < FC_CACHE_MAX_LEVEL; i++) assert (fcCacheChains[i] == NULL); assert (fcCacheMaxLevel == 0); + + free_lock (); } static FcBool commit bf2c62506558fb9b858770445fff5319b2755734 Author: Behdad Esfahbod <behdad@xxxxxxxxxx> Date: Mon Oct 8 17:59:38 2012 -0400 Fix FcConfigInit() Ouch! diff --git a/src/fccfg.c b/src/fccfg.c index 4fc6f36..a387cc7 100644 --- a/src/fccfg.c +++ b/src/fccfg.c @@ -63,7 +63,7 @@ retry: FcBool FcConfigInit (void) { - return FcConfigEnsure ? FcTrue : FcFalse; + return FcConfigEnsure () ? FcTrue : FcFalse; } void _______________________________________________ Fontconfig mailing list Fontconfig@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/fontconfig _______________________________________________ Fontconfig mailing list Fontconfig@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/fontconfig