[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