From owner-freebsd-threads@FreeBSD.ORG Thu Aug 5 08:40:46 2004 Return-Path: Delivered-To: freebsd-threads@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 300CF16A4CE for ; Thu, 5 Aug 2004 08:40:46 +0000 (GMT) Received: from itchy.rabson.org (mailgate.nlsystems.com [80.177.232.242]) by mx1.FreeBSD.org (Postfix) with ESMTP id B377343D2D for ; Thu, 5 Aug 2004 08:40:44 +0000 (GMT) (envelope-from dfr@nlsystems.com) Received: from ns0.nlsystems.com (ns0.nlsystems.com [80.177.232.243]) by itchy.rabson.org (8.12.11/8.12.11) with ESMTP id i758ed7Z025335 for ; Thu, 5 Aug 2004 09:40:39 +0100 (BST) (envelope-from dfr@nlsystems.com) From: Doug Rabson To: freebsd-threads@freebsd.org Date: Thu, 5 Aug 2004 09:40:36 +0100 User-Agent: KMail/1.6.2 MIME-Version: 1.0 Content-Disposition: inline Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Message-Id: <200408050940.36506.dfr@nlsystems.com> X-Spam-Status: No, hits=0.0 required=5.0 tests=none autolearn=no version=2.63 X-Spam-Checker-Version: SpamAssassin 2.63 (2004-01-11) on itchy.rabson.org X-Virus-Scanned: clamd / ClamAV version 0.71, clamav-milter version 0.71 X-Virus-Status: Clean Subject: Pthread patches for TLS X-BeenThere: freebsd-threads@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Threading on FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 05 Aug 2004 08:40:46 -0000 This is the current state of my patches to add TLS support to libpthread and libthr. I have added code for i386, amd64 and ia64 but I've only tested i386. I believe the code for amd64 is right. I don't much like what I've done to the ia64 version though. I would like to commit only the i386 version at this stage. The amd64 code could be committed if someone tests it. The current code in rtld for variant I TLS assumes that the size of the TCB is fixed at 2*sizeof(Elf_Addr). The original code in libpthread assumed that it was possible to extend that by allocating extra storage to live below the thread pointer. Since I don't support that in rtld, I've just allocated the extra space with malloc() and used the spare pointer in the architecturally defined TCB to point at it. This could be fixed in two ways. The first (which requires no changes to rtld) would be to add a '__thread struct tcp _pthread_tcb' variable and arrange for ia64_tp::tp_tcp to point at that in each thread. The advantage there is that rtld stays simple. The alternative is to change the semantics of _rtld_allocate_tls() for variant I to allow the caller to request a larger tcb size - it would allocate the extra space below the 16 byte architectural TCB. Trying out either of these will have to wait until I have time to fire up my horrible noisy old itanium1 system and update it to current. Index: libthr/arch/i386/i386/_curthread.S =================================================================== RCS file: /home/ncvs/src/lib/libthr/arch/i386/i386/_curthread.S,v retrieving revision 1.2 diff -u -r1.2 _curthread.S --- libthr/arch/i386/i386/_curthread.S 2 Jun 2003 02:32:56 -0000 1.2 +++ libthr/arch/i386/i386/_curthread.S 5 Aug 2004 08:17:40 -0000 @@ -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 Index: libthr/arch/i386/i386/_setcurthread.c =================================================================== RCS file: /home/ncvs/src/lib/libthr/arch/i386/i386/_setcurthread.c,v retrieving revision 1.13 diff -u -r1.13 _setcurthread.c --- libthr/arch/i386/i386/_setcurthread.c 5 Mar 2004 08:10:18 -0000 1.13 +++ libthr/arch/i386/i386/_setcurthread.c 5 Aug 2004 08:17:40 -0000 @@ -38,112 +38,67 @@ #include #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 @@ else _set_gs(LSEL(ldt_index, SEL_UPL)); - return (ldt_entry); + return (tcb); } Index: libthr/arch/ia64/ia64/_curthread.c =================================================================== RCS file: /home/ncvs/src/lib/libthr/arch/ia64/ia64/_curthread.c,v retrieving revision 1.3 diff -u -r1.3 _curthread.c --- libthr/arch/ia64/ia64/_curthread.c 25 May 2003 22:40:57 -0000 1.3 +++ libthr/arch/ia64/ia64/_curthread.c 5 Aug 2004 08:22:06 -0000 @@ -33,27 +33,38 @@ #include #include "thr_private.h" -register struct pthread *_tp __asm("%r13"); +struct tcb { + void *tcb_dtv; + struct pthread *tcb_thread; +}; + +register struct tcb *_tp __asm("%r13"); struct pthread * _get_curthread(void) { - return (_tp); + return (_tp->tcb_thread); } void _retire_thread(void *v) { + + _rtld_free_tls(v, sizeof(struct tcb), 16); } void * _set_curthread(ucontext_t *uc, struct pthread *thread, int *err) { + struct tcb *tcb; + + tcb = _rtld_allocate_tls(sizeof(struct tcb), 16); + tcb->tcb_thread = thread; *err = 0; if (uc != NULL) - uc->uc_mcontext.mc_special.tp = (uint64_t)thread; + uc->uc_mcontext.mc_special.tp = (uint64_t)tcb; else - _tp = thread; - return (NULL); + _tp = tcb; + return (tcb); } Index: libpthread/arch/amd64/amd64/pthread_md.c =================================================================== RCS file: /home/ncvs/src/lib/libpthread/arch/amd64/amd64/pthread_md.c,v retrieving revision 1.2 diff -u -r1.2 pthread_md.c --- libpthread/arch/amd64/amd64/pthread_md.c 12 Aug 2003 22:13:06 -0000 1.2 +++ libpthread/arch/amd64/amd64/pthread_md.c 5 Aug 2004 08:27:37 -0000 @@ -28,29 +28,37 @@ #include #include +#include "rtld_tls.h" #include "pthread_md.h" /* * The constructors. */ struct tcb * -_tcb_ctor(struct pthread *thread) +_tcb_ctor(struct pthread *thread, int initial) { struct tcb *tcb; + void *oldtls; - if ((tcb = malloc(sizeof(struct tcb))) != NULL) { - bzero(tcb, sizeof(struct tcb)); + if (initial) { + __asm __volatile("movq %%fs:0, %0" : "=r" (oldtls)); + } else { + oldtls = NULL; + } + + tcb = _rtld_allocate_tls(oldtls, sizeof(struct tcb), 16); + if (tcb) { tcb->tcb_thread = thread; - /* Allocate TDV */ + bzero(&tcb->tcb_tmbx, sizeof(tcb->tcb_tmbx)); } + return (tcb); } void _tcb_dtor(struct tcb *tcb) { - /* Free TDV */ - free(tcb); + _rtld_free_tls(tcb, sizeof(struct tcb), 16); } struct kcb * Index: libpthread/arch/amd64/include/pthread_md.h =================================================================== RCS file: /home/ncvs/src/lib/libpthread/arch/amd64/include/pthread_md.h,v retrieving revision 1.7 diff -u -r1.7 pthread_md.h --- libpthread/arch/amd64/include/pthread_md.h 31 Jul 2004 14:14:55 -0000 1.7 +++ libpthread/arch/amd64/include/pthread_md.h 5 Aug 2004 08:27:02 -0000 @@ -62,8 +62,10 @@ }; 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_spare[1]; /* align tcb_tmbx to 16 bytes */ struct kse_thr_mailbox tcb_tmbx; }; @@ -138,7 +140,7 @@ /* * The constructors. */ -struct tcb *_tcb_ctor(struct pthread *); +struct tcb *_tcb_ctor(struct pthread *, int); void _tcb_dtor(struct tcb *tcb); struct kcb *_kcb_ctor(struct kse *); void _kcb_dtor(struct kcb *); Index: libpthread/arch/i386/i386/pthread_md.c =================================================================== RCS file: /home/ncvs/src/lib/libpthread/arch/i386/i386/pthread_md.c,v retrieving revision 1.2 diff -u -r1.2 pthread_md.c --- libpthread/arch/i386/i386/pthread_md.c 5 Aug 2003 23:09:22 -0000 1.2 +++ libpthread/arch/i386/i386/pthread_md.c 5 Aug 2004 08:27:24 -0000 @@ -39,35 +39,35 @@ #include #include +#include "rtld_tls.h" #include "pthread_md.h" struct tcb * -_tcb_ctor(struct pthread *thread) +_tcb_ctor(struct pthread *thread, int initial) { struct tcb *tcb; - void *addr; + void *oldtls; - 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; + if (initial) { + __asm __volatile("movl %%gs:0, %0" : "=r" (oldtls)); + } else { + oldtls = NULL; + } + + tcb = _rtld_allocate_tls(oldtls, 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); } /* Index: libpthread/arch/i386/include/pthread_md.h =================================================================== RCS file: /home/ncvs/src/lib/libpthread/arch/i386/include/pthread_md.h,v retrieving revision 1.8 diff -u -r1.8 pthread_md.h --- libpthread/arch/i386/include/pthread_md.h 13 Jul 2004 22:54:23 -0000 1.8 +++ libpthread/arch/i386/include/pthread_md.h 5 Aug 2004 08:26:51 -0000 @@ -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; }; @@ -140,7 +139,7 @@ /* * The constructors. */ -struct tcb *_tcb_ctor(struct pthread *); +struct tcb *_tcb_ctor(struct pthread *, int); void _tcb_dtor(struct tcb *tcb); struct kcb *_kcb_ctor(struct kse *); void _kcb_dtor(struct kcb *); Index: libpthread/arch/ia64/ia64/pthread_md.c =================================================================== RCS file: /home/ncvs/src/lib/libpthread/arch/ia64/ia64/pthread_md.c,v retrieving revision 1.2 diff -u -r1.2 pthread_md.c --- libpthread/arch/ia64/ia64/pthread_md.c 6 Aug 2003 04:17:42 -0000 1.2 +++ libpthread/arch/ia64/ia64/pthread_md.c 5 Aug 2004 08:27:46 -0000 @@ -29,19 +29,25 @@ #include #include #include "pthread_md.h" +#include "rtld_tls.h" /* * The constructors. */ struct tcb * -_tcb_ctor(struct pthread *thread) +_tcb_ctor(struct pthread *thread, int initial) { - struct tcb *tcb; + struct ia64_tp *tp; + + tp = _rtld_allocate_tls(initial ? _tp : NULL, + sizeof(struct ia64_tp), 16); + if (tp == NULL) + return (NULL); if ((tcb = malloc(sizeof(struct tcb))) != NULL) { bzero(tcb, sizeof(struct tcb)); tcb->tcb_thread = thread; - /* Allocate TDV */ + tcb->tcb_tp = tp; } return (tcb); } @@ -49,7 +55,8 @@ void _tcb_dtor(struct tcb *tcb) { - /* Free TDV */ + + _rtld_free_tls(tcb->tcb_tp, sizeof(struct ia64_tp), 16); free(tcb); } Index: libpthread/arch/ia64/include/pthread_md.h =================================================================== RCS file: /home/ncvs/src/lib/libpthread/arch/ia64/include/pthread_md.h,v retrieving revision 1.13 diff -u -r1.13 pthread_md.h --- libpthread/arch/ia64/include/pthread_md.h 12 Jul 2004 07:41:01 -0000 1.13 +++ libpthread/arch/ia64/include/pthread_md.h 5 Aug 2004 08:27:08 -0000 @@ -44,19 +44,13 @@ struct kse; struct pthread; struct tcb; -struct tdv; /* We don't know what this is yet? */ /* - * tp points to one of these. We define the static TLS as an array - * of long double to enforce 16-byte alignment of the TLS memory, - * struct ia64_tp, struct tcb and also struct kcb. Both static and - * dynamic allocation of any of these structures will result in a - * valid, well-aligned thread pointer. + * tp points to one of these. */ struct ia64_tp { - struct tdv *tp_tdv; /* dynamic TLS */ - uint64_t _reserved_; - long double tp_tls[0]; /* static TLS */ + void *tp_dtv; /* required by rtld */ + struct tcb *tp_tcb; /* real tcb for thread */ }; struct tcb { @@ -64,7 +58,7 @@ struct pthread *tcb_thread; struct kcb *tcb_curkcb; long tcb_isfake; - struct ia64_tp tcb_tp; + struct ia64_tp *tcb_tp; }; struct kcb { @@ -76,12 +70,12 @@ register struct ia64_tp *_tp __asm("%r13"); -#define _tcb ((struct tcb*)((char*)(_tp) - offsetof(struct tcb, tcb_tp))) +#define _tcb (_tp->tp_tcb) /* * The kcb and tcb constructors. */ -struct tcb *_tcb_ctor(struct pthread *); +struct tcb *_tcb_ctor(struct pthread *, int); void _tcb_dtor(struct tcb *); struct kcb *_kcb_ctor(struct kse *kse); void _kcb_dtor(struct kcb *); @@ -90,8 +84,6 @@ static __inline void _kcb_set(struct kcb *kcb) { - /* There is no thread yet; use the fake tcb. */ - _tp = &kcb->kcb_faketcb.tcb_tp; } /* @@ -103,6 +95,7 @@ static __inline struct kcb * _kcb_get(void) { + return (_tcb->tcb_curkcb); } @@ -165,22 +158,25 @@ static __inline void _tcb_set(struct kcb *kcb, struct tcb *tcb) { + if (tcb == NULL) tcb = &kcb->kcb_faketcb; kcb->kcb_curtcb = tcb; tcb->tcb_curkcb = kcb; - _tp = &tcb->tcb_tp; + _tp = tcb->tcb_tp; } static __inline struct tcb * _tcb_get(void) { + return (_tcb); } static __inline struct pthread * _get_curthread(void) { + return (_tcb->tcb_thread); } @@ -204,6 +200,7 @@ static __inline int _thread_enter_uts(struct tcb *tcb, struct kcb *kcb) { + if (_ia64_save_context(&tcb->tcb_tmbx.tm_context.uc_mcontext) == 0) { /* Make the fake tcb the current thread. */ kcb->kcb_curtcb = &kcb->kcb_faketcb; Index: libpthread/thread/thr_kern.c =================================================================== RCS file: /home/ncvs/src/lib/libpthread/thread/thr_kern.c,v retrieving revision 1.108 diff -u -r1.108 thr_kern.c --- libpthread/thread/thr_kern.c 3 Aug 2004 02:22:25 -0000 1.108 +++ libpthread/thread/thr_kern.c 5 Aug 2004 08:29:54 -0000 @@ -2384,7 +2384,7 @@ if ((thread == NULL) && ((thread = malloc(sizeof(struct pthread))) != NULL)) { bzero(thread, sizeof(struct pthread)); - if ((thread->tcb = _tcb_ctor(thread)) == NULL) { + if ((thread->tcb = _tcb_ctor(thread, curthread == NULL)) == NULL) { free(thread); thread = NULL; } else {