Add thread-safety primitives
authorBehdad Esfahbod <behdad@behdad.org>
Sun, 7 Oct 2012 18:24:28 +0000 (14:24 -0400)
committerBehdad Esfahbod <behdad@behdad.org>
Wed, 2 Jan 2013 06:38:36 +0000 (00:38 -0600)
COPYING
src/Makefile.am
src/fcatomic.h [new file with mode: 0644]
src/fcint.h
src/fcmutex.h [new file with mode: 0644]

diff --git a/COPYING b/COPYING
index 2a5d777..66392b1 100644 (file)
--- a/COPYING
+++ b/COPYING
@@ -5,6 +5,7 @@ Copyright © 2005 Patrick Lam
 Copyright © 2009 Roozbeh Pournader
 Copyright © 2008,2009 Red Hat, Inc.
 Copyright © 2008 Danilo Šegan
 Copyright © 2009 Roozbeh Pournader
 Copyright © 2008,2009 Red Hat, Inc.
 Copyright © 2008 Danilo Šegan
+Copyright © 2012 Google, Inc.
 
 
 Permission to use, copy, modify, distribute, and sell this software and its
 
 
 Permission to use, copy, modify, distribute, and sell this software and its
index b700f5a..da1358c 100644 (file)
@@ -123,6 +123,7 @@ EXTRA_DIST += \
 libfontconfig_la_SOURCES = \
        fcarch.h \
        fcatomic.c \
 libfontconfig_la_SOURCES = \
        fcarch.h \
        fcatomic.c \
+       fcatomic.h \
        fcblanks.c \
        fccache.c \
        fccfg.c \
        fcblanks.c \
        fccache.c \
        fccfg.c \
@@ -138,6 +139,7 @@ libfontconfig_la_SOURCES = \
        fclist.c \
        fcmatch.c \
        fcmatrix.c \
        fclist.c \
        fcmatch.c \
        fcmatrix.c \
+       fcmutex.h \
        fcname.c \
        fcobjs.c \
        fcobjs.h \
        fcname.c \
        fcobjs.c \
        fcobjs.h \
