diff --git a/src/mzscheme/include/schthread.h b/src/mzscheme/include/schthread.h index c40910b45b..c6db8d2f10 100644 --- a/src/mzscheme/include/schthread.h +++ b/src/mzscheme/include/schthread.h @@ -23,7 +23,7 @@ # define USE_THREAD_LOCAL # if _MSC_VER # define THREAD_LOCAL __declspec(thread) -# elif defined(OS_X) +# elif defined(OS_X) || (defined(linux) && defined(MZ_USES_SHARED_LIB)) # define IMPLEMENT_THREAD_LOCAL_VIA_PTHREADS # if defined(__x86_64__) || defined(__i386__) # define INLINE_GETSPECIFIC_ASSEMBLY_CODE @@ -236,11 +236,28 @@ START_XFORM_SKIP; # endif static inline Thread_Local_Variables *scheme_get_thread_local_variables() __attribute__((used)); static inline Thread_Local_Variables *scheme_get_thread_local_variables() { - Thread_Local_Variables *x; -# if defined(__x86_64__) + Thread_Local_Variables *x = NULL; +# if defined(OS_X) +# if defined(__x86_64__) asm volatile("movq %%gs:0x8A0, %0" : "=r"(x)); -# else +# else asm volatile("movl %%gs:0x468, %0" : "=r"(x)); +# endif +# elif defined(linux) && defined(MZ_USES_SHARED_LIB) +# if defined(__x86_64__) + asm volatile( "mov %1, %%eax;" + "shl $0x4, %%rax;" + "mov %%fs:0x10, %%rdx;" + "mov 0x118(%%rax,%%rdx), %0;" + :"=r"(x) /* output */ + :"r"(scheme_thread_local_key) + :"%rax", "%rdx" /* clobbered register */ + ); +# else +# error scheme_get_thread_local_variables no defined on this platform +# endif +# else +# error scheme_get_thread_local_variables no defined on this platform # endif return x; } diff --git a/src/mzscheme/src/salloc.c b/src/mzscheme/src/salloc.c index 5ee86667a2..60bf423fc4 100644 --- a/src/mzscheme/src/salloc.c +++ b/src/mzscheme/src/salloc.c @@ -178,10 +178,8 @@ static int do_main_stack_setup(int no_auto_statics, Scheme_Nested_Main _main, vo return return_code; } -int scheme_main_stack_setup(int no_auto_statics, Scheme_Nested_Main _main, void *data) XFORM_SKIP_PROC -{ -#ifdef IMPLEMENT_THREAD_LOCAL_VIA_PTHREADS -# ifdef INLINE_GETSPECIFIC_ASSEMBLY_CODE +#if defined(IMPLEMENT_THREAD_LOCAL_VIA_PTHREADS) && defined(INLINE_GETSPECIFIC_ASSEMBLY_CODE) +static void macosx_get_thread_local_key_for_assembly_code() { /* Our [highly questionable] strategy for inlining pthread_getspecific() is taken from the Go implementation (see "http://golang.org/src/libcgo/darwin_386.c"). In brief, we assume that thread-local variables are going to be @@ -190,14 +188,12 @@ int scheme_main_stack_setup(int no_auto_statics, Scheme_Nested_Main _main, void that particular key and double-check that it worked. */ pthread_key_t unwanted[16]; int num_unwanted = 0; -# endif while (1) { if (pthread_key_create(&scheme_thread_local_key, NULL)) { fprintf(stderr, "pthread key create failed\n"); abort(); } -# ifdef INLINE_GETSPECIFIC_ASSEMBLY_CODE if (scheme_thread_local_key == 0x108) break; else { @@ -207,25 +203,56 @@ int scheme_main_stack_setup(int no_auto_statics, Scheme_Nested_Main _main, void } unwanted[num_unwanted++] = scheme_thread_local_key; } -# else - break; -# endif } -# ifdef INLINE_GETSPECIFIC_ASSEMBLY_CODE pthread_setspecific(scheme_thread_local_key, (void *)0xaced); if (scheme_get_thread_local_variables() != (Thread_Local_Variables *)0xaced) { fprintf(stderr, "pthread getspecific inline hack failed\n"); abort(); } + while (num_unwanted--) { pthread_key_delete(unwanted[num_unwanted]); } -# endif +} #endif - scheme_init_os_thread(); +void scheme_setup_thread_local_key_if_needed() { +#ifdef IMPLEMENT_THREAD_LOCAL_VIA_PTHREADS +# ifdef INLINE_GETSPECIFIC_ASSEMBLY_CODE +# if defined(linux) + scheme_thread_local_key = 0; + if (pthread_key_create(&scheme_thread_local_key, NULL)) { + fprintf(stderr, "pthread key create failed\n"); + abort(); + } + /* + if (scheme_thread_local_key != 0) { + fprintf(stderr, "pthread getspecific inline hack failed scheme_thread_local_key %i\n", scheme_thread_local_key); + abort(); + } + */ + pthread_setspecific(scheme_thread_local_key, (void *)0xaced); + if (scheme_get_thread_local_variables() != (Thread_Local_Variables *)0xaced) { + fprintf(stderr, "pthread getspecific inline hack failed to return set data\n"); + abort(); + } +# else + macosx_get_thread_local_key_for_assembly_code(); +# endif +# else + if (pthread_key_create(&scheme_thread_local_key, NULL)) { + fprintf(stderr, "pthread key create failed\n"); + abort(); + } +# endif +#endif +} +int scheme_main_stack_setup(int no_auto_statics, Scheme_Nested_Main _main, void *data) XFORM_SKIP_PROC +{ + scheme_setup_thread_local_key_if_needed(); + scheme_init_os_thread(); return do_main_stack_setup(no_auto_statics, _main, data); } @@ -275,6 +302,15 @@ extern void GC_attach_current_thread_exceptions_to_handler(); # endif #endif +#ifdef IMPLEMENT_THREAD_LOCAL_VIA_PTHREADS +void scheme_set_thread_local_variables(void *tlvas) XFORM_SKIP_PROC { + pthread_setspecific(scheme_thread_local_key, tlvas); +} +void* scheme_dbg_get_thread_local_variables() XFORM_SKIP_PROC { + return pthread_getspecific(scheme_thread_local_key); +} +#endif + void scheme_init_os_thread() XFORM_SKIP_PROC { #ifdef IMPLEMENT_THREAD_LOCAL_VIA_PTHREADS