diff options
author | dfr <dfr@FreeBSD.org> | 2004-08-15 16:21:30 +0000 |
---|---|---|
committer | dfr <dfr@FreeBSD.org> | 2004-08-15 16:21:30 +0000 |
commit | eebd52f2bba016b347822a238d57326feab23fc1 (patch) | |
tree | 02ab87159098d00bfbe86442a3abb3f69dc93c6c /lib | |
parent | 2f90ca8b3cce7d9b8e36a7641f90e8d59ebde4a5 (diff) | |
download | FreeBSD-src-eebd52f2bba016b347822a238d57326feab23fc1.zip FreeBSD-src-eebd52f2bba016b347822a238d57326feab23fc1.tar.gz |
Add TLS support for libthr on i386.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libthr/arch/i386/i386/_curthread.S | 2 | ||||
-rw-r--r-- | lib/libthr/arch/i386/i386/_setcurthread.c | 101 |
2 files changed, 29 insertions, 74 deletions
diff --git a/lib/libthr/arch/i386/i386/_curthread.S b/lib/libthr/arch/i386/i386/_curthread.S index 1f11f88..eb658df 100644 --- a/lib/libthr/arch/i386/i386/_curthread.S +++ b/lib/libthr/arch/i386/i386/_curthread.S @@ -5,7 +5,7 @@ ENTRY(_get_curthread) cmpl $0, _thread_initial je nothreads - movl %gs:0, %eax + movl %gs:8, %eax ret nothreads: xor %eax, %eax diff --git a/lib/libthr/arch/i386/i386/_setcurthread.c b/lib/libthr/arch/i386/i386/_setcurthread.c index 4dd0d03..0ff4ff6 100644 --- a/lib/libthr/arch/i386/i386/_setcurthread.c +++ b/lib/libthr/arch/i386/i386/_setcurthread.c @@ -38,112 +38,67 @@ #include <machine/segments.h> #include "thr_private.h" - -#define MAXTHR 8192 - -#define LDT_INDEX(x) (((long)(x) - (long)ldt_entries) / sizeof(ldt_entries[0])) - -void **ldt_free = NULL; -void *ldt_entries[MAXTHR]; -static int ldt_inited = 0; -static spinlock_t ldt_lock = _SPINLOCK_INITIALIZER; - -static void ldt_init(void); +#include "rtld_tls.h" /* in _curthread.S */ extern void _set_gs(int); -/* - * Initialize the array of ldt_entries and the next free slot. - * This routine must be called with the global ldt lock held. - */ -static void -ldt_init(void) -{ - int i; - - ldt_free = &ldt_entries[NLDT]; - - for (i = 0; i < MAXTHR - 1; i++) - ldt_entries[i] = (void *)&ldt_entries[i + 1]; - - ldt_entries[MAXTHR - 1] = NULL; - - ldt_inited = 1; -} +struct tcb { + struct tcb *tcb_self; /* required by rtld */ + void *tcb_dtv; /* required by rtld */ + struct pthread *tcb_thread; +}; void _retire_thread(void *entry) { - _spinlock(&ldt_lock); - if (ldt_free == NULL) - *(void **)entry = NULL; - else - *(void **)entry = *ldt_free; - ldt_free = entry; - _spinunlock(&ldt_lock); + _rtld_free_tls(entry, sizeof(struct tcb), 16); + /* XXX free ldt descriptor here */ } void * _set_curthread(ucontext_t *uc, struct pthread *thr, int *err) { union descriptor desc; - void **ldt_entry; + struct tcb *tcb; + void *oldtls; int ldt_index; *err = 0; - /* - * If we are setting up the initial thread, the gs register - * won't be setup for the current thread. In any case, we - * don't need protection from re-entrancy at this point in - * the life of the program. - */ - if (thr != _thread_initial) - _SPINLOCK(&ldt_lock); - - if (ldt_inited == 0) - ldt_init(); - - if (ldt_free == NULL) { - /* Concurrent thread limit reached */ - *err = curthread->error = EAGAIN; - if (thr != _thread_initial) - _SPINUNLOCK(&ldt_lock); - return (NULL); + if (uc == NULL) { + __asm __volatile("movl %%gs:0, %0" : "=r" (oldtls)); + } else { + oldtls = NULL; } /* - * Pull one off of the free list and update the free list pointer. + * Allocate and initialise a new TLS block with enough extra + * space for our self pointer. */ - ldt_entry = ldt_free; - ldt_free = (void **)*ldt_entry; - - if (thr != _thread_initial) - _SPINUNLOCK(&ldt_lock); + tcb = _rtld_allocate_tls(oldtls, sizeof(struct tcb), 16); /* - * Cache the address of the thread structure here. This is - * what the gs register will point to. + * Cache the address of the thread structure here, after + * rtld's two words of private space. */ - *ldt_entry = (void *)thr; + tcb->tcb_thread = thr; bzero(&desc, sizeof(desc)); /* - * Set up the descriptor to point into the ldt table which contains - * only a pointer to the thread. + * Set up the descriptor to point at the TLS block. */ - desc.sd.sd_lolimit = sizeof(*ldt_entry); - desc.sd.sd_lobase = (unsigned int)ldt_entry & 0xFFFFFF; - desc.sd.sd_type = SDT_MEMRO; + desc.sd.sd_lolimit = 0xFFFF; + desc.sd.sd_lobase = (unsigned int)tcb & 0xFFFFFF; + desc.sd.sd_type = SDT_MEMRW; desc.sd.sd_dpl = SEL_UPL; desc.sd.sd_p = 1; - desc.sd.sd_hilimit = 0; + desc.sd.sd_hilimit = 0xF; desc.sd.sd_xx = 0; desc.sd.sd_def32 = 1; - desc.sd.sd_gran = 0; - desc.sd.sd_hibase = (unsigned int)ldt_entry >> 24; + desc.sd.sd_gran = 1; + desc.sd.sd_hibase = (unsigned int)tcb >> 24; /* Get a slot from the process' LDT list */ ldt_index = i386_set_ldt(LDT_AUTO_ALLOC, &desc, 1); @@ -158,5 +113,5 @@ _set_curthread(ucontext_t *uc, struct pthread *thr, int *err) else _set_gs(LSEL(ldt_index, SEL_UPL)); - return (ldt_entry); + return (tcb); } |