diff --git a/src/fcatomic.h b/src/fcatomic.h
new file mode 100644 (file)
index 0000000..7479a3d
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Mutex operations.  Originally copied from HarfBuzz.
+ *
+ * Copyright © 2007  Chris Wilson
+ * Copyright © 2009,2010  Red Hat, Inc.
+ * Copyright © 2011,2012  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Contributor(s):
+ *     Chris Wilson <chris@chris-wilson.co.uk>
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef _FCATOMIC_H_
+#define _FCATOMIC_H_
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+/* atomic_int */
+
+/* We need external help for these */
+
+#if 0
+
+
+#elif !defined(FC_NO_MT) && defined(_MSC_VER) || defined(__MINGW32__)
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+/* mingw32 does not have MemoryBarrier.
+ * MemoryBarrier may be defined as a macro or a function.
+ * Just make a failsafe version for ourselves. */
+#ifdef MemoryBarrier
+#define HBMemoryBarrier MemoryBarrier
+#else
+static inline void HBMemoryBarrier (void) {
+  long dummy = 0;
+  InterlockedExchange (&dummy, 1);
+}
+#endif
+
+typedef long fc_atomic_int_t;
+#define fc_atomic_int_add(AI, V)       InterlockedExchangeAdd (&(AI), (V))
+
+#define fc_atomic_ptr_get(P)           (HBMemoryBarrier (), (void *) *(P))
+#define fc_atomic_ptr_cmpexch(P,O,N)   (InterlockedCompareExchangePointer ((void **) (P), (void *) (N), (void *) (O)) == (void *) (O))
+
+
+#elif !defined(FC_NO_MT) && defined(__APPLE__)
+
+#include <libkern/OSAtomic.h>
+
+typedef int32_t fc_atomic_int_t;
+#define fc_atomic_int_add(AI, V)       (OSAtomicAdd32Barrier ((V), &(AI)) - (V))
+
+#define fc_atomic_ptr_get(P)           (OSMemoryBarrier (), (void *) *(P))
+#define fc_atomic_ptr_cmpexch(P,O,N)   OSAtomicCompareAndSwapPtrBarrier ((void *) (O), (void *) (N), (void **) (P))
+
+
+#elif !defined(FC_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
+
+typedef int fc_atomic_int_t;
+#define fc_atomic_int_add(AI, V)       __sync_fetch_and_add (&(AI), (V))
+
+#define fc_atomic_ptr_get(P)           (void *) (__sync_synchronize (), *(P))
+#define fc_atomic_ptr_cmpexch(P,O,N)   __sync_bool_compare_and_swap ((P), (O), (N))
+
+
+#elif !defined(FC_NO_MT)
+
+#define FC_ATOMIC_INT_NIL 1 /* Warn that fallback implementation is in use. */
+typedef volatile int fc_atomic_int_t;
+#define fc_atomic_int_add(AI, V)       (((AI) += (V)) - (V))
+
+#define fc_atomic_ptr_get(P)           ((void *) *(P))
+#define fc_atomic_ptr_cmpexch(P,O,N)   (* (void * volatile *) (P) == (void *) (O) ? (* (void * volatile *) (P) = (void *) (N), true) : false)
+
+
+#else /* FC_NO_MT */
+
+typedef int fc_atomic_int_t;
+#define fc_atomic_int_add(AI, V)       (((AI) += (V)) - (V))
+
+#define fc_atomic_ptr_get(P)           ((void *) *(P))
+#define fc_atomic_ptr_cmpexch(P,O,N)   (* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false)
+
+#endif
+
+/* reference count */
+#define FC_REF_CONSTANT ((fc_atomic_int_t) -1)
+#define FC_REF_CONSTANT_INIT {FC_REF_CONSTANT}
+typedef struct _FcRef { fc_atomic_int_t count; } FcRef;
+static inline void   FcRefInit    (FcRef *r, int v) { r->count = v; }
+static inline int    FcRefInc     (FcRef *r) { return fc_atomic_int_add (r->count, +1); }
+static inline int    FcRefDec     (FcRef *r) { return fc_atomic_int_add (r->count, -1); }
+static inline void   FcRefFinish  (FcRef *r) { r->count = FC_REF_CONSTANT; }
+static inline FcBool FcRefIsConst (FcRef *r) { return r->count == FC_REF_CONSTANT; }
+
+#endif /* _FCATOMIC_H_ */
index a6d7e8a..d881a77 100644 (file)
@@ -44,6 +44,8 @@
 #include <fontconfig/fontconfig.h>
 #include <fontconfig/fcprivate.h>
 #include "fcdeprecate.h"
 #include <fontconfig/fontconfig.h>
 #include <fontconfig/fcprivate.h>
 #include "fcdeprecate.h"
+#include "fcmutex.h"
+#include "fcatomic.h"
 
 #ifndef FC_CONFIG_PATH
 #define FC_CONFIG_PATH "fonts.conf"
 
 #ifndef FC_CONFIG_PATH
 #define FC_CONFIG_PATH "fonts.conf"
@@ -293,8 +295,6 @@ typedef struct _FcCharLeaf {
     FcChar32   map[256/32];
 } FcCharLeaf;
 
     FcChar32   map[256/32];
 } FcCharLeaf;
 
