In x86 arch_os_get_current_thread(), do not load from %fs
authorDavid Lichteblau <david@lichteblau.com>
Wed, 12 Dec 2012 13:12:50 +0000 (14:12 +0100)
committerDavid Lichteblau <david@lichteblau.com>
Mon, 17 Dec 2012 13:42:07 +0000 (14:42 +0100)
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
make-config.sh
src/runtime/arch.h
src/runtime/thread.h
src/runtime/x86-bsd-os.c
src/runtime/x86-darwin-os.c

index 22530df..9ba7b4d 100644 (file)
  ;; 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
index 3897191..1b86204 100644 (file)
@@ -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
                 ;;
index 1a8cf69..c8ef480 100644 (file)
@@ -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);
index ec295fc..6de8f89 100644 (file)
@@ -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
 }
 
index 8b62584..fe75566 100644 (file)
@@ -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
index 323e549..8489322 100644 (file)
@@ -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