From 9644b3bcfc539ab201da9d3251a3cc3ebc24d457 Mon Sep 17 00:00:00 2001 From: David Lichteblau Date: Wed, 12 Dec 2012 14:12:50 +0100 Subject: [PATCH] In x86 arch_os_get_current_thread(), do not load from %fs Simplify arch_os_get_current_thread() such that %fs is not being loaded directly even on platforms which preserve it reliably (in particular, Linux/x86 and Solaris/x86). Aside from a code simplification and reduction of cross-platform differences, this change is an improvement in the following way: If arch_os_get_current_thread() gets called in a non-Lisp pthread, it now returns NULL cleanly even on the platforms mentioned above. On the other platforms, keep the support for restoring %fs, but refactor to remove code duplication with arch_os_thread_init(). Coalesce the two differently-spelled Lisp features for this case into one. --- base-target-features.lisp-expr | 2 +- make-config.sh | 2 +- src/runtime/arch.h | 3 ++ src/runtime/thread.h | 71 +++++++++++++++++----------------------- src/runtime/x86-bsd-os.c | 20 ++++++++--- src/runtime/x86-darwin-os.c | 23 +++++++++---- 6 files changed, 67 insertions(+), 54 deletions(-) diff --git a/base-target-features.lisp-expr b/base-target-features.lisp-expr index 22530df..9ba7b4d 100644 --- a/base-target-features.lisp-expr +++ b/base-target-features.lisp-expr @@ -238,7 +238,7 @@ ;; thread local storage) is not reliably preserved in signal ;; handlers, so we need to restore its value from the pthread thread ;; local storage. - ; :restore-tls-segment-register-from-tls + ; :restore-fs-segment-register-from-tls ;; On some x86oid operating systems (darwin) SIGTRAP is not reliably ;; delivered for the INT3 instruction, so we use the UD2 instruction diff --git a/make-config.sh b/make-config.sh index 3897191..1b86204 100644 --- a/make-config.sh +++ b/make-config.sh @@ -478,7 +478,7 @@ case "$sbcl_os" in printf ' :freebsd' >> $ltf printf ' :gcc-tls' >> $ltf if [ $sbcl_arch = "x86" ]; then - printf ' :restore-tls-segment-register-from-context' >> $ltf + printf ' :restore-fs-segment-register-from-tls' >> $ltf fi link_or_copy Config.$sbcl_arch-freebsd Config ;; diff --git a/src/runtime/arch.h b/src/runtime/arch.h index 1a8cf69..c8ef480 100644 --- a/src/runtime/arch.h +++ b/src/runtime/arch.h @@ -35,6 +35,9 @@ extern void arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst); extern int arch_os_thread_init(struct thread *thread); +#if defined(LISP_FEATURE_X86) && defined(LISP_FEATURE_SB_THREAD) +extern void arch_os_load_ldt(struct thread *thread); +#endif extern int arch_os_thread_cleanup(struct thread *thread); extern lispobj funcall0(lispobj function); diff --git a/src/runtime/thread.h b/src/runtime/thread.h index ec295fc..6de8f89 100644 --- a/src/runtime/thread.h +++ b/src/runtime/thread.h @@ -294,51 +294,40 @@ static inline struct thread* arch_os_get_current_thread() static inline struct thread *arch_os_get_current_thread(void) { -#if defined(LISP_FEATURE_SB_THREAD) -#if defined(LISP_FEATURE_X86) +#if !defined(LISP_FEATURE_SB_THREAD) + return all_threads; + +#elif defined(LISP_FEATURE_X86) && defined(LISP_FEATURE_WIN32) register struct thread *me=0; -#if defined(LISP_FEATURE_WIN32) && defined(LISP_FEATURE_SB_THREAD) __asm__ ("movl %%fs:0xE10+(4*63), %0" : "=r"(me) :); return me; -#endif - if(all_threads) { -#if defined(LISP_FEATURE_DARWIN) && defined(LISP_FEATURE_RESTORE_FS_SEGMENT_REGISTER_FROM_TLS) - sel_t sel; - struct thread *th = pthread_getspecific(specials); - sel.index = th->tls_cookie; - sel.rpl = USER_PRIV; - sel.ti = SEL_LDT; - __asm__ __volatile__ ("movw %w0, %%fs" : : "r"(sel)); -#elif defined(LISP_FEATURE_FREEBSD) -#ifdef LISP_FEATURE_GCC_TLS - struct thread *th = current_thread; -#else - struct thread *th = pthread_getspecific(specials); -#endif -#ifdef LISP_FEATURE_RESTORE_TLS_SEGMENT_REGISTER_FROM_TLS - unsigned int sel = LSEL(th->tls_cookie, SEL_UPL); - unsigned int fs = rfs(); - - /* Load FS only if it's necessary. Modifying a selector - * causes privilege checking and it takes long time. */ - if (fs != sel) - load_fs(sel); -#endif - return th; -#endif - __asm__ ("movl %%fs:%c1,%0" : "=r" (me) - : "i" (offsetof (struct thread,this))); - } - return me; -#else -#ifdef LISP_FEATURE_GCC_TLS - return current_thread; -#else - return pthread_getspecific(specials); -#endif -#endif /* x86 */ + #else - return all_threads; + if (!all_threads) + /* no need to bother */ + return 0; + + /* Otherwise, use pthreads to find the right value. We do not load + * directly from %fs:this even on x86 platforms (like Linux and + * Solaris) with dependable %fs, because we want to return NULL if + * called by a non-Lisp thread, and %fs would not be initialized + * suitably in that case. */ + struct thread *th; +# ifdef LISP_FEATURE_GCC_TLS + th = current_thread; +# else + th = pthread_getspecific(specials); +# endif + +# if defined(LISP_FEATURE_RESTORE_FS_SEGMENT_REGISTER_FROM_TLS) + /* If enabled by make-config (currently Darwin and FreeBSD only), + * re-setup %fs. This is an out-of-line call, and potentially + * expensive.*/ + if (th) + arch_os_load_ldt(th); +# endif + + return th; #endif } diff --git a/src/runtime/x86-bsd-os.c b/src/runtime/x86-bsd-os.c index 8b62584..fe75566 100644 --- a/src/runtime/x86-bsd-os.c +++ b/src/runtime/x86-bsd-os.c @@ -157,11 +157,24 @@ void set_data_desc_addr(struct segment_descriptor* desc, void* addr) #endif +#ifdef LISP_FEATURE_SB_THREAD +void +arch_os_load_ldt(struct thread *thread) +{ + int sel = LSEL(thread->tls_cookie, SEL_UPL); + unsigned int fs = rfs(); + + /* Load FS only if it's necessary. Modifying a selector + * causes privilege checking and it takes long time. */ + if (fs != sel) + load_fs(sel); +} +#endif + int arch_os_thread_init(struct thread *thread) { #ifdef LISP_FEATURE_SB_THREAD int n; - int sel; struct segment_descriptor ldt_entry = { 0, 0, SDT_MEMRW, SEL_UPL, 1, 0, 0, 1, 0, 0 }; @@ -175,10 +188,9 @@ int arch_os_thread_init(struct thread *thread) { lose("unexpected i386_set_ldt(..) failure\n"); } FSHOW_SIGNAL((stderr, "/ TLS: Allocated LDT %x\n", n)); - sel = LSEL(n, SEL_UPL); - load_fs(sel); - thread->tls_cookie=n; + arch_os_load_ldt(thread); + #ifdef LISP_FEATURE_GCC_TLS current_thread = thread; #else diff --git a/src/runtime/x86-darwin-os.c b/src/runtime/x86-darwin-os.c index 323e549..8489322 100644 --- a/src/runtime/x86-darwin-os.c +++ b/src/runtime/x86-darwin-os.c @@ -44,10 +44,23 @@ void set_data_desc_addr(data_desc_t* desc, void* addr) #endif +#ifdef LISP_FEATURE_SB_THREAD +void +arch_os_load_ldt(struct thread *thread) +{ + sel_t sel; + + sel.index = thread->tls_cookie; + sel.rpl = USER_PRIV; + sel.ti = SEL_LDT; + + __asm__ __volatile__ ("mov %0, %%fs" : : "r"(sel)); +} +#endif + int arch_os_thread_init(struct thread *thread) { #ifdef LISP_FEATURE_SB_THREAD int n; - sel_t sel; data_desc_t ldt_entry = { 0, 0, 0, DESC_DATA_WRITE, 3, 1, 0, DESC_DATA_32B, DESC_GRAN_BYTE, 0 }; @@ -65,13 +78,9 @@ int arch_os_thread_init(struct thread *thread) { thread_mutex_unlock(&modify_ldt_lock); FSHOW_SIGNAL((stderr, "/ TLS: Allocated LDT %x\n", n)); - sel.index = n; - sel.rpl = USER_PRIV; - sel.ti = SEL_LDT; - - __asm__ __volatile__ ("mov %0, %%fs" : : "r"(sel)); - thread->tls_cookie=n; + arch_os_load_ldt(thread); + pthread_setspecific(specials,thread); #endif #ifdef LISP_FEATURE_MACH_EXCEPTION_HANDLER -- 1.7.10.4