diff --git a/src/racket/include/schthread.h b/src/racket/include/schthread.h index 6dda342d88..ab5a95909f 100644 --- a/src/racket/include/schthread.h +++ b/src/racket/include/schthread.h @@ -327,6 +327,9 @@ typedef struct Thread_Local_Variables { /* Using Pthread getspecific() */ # include MZ_EXTERN pthread_key_t scheme_thread_local_key; +# if defined(__APPLE__) && defined(__MACH__) +MZ_EXTERN int scheme_thread_local_offset; +# endif # ifndef INLINE_GETSPECIFIC_ASSEMBLY_CODE # define scheme_get_thread_local_variables() ((Thread_Local_Variables *)pthread_getspecific(scheme_thread_local_key)) # ifdef MZ_XFORM @@ -341,13 +344,13 @@ static inline Thread_Local_Variables *scheme_get_thread_local_variables() { Thread_Local_Variables *x = NULL; # if defined(__APPLE__) && defined(__MACH__) # if defined(__x86_64__) - asm volatile("movq %%gs:0x60(,%1,8), %0" : "=r"(x) : "r"(scheme_thread_local_key)); + asm("movq %%gs:0(%1,%2,8), %0" : "=r"(x) : "r"(scheme_thread_local_offset), "r"((int)scheme_thread_local_key)); # else - asm volatile("movl %%gs:0x48(,%1,4), %0" : "=r"(x) : "r"(scheme_thread_local_key)); + asm("movl %%gs:0(%1,%2,4), %0" : "=r"(x) : "r"(scheme_thread_local_offset), "r"(scheme_thread_local_key)); # endif # elif defined(linux) # if defined(__x86_64__) - asm volatile( "mov %1, %%eax;" + asm( "mov %1, %%eax;" "shl $0x4, %%rax;" "mov %%fs:0x10, %%rdx;" "mov 0x118(%%rax,%%rdx), %0;" diff --git a/src/racket/src/salloc.c b/src/racket/src/salloc.c index 413e60183c..77859f4d30 100644 --- a/src/racket/src/salloc.c +++ b/src/racket/src/salloc.c @@ -67,6 +67,12 @@ SHARED_OK THREAD_LOCAL Thread_Local_Variables scheme_thread_locals; # endif #endif +#if defined(__APPLE__) && defined(__MACH__) +# include +# include +int scheme_thread_local_offset = 0; +#endif + extern int scheme_num_copied_stacks; SHARED_OK static uintptr_t scheme_primordial_os_thread_stack_base; THREAD_LOCAL_DECL(static uintptr_t scheme_os_thread_stack_base); @@ -198,47 +204,6 @@ void scheme_set_thread_local_variables(Thread_Local_Variables *tlvs) XFORM_SKIP_ } #endif -#if 0 && defined(IMPLEMENT_THREAD_LOCAL_VIA_PTHREADS) && defined(INLINE_GETSPECIFIC_ASSEMBLY_CODE) -/* This code is dsiabled */ -static void macosx_get_thread_local_key_for_assembly_code() XFORM_SKIP_PROC -{ - /* 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 - accessed via the gs segment register at offset 0x48 (i386) or 0x60 (x86_64), - and we also hardwire the thread-local key 0x110. Here we have to try to get - that particular key and double-check that it worked. */ - pthread_key_t unwanted[16]; - int num_unwanted = 0; - - while (1) { - if (pthread_key_create(&scheme_thread_local_key, NULL)) { - fprintf(stderr, "pthread key create failed\n"); - abort(); - } - if (scheme_thread_local_key == 0x110) - break; - else { - if (num_unwanted == 24) { - fprintf(stderr, "pthread key create never produced 0x110 for inline hack\n"); - abort(); - } - unwanted[num_unwanted++] = scheme_thread_local_key; - } - } - - 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 - #ifdef IMPLEMENT_THREAD_LOCAL_VIA_WIN_TLS void scheme_register_tls_space(void *tls_space, int tls_index) XFORM_SKIP_PROC { @@ -267,6 +232,45 @@ void scheme_setup_thread_local_key_if_needed() XFORM_SKIP_PROC fprintf(stderr, "pthread key create failed\n"); abort(); } +# if defined(__APPLE__) && defined(__MACH__) + /* Darwin version 11 (Max OS X Lion) changes the offset from %gs + for thread-local storage. */ + { + int name[2]; + char vers[128]; + size_t len; + int i, vn = 0, bad = 0; + + name[0] = CTL_KERN; + name[1] = KERN_OSRELEASE; + len = sizeof(vers); + if (sysctl(name, 2, vers, &len, NULL, 0)) + bad = 1; + else { + for (i = 0; vers[i] && (vers[i] != '.'); i++) { + if ((vers[i] < '0') || (vers[i] > '9')) + break; + vn = (vn * 10) + (vers[i] - '0'); + } + if ((vers[i] == '.') && (vn > 0) && (vn < 1000)) { + if (vn > 10) + scheme_thread_local_offset = 0; + else { +# if defined(__x86_64__) + scheme_thread_local_offset = 0x60; +# else + scheme_thread_local_offset = 0x48; +# endif + } + } else + bad = 1; + } + if (bad) { + fprintf(stderr, "kernel version lookup failed\n"); + abort(); + } + } +# endif #endif #ifdef IMPLEMENT_THREAD_LOCAL_VIA_WIN_TLS {