cvs commit: src/sys/i386/i386 sys_machdep.c

Daniel Eischen eischen at vigrid.com
Tue Aug 5 16:44:53 PDT 2003


On Tue, 5 Aug 2003, Mike Makonnen wrote:

> On Sat, Aug 02, 2003 at 02:03:39PM -0700, Marcel Moolenaar wrote:
> > On Sat, Aug 02, 2003 at 03:52:44PM -0400, Mike Makonnen wrote:
> > > 
> > > As I indicated to Julian, I don't have time to do this now. I will
> > > be going off-line in a couple of weeks for I don't know how long.
> > > In the mean time I have a bunch of other stuff I have to get to.
> > > But, if someone else wants to do it I can tell you exactly
> > > what you need to do. It's relatively simple.
> > 
> > Can you post the description to threads@?
> > I'll see if I can find a spare moment...
> 
> When I went back over the code, to write this summary
> I found it is going to be much easier than I thought
> at first. Assuming, i386_set_ldt() returns the auto-allocated
> LDT slot we just have to load that into %gs, instead of
> the ldt_index (which points into the ldt_entries array).
> 
> So, if someone can tell me what the magic number for
> auto-allocation is I can take care of this tonight. But,
> because I'll be offline soon I'll go ahead and post
> the background on how that code works just in case someone
> needs to mess with it.
> 
> The pointers to pthread structures are kept in the array
> ldt_entries[MAX_THR]. Currently, MAX_THR is set to 128, but
> since we start at index NLDT the maximum number of simultaneous
> threads in an application is MAX_THR - NLDT. The global variable
> ldt_free is used to keep track of the next free index in the
> array. To facilitate this, when libthr is first initialized
> each entry in the array contains a pointer to the next free
> index. The ldt_free variable is then set to point to the first
> free entry in the array (ldt_entries[NLDT]) and the contents
> of that index (as preveiously stated) will be a pointer to
> the next free entry in the array (in this case
> ldt_entries[NLDT + 1]). When a new pthread is created, ldt_free
> is dereferenced to find the next empty entry. It is set to this
> entry and the contents of the previous entry it pointed to
> are overwritten with the address of the newly created pthread.
> When a thread exits the array index it occupied is overwritten
> by a pointer to ldt_free and ldt_free is pointed to the
> array index that held the just freed pthread.
> 
> Another thing that happens when a new pthread is created is that
> we setup a segment descriptor structure which points into the
> ldt_entries entry we just setup for our newly created pthread.
> This segment descripter pointing into ldt_entries is what is
> passed into i386_set_ldt(). If the call to i386_set_ldt() succeeds
> we then load the LDT index into %gs.
> 
> So, there should be no need to bump up any limits or anything
> to accomodate this change.

Code says it so much better than words.  Here's a quick attempt
to show you what is needed.  I took the liberty of simplifying
it a bit since with auto ldt allocation, I don't think there's
any need to have a predetermined number of slots (it also
eliminates the need to lock the entry array).

Watch out for any line wraps...

-- 
Dan Eischen

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	5 Aug 2003 23:36:10 -0000
@@ -39,105 +39,34 @@
 
 #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);
 
-/*
- * 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;
-}
-
 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);
+	int ldt;
+
+	ldt = (int)entry;
+	if (ldt >= 0)
+		i386_set_ldt(ldt, NULL, 1);
 }
 
 void *
 _set_curthread(ucontext_t *uc, struct pthread *thr, int *err)
 {
 	union descriptor desc;
-	void **ldt_entry;
 	int ldt_index;
-	int error;
 
 	*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 == NULL)
-		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.
-	 */
-	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));
 
 	/*
 	 * 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(*thr);
+	desc.sd.sd_lobase = (unsigned int)thr & 0xFFFFFF;
 	desc.sd.sd_type = SDT_MEMRO;
 	desc.sd.sd_dpl = SEL_UPL;
 	desc.sd.sd_p = 1;
@@ -145,19 +74,19 @@
 	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_hibase = (unsigned int)thr >> 24;
 
-	error = i386_set_ldt(ldt_index, &desc, 1);
-	if (error == -1)
-		abort(); 
-
-	/*
-	 * 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);
+	ldt_index = i386_set_ldt(LDT_AUTO_ALLOC, &desc, 1);
+	if (ldt_index < 0)
+		*err = EAGAIN;
+	else {
+		/*
+		 * Set up our gs with the ldt index.
+		 */
+		if (uc != NULL)
+			uc->uc_mcontext.mc_gs = LSEL(ldt_index, SEL_UPL);
+		else
+			_set_gs(LSEL(ldt_index, SEL_UPL));
+	}
+	return ((void *)ldt_index);
 }




More information about the freebsd-threads mailing list