From 68b8ae9af8b0f86dade6135b01aaf0b2f2077fb5 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 10 Oct 2012 15:24:31 -0400 Subject: [PATCH] Make cache hash threadsafe This concludes my first pass at making fontconfig threadsafe. Now to testing and actually fixing it! --- src/fccache.c | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/src/fccache.c b/src/fccache.c index 751cea1..77bf841 100644 --- a/src/fccache.c +++ b/src/fccache.c @@ -248,6 +248,7 @@ struct _FcCacheSkip { #define FC_CACHE_MAX_LEVEL 16 +/* Protected by cache_lock below */ static FcCacheSkip *fcCacheChains[FC_CACHE_MAX_LEVEL]; static int fcCacheMaxLevel; @@ -383,6 +384,8 @@ FcCacheInsert (FcCache *cache, struct stat *cache_stat) FcCacheSkip *s, **next; int i, level; + lock_cache (); + /* * Find links along each chain */ @@ -434,11 +437,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; @@ -459,6 +464,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) { @@ -469,6 +484,7 @@ FcCacheRemove (FcCache *cache) /* * Find links along each chain */ + lock_cache (); next = fcCacheChains; for (i = fcCacheMaxLevel; --i >= 0; ) { @@ -482,6 +498,7 @@ FcCacheRemove (FcCache *cache) *update[i] = s->next[i]; while (fcCacheMaxLevel > 0 && fcCacheChains[fcCacheMaxLevel - 1] == NULL) fcCacheMaxLevel--; + unlock_cache (); free (s); } @@ -490,14 +507,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; } @@ -987,13 +1007,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);