Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 5 Aug 2003 21:59:52 -0400 (EDT)
From:      Daniel Eischen <eischen@vigrid.com>
To:        Julian Elischer <julian@elischer.org>
Cc:        freebsd-threads@freebsd.org
Subject:   Re: cvs commit: src/sys/i386/i386 sys_machdep.c
Message-ID:  <Pine.GSO.4.10.10308052123130.25125-100000@pcnet5.pcnet.com>
In-Reply-To: <Pine.BSF.4.21.0308051802500.82100-100000@InterJet.elischer.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On Tue, 5 Aug 2003, Julian Elischer wrote:

> 
> 
> On Tue, 5 Aug 2003, Daniel Eischen wrote:
> 
> > On Tue, 5 Aug 2003, Julian Elischer wrote:
> > 
> > > Warning warning warning....
> > > 
> > > The code that Dan shows ends up pointing %gs to the struct pthread
> > > structure.. however the ELF i386 (and amd64) ABI for TLS assumes that it
> > > points to a POINTER to the TCB (is that the same thing?). If the TCB
> > > (Thread control block) is the same thing as the struct pthread then you
> > > should probably make the first entry be a pointer to istelf or the TLS
> > > code generated by the linker (when enabled) will point to the wrong
> > > thing..
> > 
> > For libthr, the struct pthread isn't really the thread control
> > block.  struct pthread is MI, so you can't rely on it having
> > a layout that will satisfy all the ABIs.  It isn't correct
> > now for i386.
> > 
> > libthr will likely need the same sort of arch-dependent
> > hooks that libpthread just grew (minus the struct kcb
> > stuff).  The patch I posted just addresses auto-ldt
> > allocation.
> > 
> > > 
> > > With the array there is now it just happens to come out right.
> > 
> > But it doesn't really, since the first slot of struct pthread
> > is not a pointer to the dynamic TLS.
> 
> the i386 TLS spec doesn;t say it needs to be..
> 
> 
> What it says is:
> %gs references a LDT entry that defines a segment, the forst word of
> which is a pointer to the Thread Control block, which, at a known 
> offset (defined by a symbol), contains a pointer to the TLS vector
> array.
> 
> This is satisfied now because %gs defiens a sebment that starts at one
> of the array entries in that array, and each array entry holds a pointer
> to the associated thread control block (struct pthread) which could hold
> a pointer to the TLS vector is it was added there..

Well, it could for i386, but that doesn't hold water for
other archs.  Like I said, struct pthread is MI.  I don't
think you can satisfy all the ABIs with one layout of the
MI struct pthread.  Whatever is ABI-dependent should be
independent of struct pthread.

You could modify the current ldt entries in libthr so
that they do contain the necessary dynamic and static
TLS, and that would be fine.  I just didn't worry about
addressing it because it wasn't currently setup to handle
it, and I didn't think it was necessary at this point.

Here's a second pass that tries to handle the i386 ABI
needs.  There's no caching of old entries, but if you
cache threads, you get the same effect and all archs
benefit.

-- 
Dan Eischen

Index: arch/i386/i386/_curthread.S
===================================================================
RCS file: /opt/FreeBSD/cvs/src/lib/libthr/arch/i386/i386/_curthread.S,v
retrieving revision 1.2
diff -u -r1.2 _curthread.S
--- arch/i386/i386/_curthread.S	2 Jun 2003 02:32:56 -0000	1.2
+++ arch/i386/i386/_curthread.S	6 Aug 2003 01:52:29 -0000
@@ -6,6 +6,7 @@
 	cmpl	$0, _thread_initial
 	je	nothreads
 	movl	%gs:0, %eax
+	movl	4(%eax), %eax
 	ret
 nothreads:
 	xor	%eax, %eax
Index: arch/i386/i386/_setcurthread.c
===================================================================
RCS file: /opt/FreeBSD/cvs/src/lib/libthr/arch/i386/i386/_setcurthread.c,v
retrieving revision 1.10
diff -u -r1.10 _setcurthread.c
--- arch/i386/i386/_setcurthread.c	29 Jun 2003 00:12:39 -0000	1.10
+++ arch/i386/i386/_setcurthread.c	6 Aug 2003 01:53:40 -0000
@@ -39,105 +39,64 @@
 
 #include "thr_private.h"
 
