X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fruntime%2Fx86-sunos-os.c;h=0edd0b1d7b8582b7deb91c70fe1e6f0c81930cf1;hb=35ab27e7aab71c94aa6be12da15603c7fd87fca8;hp=fd11cf5e6d20725582dab6c466e963c05f9b00c8;hpb=a01045b552695ae546b19ca6fa9bc554ad9c7998;p=sbcl.git diff --git a/src/runtime/x86-sunos-os.c b/src/runtime/x86-sunos-os.c index fd11cf5..0edd0b1 100644 --- a/src/runtime/x86-sunos-os.c +++ b/src/runtime/x86-sunos-os.c @@ -18,12 +18,96 @@ #include #include +#ifdef LISP_FEATURE_SB_THREAD +#include +#include +#endif + #include "validate.h" + #ifdef LISP_FEATURE_SB_THREAD -#error "Define threading support functions" -#else +pthread_mutex_t modify_ldt_lock = PTHREAD_MUTEX_INITIALIZER; + +static int +ldt_index_selector (int index) { + return index << 3 | 7; +} + +static int +find_free_ldt_index () { + struct ssd ssd; + int usage[65536/sizeof(int)]; + int i; + FILE *fp; + + memset(usage, 0, sizeof(usage)); + + fp = fopen("/proc/self/ldt", "r"); + + if (fp == NULL) { + lose("Couldn't open /proc/self/ldt"); + } + + while (fread(&ssd, sizeof(ssd), 1, fp) == 1) { + int index = ssd.sel >> 3; + if (index >= 65536) { + lose("segment selector index too large: %d", index); + } + + usage[index / sizeof(int)] |= 1 << (index & (sizeof(int)-1)); + } + + fclose(fp); + + /* Magic number 7 is the first LDT index that Solaris leaves free. */ + for (i = 7; i < 65536; i++) { + if (~usage[i / sizeof(int)] & (1 << (i & (sizeof(int)-1)))) { + return i; + } + } + + lose("Couldn't find a free LDT index"); +} + +static int +install_segment (unsigned long start, unsigned long size) { + int selector; + + thread_mutex_lock(&modify_ldt_lock); + + selector = ldt_index_selector(find_free_ldt_index()); + struct ssd ssd = { selector, + start, + size, + 0xf2, + 0x4}; + if (sysi86(SI86DSCR, &ssd) < 0) { + lose("Couldn't install segment for thread-local data"); + } + + thread_mutex_unlock(&modify_ldt_lock); + + return selector; +} +#endif + int arch_os_thread_init(struct thread *thread) { stack_t sigstack; + +#ifdef LISP_FEATURE_SB_THREAD + int sel = install_segment((unsigned long) thread, dynamic_values_bytes); + + FSHOW_SIGNAL((stderr, "/ TLS: Allocated LDT %x\n", sel)); + __asm__ __volatile__ ("mov %0, %%fs" : : "r"(sel)); + + thread->tls_cookie = sel; + pthread_setspecific(specials,thread); + +# ifdef LISP_FEATURE_SB_SAFEPOINT + thread->selfptr = 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 @@ -35,10 +119,27 @@ int arch_os_thread_init(struct thread *thread) { #endif return 1; /* success */ } + int arch_os_thread_cleanup(struct thread *thread) { +#if defined(LISP_FEATURE_SB_THREAD) + int n = thread->tls_cookie; + struct ssd delete = { n, 0, 0, 0, 0}; + + /* Set the %%fs register back to 0 and free the ldt by setting it + * to NULL. + */ + FSHOW_SIGNAL((stderr, "/ TLS: Freeing LDT %x\n", n)); + + __asm__ __volatile__ ("mov %0, %%fs" : : "r"(0)); + + thread_mutex_lock(&modify_ldt_lock); + if (sysi86(SI86DSCR, &delete) < 0) { + lose("Couldn't remove segment\n"); + } + thread_mutex_unlock(&modify_ldt_lock); +#endif return 1; /* success */ } -#endif os_context_register_t * os_context_register_addr(os_context_t *context, int offset) @@ -79,3 +180,14 @@ os_context_sigmask_addr(os_context_t *context) void os_flush_icache(os_vm_address_t address, os_vm_size_t length) { } + +unsigned long +os_context_fp_control(os_context_t *context) +{ + int *state = context->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state; + /* The STATE array is in the format used by the x86 instruction FNSAVE, + * so the FPU control word is in the first 16 bits */ + int cw = (state[0] & 0xffff); + int sw = context->uc_mcontext.fpregs.fp_reg_set.fpchip_state.status; + return (cw ^ 0x3f) | (sw << 16); +}