mingw32: use same strategy for thread-locals as MSVC

The gcc implementation of `_thread' seems to be much
slower, so we use the inline-assembly technique from
the MSVC build plus a hack in "main.c".
This commit is contained in:
Matthew Flatt 2012-12-20 16:37:23 -07:00
parent 0c91930965
commit 3fb02ecb2e
3 changed files with 34 additions and 7 deletions

View File

@ -27,7 +27,7 @@ extern "C" {
#if defined(MZ_USE_PLACES) || defined(MZ_USE_FUTURES) #if defined(MZ_USE_PLACES) || defined(MZ_USE_FUTURES)
# define USE_THREAD_LOCAL # define USE_THREAD_LOCAL
# if _MSC_VER # ifdef _WIN32
# ifdef _WIN64 # ifdef _WIN64
# define THREAD_LOCAL __declspec(thread) # define THREAD_LOCAL __declspec(thread)
# define MZ_THREAD_EXTERN extern # define MZ_THREAD_EXTERN extern
@ -36,10 +36,6 @@ extern "C" {
# define THREAD_LOCAL /* empty */ # define THREAD_LOCAL /* empty */
# define IMPLEMENT_THREAD_LOCAL_VIA_WIN_TLS # define IMPLEMENT_THREAD_LOCAL_VIA_WIN_TLS
# endif # endif
# elif __MINGW32__
# define THREAD_LOCAL __thread
# define MZ_THREAD_EXTERN extern
# define IMPLEMENT_THREAD_LOCAL_EXTERNALLY_VIA_PROC
# elif (defined(__APPLE__) && defined(__MACH__)) || defined(GC2_PLACES_TESTING) # elif (defined(__APPLE__) && defined(__MACH__)) || defined(GC2_PLACES_TESTING)
# define IMPLEMENT_THREAD_LOCAL_VIA_PTHREADS # define IMPLEMENT_THREAD_LOCAL_VIA_PTHREADS
# if defined(__x86_64__) || defined(__i386__) # if defined(__x86_64__) || defined(__i386__)
@ -422,6 +418,19 @@ MZ_EXTERN uintptr_t scheme_tls_delta;
MZ_EXTERN int scheme_tls_index; MZ_EXTERN int scheme_tls_index;
# endif # endif
static __inline Thread_Local_Variables **scheme_get_thread_local_variables_ptr(void) { static __inline Thread_Local_Variables **scheme_get_thread_local_variables_ptr(void) {
# ifdef __MINGW32__
Thread_Local_Variables **x;
asm (
"mov %%fs:(0x2C), %%eax;"
"mov (%%eax), %%eax;"
"add %1, %%eax;"
"mov %%eax, %0;"
:"=r"(x) /* output */
:"r"(scheme_tls_delta)
:"%eax" /* clobbered register */
);
return x;
# else
__asm { mov eax, FS:[0x2C] __asm { mov eax, FS:[0x2C]
# ifdef MZ_USE_WIN_TLS_VIA_DLL # ifdef MZ_USE_WIN_TLS_VIA_DLL
add eax, scheme_tls_index add eax, scheme_tls_index
@ -429,6 +438,7 @@ static __inline Thread_Local_Variables **scheme_get_thread_local_variables_ptr(v
mov eax, [eax] mov eax, [eax]
add eax, scheme_tls_delta } add eax, scheme_tls_delta }
/* result is in eax */ /* result is in eax */
# endif
} }
static __inline Thread_Local_Variables *scheme_get_thread_local_variables(void) { static __inline Thread_Local_Variables *scheme_get_thread_local_variables(void) {
return *scheme_get_thread_local_variables_ptr(); return *scheme_get_thread_local_variables_ptr();

View File

@ -292,11 +292,11 @@ START_XFORM_SKIP;
#ifdef IMPLEMENT_THREAD_LOCAL_VIA_WIN_TLS #ifdef IMPLEMENT_THREAD_LOCAL_VIA_WIN_TLS
extern intptr_t _tls_index; extern intptr_t _tls_index;
static __declspec(thread) void *tls_space; static __thread void *tls_space;
#endif #endif
#ifdef DOS_FILE_SYSTEM #ifdef DOS_FILE_SYSTEM
static void load_delayed() void load_delayed()
{ {
/* Order matters: load dependencies first */ /* Order matters: load dependencies first */
# ifndef MZ_PRECISE_GC # ifndef MZ_PRECISE_GC
@ -305,8 +305,20 @@ static void load_delayed()
load_delayed_dll(NULL, "libracket" DLL_3M_SUFFIX "xxxxxxx.dll"); load_delayed_dll(NULL, "libracket" DLL_3M_SUFFIX "xxxxxxx.dll");
record_dll_path(); record_dll_path();
# ifdef IMPLEMENT_THREAD_LOCAL_VIA_WIN_TLS # ifdef IMPLEMENT_THREAD_LOCAL_VIA_WIN_TLS
# ifdef __MINGW32__
{
/* gcc declares space for the thread-local variable in a way that
the OS can set up, but its doesn't actually map variables
through the OS-supplied mechanism. Just assume that the first
thread-local variable is ours. */
void **base;
asm("mov %%fs:(0x2C), %0;" :"=r"(base));
scheme_register_tls_space(*base, _tls_index);
}
# else
scheme_register_tls_space(&tls_space, _tls_index); scheme_register_tls_space(&tls_space, _tls_index);
# endif # endif
# endif
} }
#endif #endif

View File

@ -281,8 +281,13 @@ void scheme_setup_thread_local_key_if_needed() XFORM_SKIP_PROC
{ {
void **base; void **base;
# ifdef __MINGW32__
asm("mov %%fs:(0x2C), %0;"
:"=r"(base)); /* output */
# else
__asm { mov ecx, FS:[0x2C] __asm { mov ecx, FS:[0x2C]
mov base, ecx } mov base, ecx }
# endif
scheme_tls_delta -= (uintptr_t)base[scheme_tls_index]; scheme_tls_delta -= (uintptr_t)base[scheme_tls_index];
scheme_tls_index *= sizeof(void*); scheme_tls_index *= sizeof(void*);
} }