Make cache hash threadsafe
authorBehdad Esfahbod <behdad@behdad.org>
Wed, 10 Oct 2012 19:24:31 +0000 (15:24 -0400)
committerBehdad Esfahbod <behdad@behdad.org>
Wed, 2 Jan 2013 07:04:47 +0000 (01:04 -0600)
This concludes my first pass at making fontconfig threadsafe.  Now to
testing and actually fixing it!

src/fccache.c

index 751cea1..77bf841 100644 (file)
@@ -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);