[cairo] Problem in pthread-specific thread-local storage macros in pixman?

Tor Lillqvist tml at iki.fi
Wed Apr 7 00:14:57 PDT 2010


> A related question: Is there any support in the Windows versions of
> GCC for either __thread or __declspec(thread)?

There is support for __thread (it gets recognized by the configure
script), but I strongly suspect it might be broken.

I think I would prefer to just use explicit code, as in the pthread
case. In fact, I was just hacking on that last weekend. Below is what
I came up with before abandoning it... I.e. this is not really tested
that well, as the thread-local storage is used, if I understood
correctly, only when SSE2 is used, and as seen in another thread, SSE2
intrinsics are broken in MinGW, so I disable it anyway currently...

This looks more complex than I like. The complexity comes mostly from
the way the equivalent of pthread_once() is implemented; I got this
idea from http://stackoverflow.com/questions/631879/library-initialization-pthread-once-in-win32-implementation
.

Also, not being able to just #include <windows.h> is a pain. (That's
the reason for the !defined(__WIN64); on 64-bit Windows the Win32 API
declarations would be slightly different.)

This has to be before the check for if
defined(TOOLCHAIN_SUPPORTS__THREAD), as that gets set for MinGW, too.

#if defined(__MINGW32__) && !defined(__WIN64)

/* We can't include <windows.h> as it causes carious clashes with
 * identifiers in pixman, sigh. So just declare the functions we need
 * here.
 */
extern __stdcall long InterlockedCompareExchange(long volatile *, long, long);
#define InterlockedCompareExchangePointer(d,e,c)  \
    (void *)InterlockedCompareExchange((long volatile *)(d),(long)(e),(long)(c))
extern __stdcall int TlsAlloc (void);
extern __stdcall void *TlsGetValue (unsigned);
extern __stdcall int TlsSetValue (unsigned, void *);
extern __stdcall void *CreateMutexA(void *, int, char *);
extern __stdcall int CloseHandle(void *);
extern __stdcall unsigned WaitForSingleObject (void *, unsigned);
extern __stdcall int ReleaseMutex (void *);

#  define PIXMAN_DEFINE_THREAD_LOCAL(type, name) \
    static volatile int tls_ ## name ## _initialized = 0; \
    static void *tls_ ## name ## _mutex = NULL; \
    static unsigned tls_ ## name ## _index; \
 \
    static type * \
    tls_ ## name ## _alloc (void) \
    { \
        type *value = malloc (sizeof (type)); \
        if (value) \
            TlsSetValue (tls_ ## name ## _index, value); \
        return value; \
    } \
 \
    static force_inline type * \
    tls_ ## name ## _get (void) \
    { \
        type *value; \
        if (!tls_ ## name ## _initialized) \
        { \
            if (!tls_ ## name ## _mutex) \
            { \
                void *mutex = CreateMutexA (NULL, 0, NULL); \
                if (InterlockedCompareExchangePointer (&tls_ ## name
## _mutex, mutex, NULL) != NULL) \
                    CloseHandle (mutex); \
            } \
            WaitForSingleObject (tls_ ## name ## _mutex, 0xFFFFFFFF); \
            if (!tls_ ## name ## _initialized) \
            { \
                tls_ ## name ## _index = TlsAlloc (); \
                tls_ ## name ## _initialized = 1; \
            } \
            ReleaseMutex (tls_ ## name ## _mutex); \
        } \
        if (tls_ ## name ## _index == 0xFFFFFFFF) \
            return NULL; \
        value = TlsGetValue (tls_ ## name ## _index); \
        if (!value) \
            value = tls_ ## name ## _alloc (); \
        return value; \
    }

#   define PIXMAN_GET_THREAD_LOCAL(name) \
    tls_ ## name ## _get ()

--tml


More information about the cairo mailing list