-#define	MAXTHR	128
-
-#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);
 
+struct tcb {
+	struct tdv	*tdv;		/* dynamic TLS */
+	struct pthread	*thread;
+	/* static TLS ??? */
+};
+
 /*
- * Initialize the array of ldt_entries and the next free slot.
- * This routine must be called with the global ldt lock held.
+ * %gs points to one of these.
  */
-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];
+struct ldt_entry {
+	struct tcb	*self;	/* points to tcb */
+	int		ldt;
+	struct tcb	tcb;
+};
 
-	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);
+	struct ldt_entry *ldt;
+
+	ldt = (struct ldt_entry *)entry;
+	if (ldt != NULL) {
+		if (ldt->ldt >= 0) {
+			i386_set_ldt(ldt->ldt, NULL, 1);
+			ldt->ldt = -1;	/* just in case */
+		}
+		free(ldt);
+	}
 }
 
+
 void *
 _set_curthread(ucontext_t *uc, struct pthread *thr, int *err)
 {
 	union descriptor desc;
-	void **ldt_entry;
-	int ldt_index;
-	int error;
+	struct ldt_entry *entry;
 
 	*err = 0;
+	bzero(&desc, sizeof(desc));
 
-	/*
-	 * 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 == NULL)
-		ldt_init();
-
-	if (ldt_free == NULL) {
-		/* Concurrent thread limit reached */
-		*err = curthread->error = EAGAIN;
-		if (thr != _thread_initial)
-			_SPINUNLOCK(&ldt_lock);
+	if ((entry = malloc(sizeof(entry))) == NULL) {
+		*err = EAGAIN;
 		return (NULL);
 	}
-
-	/*
-	 * Pull one off of the free list and update the free list pointer.
-	 */
-	ldt_entry = ldt_free;
-	ldt_free = (void **)*ldt_entry;
-
-	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;
-	ldt_index = LDT_INDEX(ldt_entry);
-
-	bzero(&desc, sizeof(desc));
+	bzero(entry, sizeof(entry));
+	entry->self = &entry->tcb;	/* set up self reference */
+	entry->tcb.thread = thr;
 
 	/*
 	 * Set up the descriptor to point into the ldt table which contains
 	 * only a pointer to the thread.
 	 */
-	desc.sd.sd_lolimit = sizeof(*ldt_entry);
-	desc.sd.sd_lobase = (unsigned int)ldt_entry & 0xFFFFFF;
+	desc.sd.sd_lolimit = sizeof(*entry);
+	desc.sd.sd_lobase = (unsigned int)entry & 0xFFFFFF;
 	desc.sd.sd_type = SDT_MEMRO;
 	desc.sd.sd_dpl = SEL_UPL;
 	desc.sd.sd_p = 1;
@@ -145,19 +104,20 @@
 	desc.sd.sd_xx = 0;
 	desc.sd.sd_def32 = 1;
 	desc.sd.sd_gran = 0;
-	desc.sd.sd_hibase = (unsigned int)ldt_entry >> 24;
-
-	error = i386_set_ldt(ldt_index, &desc, 1);
-	if (error == -1)
-		abort(); 
+	desc.sd.sd_hibase = (unsigned int)entry >> 24;
 
-	/*
-	 * Set up our gs with the index into the ldt for this entry.
-	 */
-	if (uc != NULL)
-		uc->uc_mcontext.mc_gs = LSEL(ldt_index, SEL_UPL);
-	else
-		_set_gs(LSEL(ldt_index, SEL_UPL));
-
-	return (ldt_entry);
+	entry->ldt = i386_set_ldt(LDT_AUTO_ALLOC, &desc, 1);
+	if (entry->ldt < 0) {
+		*err = EAGAIN;
+		free(entry);
+	} else {
+		/*
+		 * Set up our gs with the ldt index.
+		 */
+		if (uc != NULL)
+			uc->uc_mcontext.mc_gs = LSEL(entry->ldt, SEL_UPL);
+		else
+			_set_gs(LSEL(entry->ldt, SEL_UPL));
+	}
+	return ((void *)entry);
 }




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.GSO.4.10.10308052123130.25125-100000>