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