[Pixman] [PATCH 2/2] Add PIXMAN_DEFINE_THREAD_LOCAL() and PIXMAN_GET_THREAD_LOCAL() macros

Søren Sandmann sandmann at daimi.au.dk
Tue Mar 16 09:52:16 PDT 2010


From: Søren Sandmann Pedersen <ssp at redhat.com>

These macros hide the various types of thread local support. On Linux
and Unix, they expand to just __thread. On Microsoft Visual C++, they
expand to __declspec(thread).

On OS X and other systems that don't have __thread, they expand to a
complicated concoction that uses pthread_once() and
pthread_get/set_specific() to get thread local variables.
---
 configure.ac             |    2 +-
 pixman/pixman-compiler.h |   63 +++++++++++++++++++++++++++++++++++++++++----
 pixman/pixman.c          |   37 ++++++++++++++++-----------
 3 files changed, 80 insertions(+), 22 deletions(-)

diff --git a/configure.ac b/configure.ac
index 0bf5658..d790bf3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -532,7 +532,7 @@ AC_MSG_CHECKING(for __thread)
 AC_COMPILE_IFELSE([
 __thread int x ;
 int main () { return 0; }
-], support_for__thread=yes)
+], support_for__thread=no)
 
 if test $support_for__thread = yes; then 
    AC_DEFINE([TOOLCHAIN_SUPPORTS__THREAD],[],[Whether the tool chain supports __thread])
diff --git a/pixman/pixman-compiler.h b/pixman/pixman-compiler.h
index 5aeef86..a4e3f88 100644
--- a/pixman/pixman-compiler.h
+++ b/pixman/pixman-compiler.h
@@ -70,11 +70,62 @@
 #endif
 
 /* TLS */
-#if (defined (__GNUC__) && ((__GNUC__ == 3 && __GNUC_MINOR >= 3) || __GNUC__ > 3)) || defined(__SUNPRO_C)
-#    define THREAD_LOCAL __thread
-#elif defined (_MSC_VER)
-#    define THREAD_LOCAL __declspec(thread)
+#if defined(TOOLCHAIN_SUPPORTS__THREAD)
+
+#   define PIXMAN_DEFINE_THREAD_LOCAL(type, name)			\
+    static __thread type name
+#   define PIXMAN_GET_THREAD_LOCAL(name)				\
+    (&name)
+
+#elif defined(_MSC_VER)
+
+#   define PIXMAN_DEFINE_THREAD_LOCAL(type, name)			\
+    static __declspec(thread) type name
+#   define PIXMAN_GET_THREAD_LOCAL(name)				\
+    (&name)
+
+#elif defined(HAVE_PTHREAD_SETSPECIFIC)
+
+#include <pthread.h>
+
+#  define PIXMAN_DEFINE_THREAD_LOCAL(type, name)			\
+    static pthread_once_t tls_ ## name ## _once_control = PTHREAD_ONCE_INIT; \
+    static pthread_key_t tls_ ## name ## _key;				\
+									\
+    static void								\
+    tls_ ## name ## _make_key (void)					\
+    {									\
+	pthread_key_create (&tls_ ## name ## _key, NULL);		\
+    }									\
+									\
+    static type *							\
+    tls_ ## name ## _alloc (key)					\
+    {									\
+	type *value = malloc (sizeof (type));				\
+	if (value)							\
+	    pthread_setspecific (key, value);				\
+	return value;							\
+    }									\
+									\
+    static force_inline type *						\
+    tls_ ## name ## _get (key)						\
+    {									\
+	type *value = NULL;						\
+	if (pthread_once (&tls_ ## name ## _once_control,		\
+			  tls_ ## name ## _make_key) == 0)		\
+	{								\
+	    value = pthread_getspecific (tls_ ## name ## _key);		\
+	    if (!value)							\
+		value = tls_ ## name ## _alloc (key);			\
+	}								\
+	return value;							\
+    }
+
+#   define PIXMAN_GET_THREAD_LOCAL(name)				\
+    tls_ ## name ## _get (tls_ ## name ## _key)
+
 #else
-#    warning "unknown compiler"
-#    define THREAD_LOCAL __thread
+
+#    error "Unknown thread local support for this system"
+
 #endif
diff --git a/pixman/pixman.c b/pixman/pixman.c
index c71617e..68483a0 100644
--- a/pixman/pixman.c
+++ b/pixman/pixman.c
@@ -499,6 +499,15 @@ image_covers (pixman_image_t *image,
     return TRUE;
 }
 
+#define N_CACHED_FAST_PATHS 8
+
+typedef struct
+{
+    pixman_fast_path_t cache [N_CACHED_FAST_PATHS];
+} cache_t;
+
+PIXMAN_DEFINE_THREAD_LOCAL (cache_t, fast_path_cache);
+
 static void
 do_composite (pixman_implementation_t *imp,
 	      pixman_op_t	       op,
@@ -514,8 +523,6 @@ do_composite (pixman_implementation_t *imp,
 	      int		       width,
 	      int		       height)
 {
-#define N_CACHED_FAST_PATHS 8
-    static THREAD_LOCAL pixman_fast_path_t tls_cache[N_CACHED_FAST_PATHS];
     pixman_format_code_t src_format, mask_format, dest_format;
     uint32_t src_flags, mask_flags, dest_flags;
     pixman_region32_t region;
@@ -527,8 +534,8 @@ do_composite (pixman_implementation_t *imp,
     uint32_t *dest_bits;
     int dest_dx, dest_dy;
     pixman_bool_t need_workaround;
-    pixman_fast_path_t *cache;
     const pixman_fast_path_t *info;
+    cache_t *cache;
     int i;
 
     src_format = src->common.extended_format_code;
@@ -597,11 +604,11 @@ do_composite (pixman_implementation_t *imp,
 	return;
 
     /* Check cache for fast paths */
-    cache = tls_cache;
+    cache = PIXMAN_GET_THREAD_LOCAL (fast_path_cache);
 
     for (i = 0; i < N_CACHED_FAST_PATHS; ++i)
     {
-	info = &(cache[i]);
+	info = &(cache->cache[i]);
 
 	/* Note that we check for equality here, not whether
 	 * the cached fast path matches. This is to prevent
@@ -677,16 +684,16 @@ found:
 	pixman_composite_func_t func = info->func;
 	
 	while (i--)
-	    cache[i + 1] = cache[i];
-
-	cache[0].op = op;
-	cache[0].src_format = src_format;
-	cache[0].src_flags = src_flags;
-	cache[0].mask_format = mask_format;
-	cache[0].mask_flags = mask_flags;
-	cache[0].dest_format = dest_format;
-	cache[0].dest_flags = dest_flags;
-	cache[0].func = func;
+	    cache->cache[i + 1] = cache->cache[i];
+
+	cache->cache[0].op = op;
+	cache->cache[0].src_format = src_format;
+	cache->cache[0].src_flags = src_flags;
+	cache->cache[0].mask_format = mask_format;
+	cache->cache[0].mask_flags = mask_flags;
+	cache->cache[0].dest_format = dest_format;
+	cache->cache[0].dest_flags = dest_flags;
+	cache->cache[0].func = func;
     }
 
 out:
-- 
1.7.0.1



More information about the Pixman mailing list