Add PIXMAN_DEFINE_THREAD_LOCAL() and PIXMAN_GET_THREAD_LOCAL() macros
authorSøren Sandmann Pedersen <ssp@redhat.com>
Tue, 16 Mar 2010 16:23:50 +0000 (12:23 -0400)
committerSøren Sandmann Pedersen <ssp@redhat.com>
Tue, 16 Mar 2010 18:58:12 +0000 (14:58 -0400)
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.

pixman/pixman-compiler.h
pixman/pixman.c

index 5aeef86..a4e3f88 100644 (file)
 #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
index c71617e..68483a0 100644 (file)
@@ -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: