linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [announce, patch] Thread-Local Storage (TLS) support for Linux, 2.5.28
@ 2002-07-25 17:35 Ingo Molnar
  2002-07-26 13:06 ` jlnance
  0 siblings, 1 reply; 9+ messages in thread
From: Ingo Molnar @ 2002-07-25 17:35 UTC (permalink / raw)
  To: linux-kernel; +Cc: Linus Torvalds, Ulrich Drepper, Richard Henderson


the following patch implements proper x86 TLS support in the Linux kernel,
via a new system-call, sys_set_thread_area():

   http://redhat.com/~mingo/tls-patches/tls-2.5.28-C6

a TLS test utility can be downloaded from:

    http://redhat.com/~mingo/tls-patches/tls_test.c

what is TLS? Thread Local Storage is a concept used by threading
abstractions - fast an efficient way to store per-thread local (but not
on-stack local) data. The __thread extension is already supported by gcc.

proper TLS support in compilers (and glibc/pthreads) is a bit problematic
on the x86 platform. There's only 8 general purpose registers available,
so on x86 we have to use segments to access the TLS. The approach used by
glibc so far was to set up a per-thread LDT entry to describe the TLS.
Besides the generic unrobustness of LDTs, this also introduced a limit:
the maximum number of LDT entries is 8192, so the maximum number of
threads per application is 8192.

this patch does it differently - the kernel keeps a specific per-thread
GDT entry that can be set up and modified by each thread:

     asmlinkage int sys_set_thread_area(unsigned int base,
               unsigned int limit, unsigned int flags)

the kernel, upon context-switch, modifies this GDT entry to match that of
the thread's TLS setting. This way user-space threaded code can access
per-thread data via this descriptor - by using the same, constant %gs (or
%gs) selector. The number of TLS areas is unlimited, and there is no
additional allocation overhead associated with TLS support.


the biggest problem preventing the introduction of this concept was
Linux's global shared GDT on SMP systems. The patch fixes this by
implementing a per-CPU GDT, which is also a nice context-switch speedup,
2-task lat_ctx context-switching got faster by about 5% on a dual Celeron
testbox. [ Could it be that a shared GDT is fundamentally suboptimal on
SMP? perhaps updating the 'accessed' bit in the DS/CS descriptors causes
some sort locked memory cycle overhead? ]

the GDT layout got simplified:

 *   0 - null
 *   1 - Thread-Local Storage (TLS) segment
 *   2 - kernel code segment
 *   3 - kernel data segment
 *   4 - user code segment              <==== new cacheline
 *   5 - user data segment
 *   6 - TSS
 *   7 - LDT
 *   8 - APM BIOS support               <==== new cacheline
 *   9 - APM BIOS support
 *  10 - APM BIOS support
 *  11 - APM BIOS support
 *  12 - PNPBIOS support                <==== new cacheline
 *  13 - PNPBIOS support
 *  14 - PNPBIOS support
 *  15 - PNPBIOS support
 *  16 - PNPBIOS support                <==== new cacheline
 *  17 - not used
 *  18 - not used
 *  19 - not used

set_thread_area() currently recognizes the following flags:

  #define TLS_FLAG_LIMIT_IN_PAGES         0x00000001
  #define TLS_FLAG_WRITABLE               0x00000002
  #define TLS_FLAG_CLEAR                  0x00000004

- in theory we could avoid the 'limit in pages' bit, but i wanted to
  preserve the flexibility to potentially enable the setting of
  byte-granularity stack segments for example. And unlimited segments 
  (granularity = pages, limit = 0xfffff) might have a performance
  advantage on some CPUs. We could also automatically figure out the best
  possible granularity for a given limit - but i wanted to avoid this kind
  of guesswork. Some CPUs might have a plus for page-limit segments - who
  knows.

- The 'writable' flag is straightforward and could be useful to some
  applications.

- The 'clear' flag clears the TLS. [note that a base 0 limit 0 TLS is in
  fact legal, it's a single-byte segment at address 0.]

(the system-call does not expose any other segment options to user-space,
priviledge level is 3, the segment is 32-bit, etc. - it's using safe and
sane defaults.)

NOTE: the interface does not allow the changing of the TLS of another
thread on purpose - that would just complicate the interface (and
implementation) unnecesserily. Is there any good reason to allow the
setting of another thread's TLS?

NOTE2: non-pthreads glibc applications can call set_thread_area() to set
up a GDT entry just below the end of stack. We could use some sort of
default TLS area as well, but that would hard-code a given segment.

i fixed a number of unclean items in our GDT/IDT handling as well:

 - the 'gdt' pointer is completely unnecessery, it introduces an 
   additional redirection.

 - ditto the 'idt' pointer.

 - this also enabled simpler setting of the GDT/IDT descriptors.

 - on UP the GDT got smaller in fact, by a few bytes :-)

 - cleaned up LDT loading: load_LDT_desc() now loads the (constant) LDT 
   selector. A pity that we have to do this - but it's necessery to flush
   the LDT shadow descriptors.

 - the thread context-switching hotpath included a call to a non-inlined 
   function - set_ldt_desc() - this function is inlined now.

the patch compiles, boots & works just fine on UP and SMP x86 boxes.  
Comments and suggestions are welcome,

	Ingo


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [announce, patch] Thread-Local Storage (TLS) support for Linux, 2.5.28
  2002-07-25 17:35 [announce, patch] Thread-Local Storage (TLS) support for Linux, 2.5.28 Ingo Molnar
@ 2002-07-26 13:06 ` jlnance
  0 siblings, 0 replies; 9+ messages in thread
From: jlnance @ 2002-07-26 13:06 UTC (permalink / raw)
  To: linux-kernel

On Thu, Jul 25, 2002 at 07:35:34PM +0200, Ingo Molnar wrote:
> 
> the following patch implements proper x86 TLS support in the Linux kernel,
> via a new system-call, sys_set_thread_area():

Ingo,
    Its great that you can add a feature and make the code smaller and
faster at the same time.  Good job!

Jim

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [announce, patch] Thread-Local Storage (TLS) support for  Linux,2.5.28
  2002-07-28 20:08 ` [announce, patch] Thread-Local Storage (TLS) support for Linux, 2.5.28 Ingo Molnar
@ 2002-07-28 20:54   ` Oleg Nesterov
  2002-07-28 20:51     ` Ingo Molnar
  0 siblings, 1 reply; 9+ messages in thread
From: Oleg Nesterov @ 2002-07-28 20:54 UTC (permalink / raw)
  To: Ingo Molnar; +Cc: linux-kernel

Hello.

Ingo Molnar wrote:
> 
> On Sun, 28 Jul 2002, Oleg Nesterov wrote:
> 
> > +      * Load the per-thread Thread-Local Storage descriptor.
> > +      *
> > +      * NOTE: it's faster to do the two stores unconditionally
> > +      * than to branch away.
> > +      */
> > +     load_TLS_desc(next, cpu);
> > +
> > +     /*
> >        * Save away %fs and %gs. No need to save %es and %ds, as
> 
> actually, shouldnt this be done after saving the current %fs and %gs, and
> before loading the next %fs and %gs?
> 
>         Ingo

Well, load_TLS() and saving current %fs,%gs are just mem stores, no?
I can't see any difference in terms of correctness.

Oleg.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [announce, patch] Thread-Local Storage (TLS) support for  Linux,2.5.28
  2002-07-28 20:54   ` [announce, patch] Thread-Local Storage (TLS) support for Linux,2.5.28 Oleg Nesterov
@ 2002-07-28 20:51     ` Ingo Molnar
  0 siblings, 0 replies; 9+ messages in thread
From: Ingo Molnar @ 2002-07-28 20:51 UTC (permalink / raw)
  To: Oleg Nesterov; +Cc: linux-kernel


On Mon, 29 Jul 2002, Oleg Nesterov wrote:

> Well, load_TLS() and saving current %fs,%gs are just mem stores, no? I
> can't see any difference in terms of correctness.

yes, your patch is fine.

	Ingo


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [announce, patch] Thread-Local Storage (TLS) support for  Linux,2.5.28
  2002-07-28 20:01 ` Ingo Molnar
  2002-07-28 20:14   ` Ingo Molnar
@ 2002-07-28 20:19   ` Oleg Nesterov
  1 sibling, 0 replies; 9+ messages in thread
From: Oleg Nesterov @ 2002-07-28 20:19 UTC (permalink / raw)
  To: Ingo Molnar; +Cc: linux-kernel

Hello.

> > I thought, that gdt entry consulted only while
> > loading its index into the segment register.
> >
> > So load_TLS_desc(next, cpu) must be called before
> > loading next->fs,next->gs in __switch_to() ?
> 
> hm, right. I'm wondering, why did the tls_test code still work?
> 
>         Ingo

Because that code reloads %fs before every time in {read,write}seg.

Oleg.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [announce, patch] Thread-Local Storage (TLS) support for Linux, 2.5.28
  2002-07-28 20:01 ` Ingo Molnar
@ 2002-07-28 20:14   ` Ingo Molnar
  2002-07-28 20:19   ` [announce, patch] Thread-Local Storage (TLS) support for Linux,2.5.28 Oleg Nesterov
  1 sibling, 0 replies; 9+ messages in thread
From: Ingo Molnar @ 2002-07-28 20:14 UTC (permalink / raw)
  To: Oleg Nesterov; +Cc: linux-kernel


On Sun, 28 Jul 2002, Ingo Molnar wrote:

> > So load_TLS_desc(next, cpu) must be called before
> > loading next->fs,next->gs in __switch_to() ?
> 
> hm, right. I'm wondering, why did the tls_test code still work?

okay, the tls_test.c code worked only because the code didnt
context-switch after installing the TLS.

	Ingo


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [announce, patch] Thread-Local Storage (TLS) support for Linux, 2.5.28
  2002-07-28 18:44 Oleg Nesterov
  2002-07-28 20:01 ` Ingo Molnar
