Skip to content

Commit

Permalink
1.0.9.62: Performance and stability improvement of threading on FreeBSD
Browse files Browse the repository at this point in the history
* Use GCC's Thread-Local Storage to store current thread.
  (Tested on Linux x86 and x86-64, too)

* Restore lisp level TLS segment register at interrupt handler.
  • Loading branch information
NIIMI Satoshi committed Sep 18, 2007
1 parent 134fa6b commit 9a19ce4
Show file tree
Hide file tree
Showing 11 changed files with 59 additions and 6 deletions.
3 changes: 2 additions & 1 deletion make-config.sh
Expand Up @@ -198,8 +198,9 @@ case "$sbcl_os" in
printf ' :elf' >> $ltf
printf ' :freebsd' >> $ltf
printf ' :sb-pthread-futex' >> $ltf
printf ' :gcc-tls' >> $ltf
if [ $sbcl_arch = "x86" ]; then
printf ' :restore-tls-segment-register-from-tls' >> $ltf
printf ' :restore-tls-segment-register-from-context' >> $ltf
fi
link_or_copy Config.$sbcl_arch-freebsd Config
;;
Expand Down
4 changes: 2 additions & 2 deletions src/runtime/globals.c
Expand Up @@ -52,7 +52,7 @@ boolean stop_the_world=0;
* is done). For the GENCGC, it always points to DYNAMIC_SPACE_START. */
lispobj *current_dynamic_space;

#if defined(LISP_FEATURE_SB_THREAD)
#if defined(LISP_FEATURE_SB_THREAD) && !defined(LISP_FEATURE_GCC_TLS)
pthread_key_t specials=0;
#endif

Expand All @@ -71,7 +71,7 @@ void globals_init(void)
foreign_function_call_active = 1;
#endif

#ifdef LISP_FEATURE_SB_THREAD
#if defined(LISP_FEATURE_SB_THREAD) && !defined(LISP_FEATURE_GCC_TLS)
pthread_key_create(&specials,0);
#endif
}
2 changes: 1 addition & 1 deletion src/runtime/globals.h
Expand Up @@ -41,7 +41,7 @@ extern size_t dynamic_space_size;
#endif
extern char **ENVIRON;

#if defined(LISP_FEATURE_SB_THREAD)
#if defined(LISP_FEATURE_SB_THREAD) && !defined(LISP_FEATURE_GCC_TLS)
extern pthread_key_t specials;
#endif

Expand Down
3 changes: 3 additions & 0 deletions src/runtime/thread.c
Expand Up @@ -91,6 +91,9 @@ pthread_mutex_t all_threads_lock = PTHREAD_MUTEX_INITIALIZER;
#ifdef LOCK_CREATE_THREAD
static pthread_mutex_t create_thread_lock = PTHREAD_MUTEX_INITIALIZER;
#endif
#ifdef LISP_FEATURE_GCC_TLS
__thread struct thread *current_thread;
#endif
#endif

#if defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64)
Expand Down
16 changes: 15 additions & 1 deletion src/runtime/thread.h
Expand Up @@ -109,6 +109,10 @@ os_context_t *get_interrupt_context_for_thread(struct thread *th)
[fixnum_value(SymbolValue(FREE_INTERRUPT_CONTEXT_INDEX,th)-1)];
}

#if defined(LISP_FEATURE_SB_THREAD) && defined(LISP_FEATURE_GCC_TLS)
extern __thread struct thread *current_thread;
#endif

