Date: Mon, 5 Apr 2004 08:33:30 -0700 (PDT) From: Doug Rabson <dfr@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 50408 for review Message-ID: <200404051533.i35FXUjd018384@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=50408 Change 50408 by dfr@dfr_home on 2004/04/05 08:33:17 Wire up the TLS stuff to the thread libraries (i386 only). Affected files ... .. //depot/projects/kse/lib/libpthread/arch/i386/i386/pthread_md.c#2 edit .. //depot/projects/kse/lib/libpthread/arch/i386/include/pthread_md.h#2 edit .. //depot/projects/kse/lib/libthr/Makefile#2 edit .. //depot/projects/kse/lib/libthr/arch/i386/i386/_curthread.S#2 edit .. //depot/projects/kse/lib/libthr/arch/i386/i386/_setcurthread.c#2 edit .. //depot/projects/kse/libexec/rtld-elf/i386/reloc.c#4 edit .. //depot/projects/kse/libexec/rtld-elf/i386/rtld_machdep.h#5 edit .. //depot/projects/kse/libexec/rtld-elf/rtld.c#6 edit .. //depot/projects/kse/libexec/rtld-elf/rtld.h#4 edit .. //depot/projects/kse/libexec/rtld-elf/rtld_tls.h#1 add .. //depot/projects/kse/tools/regression/tls/Makefile#2 edit .. //depot/projects/kse/tools/regression/tls/ttls2/Makefile#1 add .. //depot/projects/kse/tools/regression/tls/ttls2/ttls2.c#1 add Differences ... ==== //depot/projects/kse/lib/libpthread/arch/i386/i386/pthread_md.c#2 (text+ko) ==== @@ -39,35 +39,28 @@ #include <string.h> #include <ucontext.h> +#include "rtld_tls.h" #include "pthread_md.h" struct tcb * _tcb_ctor(struct pthread *thread) { struct tcb *tcb; - void *addr; - addr = malloc(sizeof(struct tcb) + 15); - if (addr == NULL) - tcb = NULL; - else { - tcb = (struct tcb *)(((uintptr_t)(addr) + 15) & ~15); - bzero(tcb, sizeof(struct tcb)); - tcb->tcb_addr = addr; + tcb = _rtld_allocate_tls(sizeof(struct tcb), 16); + if (tcb) { tcb->tcb_thread = thread; - /* XXX - Allocate tdv/tls */ + tcb->tcb_spare = 0; + bzero(&tcb->tcb_tmbx, sizeof(tcb->tcb_tmbx)); } + return (tcb); } void _tcb_dtor(struct tcb *tcb) { - void *addr; - - addr = tcb->tcb_addr; - tcb->tcb_addr = NULL; - free(addr); + _rtld_free_tls(tcb, sizeof(struct tcb), 16); } /* ==== //depot/projects/kse/lib/libpthread/arch/i386/include/pthread_md.h#2 (text+ko) ==== @@ -47,7 +47,6 @@ struct kse; struct pthread; -struct tdv; /* * %gs points to a struct kcb. @@ -61,9 +60,9 @@ }; struct tcb { - struct tdv *tcb_tdv; + struct tcb *tcb_self; /* required by rtld */ + void *tcb_dtv; /* required by rtld */ struct pthread *tcb_thread; - void *tcb_addr; /* allocated tcb address */ void *tcb_spare; /* align tcb_tmbx to 16 bytes */ struct kse_thr_mailbox tcb_tmbx; }; ==== //depot/projects/kse/lib/libthr/Makefile#2 (text+ko) ==== @@ -13,6 +13,7 @@ CFLAGS+=-DPTHREAD_KERNEL -D_THREAD_SAFE CFLAGS+=-I${.CURDIR}/../libc/include -I${.CURDIR}/thread \ -I${.CURDIR}/../../include +CFLAGS+=-I${.CURDIR}/../../libexec/rtld-elf # enable extra internal consistancy checks CFLAGS+=-D_PTHREADS_INVARIANTS ==== //depot/projects/kse/lib/libthr/arch/i386/i386/_curthread.S#2 (text+ko) ==== @@ -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 ==== //depot/projects/kse/lib/libthr/arch/i386/i386/_setcurthread.c#2 (text+ko) ==== @@ -38,112 +38,60 @@ #include <machine/segments.h> #include "thr_private.h" - -#define MAXTHR 8192 +#include "rtld_tls.h" -#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); - /* 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; +struct tcb { + struct tcb *tcb_self; /* required by rtld */ + void *tcb_dtv; /* required by rtld */ + struct pthread *tcb_thread; +}; - 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; -} - 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; 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. + * Allocate and initialise a new TLS block with enough extra + * space for our self pointer. */ - if (thr != _thread_initial) - _SPINLOCK(&ldt_lock); + tcb = _rtld_allocate_tls(sizeof(struct tcb), 16); - 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); - } - /* - * Pull one off of the free list and update the free list pointer. + * Cache the address of the thread structure here, after + * rtld's two words of private space. */ - ldt_entry = ldt_free; - ldt_free = (void **)*ldt_entry; + tcb->tcb_thread = thr; - if (thr != _thread_initial) - _SPINUNLOCK(&ldt_lock); - - /* - * Cache the address of the thread structure here. This is - * what the gs register will point to. - */ - *ldt_entry = (void *)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 +106,5 @@ else _set_gs(LSEL(ldt_index, SEL_UPL)); - return (ldt_entry); + return (tcb); } ==== //depot/projects/kse/libexec/rtld-elf/i386/reloc.c#4 (text+ko) ==== @@ -332,24 +332,26 @@ return 0; } -void -allocate_initial_tls(Obj_Entry *list) +void * +allocate_tls(Objlist* list, size_t tcbsize, size_t tcbalign) { + Objlist_Entry *entry; Obj_Entry *obj; size_t size; char *tls; Elf_Addr *dtv; - union descriptor ldt; Elf_Addr segbase; - int sel; size = 0; - for (obj = list; obj; obj = obj->next) { + STAILQ_FOREACH(entry, list, link) { + obj = entry->obj; if (obj->tlsoffset > size) size = obj->tlsoffset; } + size = round(size, tcbalign); - tls = malloc(size + 2*sizeof(Elf_Addr)); + assert(tcbsize >= 2*sizeof(Elf_Addr)); + tls = malloc(size + tcbsize); dtv = malloc((tls_max_index + 2) * sizeof(Elf_Addr)); segbase = (Elf_Addr)(tls + size); @@ -358,7 +360,8 @@ dtv[0] = tls_dtv_generation; dtv[1] = tls_max_index; - for (obj = list; obj; obj = obj->next) { + STAILQ_FOREACH(entry, list, link) { + obj = entry->obj; Elf_Addr addr = segbase - obj->tlsoffset; memset((void*) (addr + obj->tlsinitsize), 0, obj->tlssize - obj->tlsinitsize); @@ -367,16 +370,61 @@ dtv[obj->tlsindex] = addr; } + return (void*) segbase; +} + +void +free_tls(Objlist *list, void *tls, size_t tcbsize, size_t tcbalign) +{ + Objlist_Entry *entry; + Obj_Entry *obj; + size_t size; + Elf_Addr* dtv; + int dtvsize, i; + Elf_Addr tlsstart, tlsend; + + /* + * Figure out the size of the initial TLS block so that we can + * find stuff which ___tls_get_addr() allocated dynamically. + */ + size = 0; + STAILQ_FOREACH(entry, list, link) { + obj = entry->obj; + if (obj->tlsoffset > size) + size = obj->tlsoffset; + } + size = round(size, tcbalign); + + dtv = ((Elf_Addr**)tls)[1]; + dtvsize = dtv[1]; + tlsend = (Elf_Addr) tls; + tlsstart = tlsend - size; + for (i = 0; i < dtvsize; i++) { + if (dtv[i+2] < tlsstart || dtv[i+2] > tlsend) { + free((void*) dtv[i+2]); + } + } + + free((void*) tlsstart); +} + +void +allocate_initial_tls(Objlist *list) +{ + void* tls = allocate_tls(list, 2*sizeof(Elf_Addr), 4); + union descriptor ldt; + int sel; + memset(&ldt, 0, sizeof(ldt)); ldt.sd.sd_lolimit = 0xffff; /* 4G limit */ - ldt.sd.sd_lobase = segbase & 0xffffff; + ldt.sd.sd_lobase = ((Elf_Addr)tls) & 0xffffff; ldt.sd.sd_type = SDT_MEMRWA; ldt.sd.sd_dpl = SEL_UPL; ldt.sd.sd_p = 1; /* present */ ldt.sd.sd_hilimit = 0xf; /* 4G limit */ ldt.sd.sd_def32 = 1; /* 32 bit */ ldt.sd.sd_gran = 1; /* limit in pages */ - ldt.sd.sd_hibase = (segbase >> 24) & 0xff; + ldt.sd.sd_hibase = (((Elf_Addr)tls) >> 24) & 0xff; sel = i386_set_ldt(LDT_AUTO_ALLOC, &ldt, 1); __asm __volatile("movl %0,%%gs" : : "rm" ((sel << 3) | 7)); } ==== //depot/projects/kse/libexec/rtld-elf/i386/rtld_machdep.h#5 (text+ko) ==== ==== //depot/projects/kse/libexec/rtld-elf/rtld.c#6 (text+ko) ==== @@ -53,6 +53,7 @@ #include "debug.h" #include "rtld.h" #include "libmap.h" +#include "rtld_tls.h" #ifndef COMPAT_32BIT #define PATH_RTLD "/libexec/ld-elf.so.1" @@ -182,6 +183,8 @@ (func_ptr_type) &___tls_get_addr, #endif (func_ptr_type) &__tls_get_addr, + (func_ptr_type) &_rtld_allocate_tls, + (func_ptr_type) &_rtld_free_tls, NULL }; @@ -404,7 +407,7 @@ /* setup TLS for main thread */ dbg("initializing initial thread local storage"); - allocate_initial_tls(obj_list); + allocate_initial_tls(&list_main); /* Make a list of init functions to call. */ objlist_init(&initlist); @@ -2486,7 +2489,7 @@ /* Dynamically allocate module TLS if necessary */ if (!dtv[index + 1]) - dtv[index + 1] = (Elf_Addr)allocate_tls(index); + dtv[index + 1] = (Elf_Addr)allocate_module_tls(index); return (void*) (dtv[index + 1] + offset); } @@ -2495,7 +2498,7 @@ * Allocate TLS block for module with given index. */ void * -allocate_tls(int index) +allocate_module_tls(int index) { Obj_Entry* obj; char* p; @@ -2515,3 +2518,15 @@ return p; } + +void * +_rtld_allocate_tls(size_t tcbsize, size_t tcbalign) +{ + return allocate_tls(&list_main, tcbsize, tcbalign); +} + +void +_rtld_free_tls(void *tcb, size_t tcbsize, size_t tcbalign) +{ + free_tls(&list_main, tcb, tcbsize, tcbalign); +} ==== //depot/projects/kse/libexec/rtld-elf/rtld.h#4 (text+ko) ==== @@ -229,7 +229,7 @@ const Elf_Sym *symlook_obj(const char *, unsigned long, const Obj_Entry *, bool); void *tls_get_addr_common(Elf_Addr** dtvp, int index, size_t offset); -void *allocate_tls(int index); +void *allocate_module_tls(int index); /* * MD function declarations. @@ -238,6 +238,8 @@ int reloc_non_plt(Obj_Entry *, Obj_Entry *); int reloc_plt(Obj_Entry *); int reloc_jmpslots(Obj_Entry *); -void allocate_initial_tls(Obj_Entry *); +void *allocate_tls(Objlist *, size_t, size_t); +void free_tls(Objlist *, void *, size_t, size_t); +void allocate_initial_tls(Objlist *); #endif /* } */ ==== //depot/projects/kse/tools/regression/tls/Makefile#2 (text+ko) ==== @@ -1,3 +1,3 @@ -SUBDIR=libxx libyy ttls1 +SUBDIR=libxx libyy ttls1 ttls2 .include <bsd.subdir.mk>
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200404051533.i35FXUjd018384>