Make cache hash threadsafe

This concludes my first pass at making fontconfig threadsafe.  Now to
testing and actually fixing it!
This commit is contained in:
Behdad Esfahbod 2012-10-10 15:24:31 -04:00
parent adb03b730d
commit 68b8ae9af8
1 changed files with 30 additions and 7 deletions

View File

@ -248,6 +248,7 @@ struct _FcCacheSkip {
#define FC_CACHE_MAX_LEVEL 16 #define FC_CACHE_MAX_LEVEL 16
/* Protected by cache_lock below */
static FcCacheSkip *fcCacheChains[FC_CACHE_MAX_LEVEL]; static FcCacheSkip *fcCacheChains[FC_CACHE_MAX_LEVEL];
static int fcCacheMaxLevel; static int fcCacheMaxLevel;
@ -383,6 +384,8 @@ FcCacheInsert (FcCache *cache, struct stat *cache_stat)
FcCacheSkip *s, **next; FcCacheSkip *s, **next;
int i, level; int i, level;
lock_cache ();
/* /*
* Find links along each chain * Find links along each chain
*/ */
@ -434,11 +437,13 @@ FcCacheInsert (FcCache *cache, struct stat *cache_stat)
s->next[i] = *update[i]; s->next[i] = *update[i];
*update[i] = s; *update[i] = s;
} }
unlock_cache ();
return FcTrue; return FcTrue;
} }
static FcCacheSkip * static FcCacheSkip *
FcCacheFindByAddr (void *object) FcCacheFindByAddrUnlocked (void *object)
{ {
int i; int i;
FcCacheSkip **next = fcCacheChains; FcCacheSkip **next = fcCacheChains;
@ -459,6 +464,16 @@ FcCacheFindByAddr (void *object)
return NULL; return NULL;
} }
static FcCacheSkip *
FcCacheFindByAddr (void *object)
{
FcCacheSkip *ret;
lock_cache ();
ret = FcCacheFindByAddrUnlocked (object);
unlock_cache ();
return ret;
}
static void static void
FcCacheRemove (FcCache *cache) FcCacheRemove (FcCache *cache)
{ {
@ -469,6 +484,7 @@ FcCacheRemove (FcCache *cache)
/* /*
* Find links along each chain * Find links along each chain
*/ */
lock_cache ();
next = fcCacheChains; next = fcCacheChains;
for (i = fcCacheMaxLevel; --i >= 0; ) for (i = fcCacheMaxLevel; --i >= 0; )
{ {
@ -482,6 +498,7 @@ FcCacheRemove (FcCache *cache)
*update[i] = s->next[i]; *update[i] = s->next[i];
while (fcCacheMaxLevel > 0 && fcCacheChains[fcCacheMaxLevel - 1] == NULL) while (fcCacheMaxLevel > 0 && fcCacheChains[fcCacheMaxLevel - 1] == NULL)
fcCacheMaxLevel--; fcCacheMaxLevel--;
unlock_cache ();
free (s); free (s);
} }
@ -490,14 +507,17 @@ FcCacheFindByStat (struct stat *cache_stat)
{ {
FcCacheSkip *s; FcCacheSkip *s;
lock_cache ();
for (s = fcCacheChains[0]; s; s = s->next[0]) for (s = fcCacheChains[0]; s; s = s->next[0])
if (s->cache_dev == cache_stat->st_dev && if (s->cache_dev == cache_stat->st_dev &&
s->cache_ino == cache_stat->st_ino && s->cache_ino == cache_stat->st_ino &&
s->cache_mtime == cache_stat->st_mtime) s->cache_mtime == cache_stat->st_mtime)
{ {
FcRefInc (&s->ref); FcRefInc (&s->ref);
unlock_cache ();
return s->cache; return s->cache;
} }
unlock_cache ();
return NULL; 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 * 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. * such that we reload it, using mmap, which is shared across processes.
*/ */
if (cache->size < FC_CACHE_MIN_MMAP && if (cache->size < FC_CACHE_MIN_MMAP && FcStat (cache_hashed, &cache_stat))
(skip = FcCacheFindByAddr (cache)) &&
FcStat (cache_hashed, &cache_stat))
{ {
skip->cache_dev = cache_stat.st_dev; lock_cache ();
skip->cache_ino = cache_stat.st_ino; if ((skip = FcCacheFindByAddrUnlocked (cache)))
skip->cache_mtime = cache_stat.st_mtime; {
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); FcStrFree (cache_hashed);