/* This is clearly per-arch and possibly even per-OS code, but we can't
* put it somewhere sensible like x86-linux-os.c because it needs too
* much stuff like struct thread and all_threads to be defined, which
Expand All @@ -127,23 +131,33 @@ static inline struct thread *arch_os_get_current_thread(void)
sel.rpl = USER_PRIV;
sel.ti = SEL_LDT;
__asm__ __volatile__ ("movw %w0, %%fs" : : "r"(sel));
#elif defined(LISP_FEATURE_FREEBSD) && defined(LISP_FEATURE_RESTORE_TLS_SEGMENT_REGISTER_FROM_TLS)
#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__ __volatile__ ("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;
Expand Down
5 changes: 5 additions & 0 deletions src/runtime/x86-64-assem.S
Expand Up @@ -182,13 +182,18 @@ Lstack:
push %rsi #
push %rdx #
#ifdef LISP_FEATURE_SB_THREAD
#ifdef LISP_FEATURE_GCC_TLS
movq %fs:0, %rax
movq GNAME(current_thread)@TPOFF(%rax), %r12
#else
#ifdef LISP_FEATURE_DARWIN
mov GSYM(GNAME(specials)),%rdi
#else
mov specials,%rdi
#endif
call GNAME(pthread_getspecific)
mov %rax,%r12
#endif
#endif
pop %rcx # num args
pop %rbx # arg vector
Expand Down
4 changes: 4 additions & 0 deletions src/runtime/x86-64-bsd-os.c
Expand Up @@ -89,8 +89,12 @@ os_flush_icache(os_vm_address_t address, os_vm_size_t length)
int arch_os_thread_init(struct thread *thread) {
stack_t sigstack;
#ifdef LISP_FEATURE_SB_THREAD
#ifdef LISP_FEATURE_GCC_TLS
current_thread = thread;
#else
pthread_setspecific(specials,thread);
#endif
#endif

#ifdef LISP_FEATURE_MACH_EXCEPTION_HANDLER
mach_thread_init(THREAD_STRUCT_TO_EXCEPTION_PORT(thread));
Expand Down
4 changes: 4 additions & 0 deletions src/runtime/x86-64-linux-os.c
Expand Up @@ -56,8 +56,12 @@ size_t os_vm_page_size;
int arch_os_thread_init(struct thread *thread) {
stack_t sigstack;
#ifdef LISP_FEATURE_SB_THREAD
#ifdef LISP_FEATURE_GCC_TLS
current_thread = thread;
#else
pthread_setspecific(specials,thread);
#endif
#endif
#ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK
/* Signal handlers are run on the control stack, so if it is exhausted
* we had better use an alternate stack for whatever signal tells us
Expand Down
18 changes: 18 additions & 0 deletions src/runtime/x86-bsd-os.c
Expand Up @@ -169,8 +169,12 @@ int arch_os_thread_init(struct thread *thread) {
load_fs(sel);

thread->tls_cookie=n;
#ifdef LISP_FEATURE_GCC_TLS
current_thread = thread;
#else
pthread_setspecific(specials,thread);
#endif
#endif

#ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK
stack_t sigstack;
Expand Down Expand Up @@ -207,6 +211,14 @@ int arch_os_thread_cleanup(struct thread *thread) {
#endif /* !LISP_FEATURE_DARWIN */

#if defined(LISP_FEATURE_FREEBSD)
#if defined(LISP_FEATURE_RESTORE_TLS_SEGMENT_REGISTER_FROM_CONTEXT)
void
os_restore_tls_segment_register(os_context_t *context)
{
load_fs(context->uc_mcontext.mc_fs);
}
#endif

void
os_restore_fp_control(os_context_t *context)
{
Expand All @@ -217,5 +229,11 @@ os_restore_fp_control(os_context_t *context)
struct envxmm *ex = (struct envxmm*)(&context->uc_mcontext.mc_fpstate);
asm ("fldcw %0" : : "m" (ex->en_cw));
#endif
#if defined(LISP_FEATURE_RESTORE_TLS_SEGMENT_REGISTER_FROM_CONTEXT)
/* Calling this function here may not be good idea. Or rename
* function name os_restore_fp_control to os_restore_context or
* so, to match the behavior? */
os_restore_tls_segment_register(context);
#endif
}
#endif
4 changes: 4 additions & 0 deletions src/runtime/x86-linux-os.c
Expand Up @@ -107,8 +107,12 @@ int arch_os_thread_init(struct thread *thread) {
pthread_mutex_unlock(&modify_ldt_lock);

if(n<0) return 0;
#ifdef LISP_FEATURE_GCC_TLS
current_thread = thread;
#else
pthread_setspecific(specials,thread);
#endif
#endif
#ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK
/* Signal handlers are run on the control stack, so if it is exhausted
* we had better use an alternate stack for whatever signal tells us
Expand Down
2 changes: 1 addition & 1 deletion version.lisp-expr
Expand Up @@ -17,4 +17,4 @@
;;; checkins which aren't released. (And occasionally for internal
;;; versions, especially for internal versions off the main CVS
;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".)
"1.0.9.61"
"1.0.9.62"

0 comments on commit 9a19ce4

Please sign in to comment.