-#define FC_REF_CONSTANT            -1
-
 struct _FcCharSet {
     int                    ref;        /* reference count */
     int                    num;        /* size of leaves and numbers arrays */
 struct _FcCharSet {
     int                    ref;        /* reference count */
     int                    num;        /* size of leaves and numbers arrays */
diff --git a/src/fcmutex.h b/src/fcmutex.h
new file mode 100644 (file)
index 0000000..dd4487d
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Atomic int and pointer operations.  Originally copied from HarfBuzz.
+ *
+ * Copyright © 2007  Chris Wilson
+ * Copyright © 2009,2010  Red Hat, Inc.
+ * Copyright © 2011,2012  Google, Inc.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Contributor(s):
+ *     Chris Wilson <chris@chris-wilson.co.uk>
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef _FCMUTEX_H_
+#define _FCMUTEX_H_
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+/* mutex */
+
+/* We need external help for these */
+
+#if 0
+
+
+#elif !defined(FC_NO_MT) && defined(_MSC_VER) || defined(__MINGW32__)
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+typedef CRITICAL_SECTION fc_mutex_impl_t;
+#define FC_MUTEX_IMPL_INIT     { NULL, 0, 0, NULL, NULL, 0 }
+#define fc_mutex_impl_init(M)  InitializeCriticalSection (M)
+#define fc_mutex_impl_lock(M)  EnterCriticalSection (M)
+#define fc_mutex_impl_unlock(M)        LeaveCriticalSection (M)
+#define fc_mutex_impl_finish(M)        DeleteCriticalSection (M)
+
+
+#elif !defined(FC_NO_MT) && (defined(HAVE_PTHREAD) || defined(__APPLE__))
+
+#include <pthread.h>
+typedef pthread_mutex_t fc_mutex_impl_t;
+#define FC_MUTEX_IMPL_INIT     PTHREAD_MUTEX_INITIALIZER
+#define fc_mutex_impl_init(M)  pthread_mutex_init (M, NULL)
+#define fc_mutex_impl_lock(M)  pthread_mutex_lock (M)
+#define fc_mutex_impl_unlock(M)        pthread_mutex_unlock (M)
+#define fc_mutex_impl_finish(M)        pthread_mutex_destroy (M)
+
+
+#elif !defined(FC_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
+
+#if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD)
+# include <sched.h>
+# define FC_SCHED_YIELD() sched_yield ()
+#else
+# define FC_SCHED_YIELD() FC_STMT_START {} FC_STMT_END
+#endif
+
+/* This actually is not a totally awful implementation. */
+typedef volatile int fc_mutex_impl_t;
+#define FC_MUTEX_IMPL_INIT     0
+#define fc_mutex_impl_init(M)  *(M) = 0
+#define fc_mutex_impl_lock(M)  FC_STMT_START { while (__sync_lock_test_and_set((M), 1)) FC_SCHED_YIELD (); } FC_STMT_END
+#define fc_mutex_impl_unlock(M)        __sync_lock_release (M)
+#define fc_mutex_impl_finish(M)        FC_STMT_START {} FC_STMT_END
+
+
+#elif !defined(FC_NO_MT)
+
+#if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD)
+# include <sched.h>
+# define FC_SCHED_YIELD() sched_yield ()
+#else
+# define FC_SCHED_YIELD() FC_STMT_START {} FC_STMT_END
+#endif
+
+#define FC_MUTEX_INT_NIL 1 /* Warn that fallback implementation is in use. */
+typedef volatile int fc_mutex_impl_t;
+#define FC_MUTEX_IMPL_INIT     0
+#define fc_mutex_impl_init(M)  *(M) = 0
+#define fc_mutex_impl_lock(M)  FC_STMT_START { while (*(M)) FC_SCHED_YIELD (); (*(M))++; } FC_STMT_END
+#define fc_mutex_impl_unlock(M)        (*(M))--;
+#define fc_mutex_impl_finish(M)        FC_STMT_START {} FC_STMT_END
+
+
+#else /* FC_NO_MT */
+
+typedef int fc_mutex_impl_t;
+#define FC_MUTEX_IMPL_INIT     0
+#define fc_mutex_impl_init(M)  FC_STMT_START {} FC_STMT_END
+#define fc_mutex_impl_lock(M)  FC_STMT_START {} FC_STMT_END
+#define fc_mutex_impl_unlock(M)        FC_STMT_START {} FC_STMT_END
+#define fc_mutex_impl_finish(M)        FC_STMT_START {} FC_STMT_END
+
+#endif
+
+
+#define FC_MUTEX_INIT          {FC_MUTEX_IMPL_INIT}
+typedef fc_mutex_impl_t FcMutex;
+static inline void FcMutexInit   (FcMutex *m) { fc_mutex_impl_init (m);   }
+static inline void FcMutexLock   (FcMutex *m) { fc_mutex_impl_lock (m);   }
+static inline void FcMutexUnlock (FcMutex *m) { fc_mutex_impl_unlock (m); }
+static inline void FcMutexFinish (FcMutex *m) { fc_mutex_impl_finish (m); }
+
+
+#endif /* _FCMUTEX_H_ */