@ 2002-07-28 20:08 ` Ingo Molnar
  2002-07-28 20:54   ` [announce, patch] Thread-Local Storage (TLS) support for Linux,2.5.28 Oleg Nesterov
  1 sibling, 1 reply; 9+ messages in thread
From: Ingo Molnar @ 2002-07-28 20:08 UTC (permalink / raw)
  To: Oleg Nesterov; +Cc: linux-kernel


On Sun, 28 Jul 2002, Oleg Nesterov wrote:

> +	 * Load the per-thread Thread-Local Storage descriptor.
> +	 *
> +	 * NOTE: it's faster to do the two stores unconditionally
> +	 * than to branch away.
> +	 */
> +	load_TLS_desc(next, cpu);
> +
> +	/*
>  	 * Save away %fs and %gs. No need to save %es and %ds, as

actually, shouldnt this be done after saving the current %fs and %gs, and
before loading the next %fs and %gs?

	Ingo


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [announce, patch] Thread-Local Storage (TLS) support for Linux, 2.5.28
  2002-07-28 18:44 Oleg Nesterov
@ 2002-07-28 20:01 ` Ingo Molnar
  2002-07-28 20:14   ` Ingo Molnar
  2002-07-28 20:19   ` [announce, patch] Thread-Local Storage (TLS) support for Linux,2.5.28 Oleg Nesterov
  2002-07-28 20:08 ` [announce, patch] Thread-Local Storage (TLS) support for Linux, 2.5.28 Ingo Molnar
  1 sibling, 2 replies; 9+ messages in thread
From: Ingo Molnar @ 2002-07-28 20:01 UTC (permalink / raw)
  To: Oleg Nesterov; +Cc: linux-kernel


On Sun, 28 Jul 2002, Oleg Nesterov wrote:

> I thought, that gdt entry consulted only while
> loading its index into the segment register.
> 
> So load_TLS_desc(next, cpu) must be called before
> loading next->fs,next->gs in __switch_to() ?

hm, right. I'm wondering, why did the tls_test code still work?

	Ingo


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [announce, patch] Thread-Local Storage (TLS) support for Linux,  2.5.28
@ 2002-07-28 18:44 Oleg Nesterov
  2002-07-28 20:01 ` Ingo Molnar
  2002-07-28 20:08 ` [announce, patch] Thread-Local Storage (TLS) support for Linux, 2.5.28 Ingo Molnar
  0 siblings, 2 replies; 9+ messages in thread
From: Oleg Nesterov @ 2002-07-28 18:44 UTC (permalink / raw)
  To: Ingo Molnar; +Cc: linux-kernel

Hello.

I thought, that gdt entry consulted only while
loading its index into the segment register.

So load_TLS_desc(next, cpu) must be called before
loading next->fs,next->gs in __switch_to() ?

--- linux-2.5.29/arch/i386/kernel/process.c~	Sun Jul 28 21:44:35 2002
+++ linux-2.5.29/arch/i386/kernel/process.c	Sun Jul 28 21:46:07 2002
@@ -675,6 +675,14 @@
 	tss->esp0 = next->esp0;
 
 	/*
+	 * Load the per-thread Thread-Local Storage descriptor.
+	 *
+	 * NOTE: it's faster to do the two stores unconditionally
+	 * than to branch away.
+	 */
+	load_TLS_desc(next, cpu);
+
+	/*
 	 * Save away %fs and %gs. No need to save %es and %ds, as
 	 * those are always kernel segments while inside the kernel.
 	 */
@@ -688,14 +696,6 @@
 		loadsegment(fs, next->fs);
 		loadsegment(gs, next->gs);
 	}
-
-	/*
-	 * Load the per-thread Thread-Local Storage descriptor.
-	 *
-	 * NOTE: it's faster to do the two stores unconditionally
-	 * than to branch away.
-	 */
-	load_TLS_desc(next, cpu);
 
 	/*
 	 * Now maybe reload the debug registers

Oleg.

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2002-07-28 20:49 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-07-25 17:35 [announce, patch] Thread-Local Storage (TLS) support for Linux, 2.5.28 Ingo Molnar
2002-07-26 13:06 ` jlnance
2002-07-28 18:44 Oleg Nesterov
2002-07-28 20:01 ` Ingo Molnar
2002-07-28 20:14   ` Ingo Molnar
2002-07-28 20:19   ` [announce, patch] Thread-Local Storage (TLS) support for Linux,2.5.28 Oleg Nesterov
2002-07-28 20:08 ` [announce, patch] Thread-Local Storage (TLS) support for Linux, 2.5.28 Ingo Molnar
2002-07-28 20:54   ` [announce, patch] Thread-Local Storage (TLS) support for Linux,2.5.28 Oleg Nesterov
2002-07-28 20:51     ` Ingo Molnar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).