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

Julian Elischer julian at elischer.org
Tue Aug 5 17:26:55 PDT 2003


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..

With the array there is now it just happens to come out right.



On Tue, 5 Aug 2003, Daniel Eischen wrote:

> 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);
>  }
> 
> 
> _______________________________________________
> freebsd-threads at freebsd.org mailing list
> http://lists.freebsd.org/mailman/listinfo/freebsd-threads
> To unsubscribe, send any mail to "freebsd-threads-unsubscribe at freebsd.org"
> 



More information about the freebsd-threads mailing list