[Fontconfig] fontconfig: Branch 'wip/threadsafe' - 4 commits

Behdad Esfahbod behdad at kemper.freedesktop.org
Wed Oct 10 12:28:41 PDT 2012


 src/fccache.c |   83 +++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 src/fccfg.c   |    2 -
 2 files changed, 77 insertions(+), 8 deletions(-)

New commits:
commit 887bbf9984a26077105d280e8134bde9b97b34ee
Author: Behdad Esfahbod <behdad at behdad.org>
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 at behdad.org>
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 at behdad.org>
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 at behdad.org>
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


More information about the Fontconfig mailing list