Thread Local Storage: Difference between revisions

[unchecked revision][unchecked revision]
Content deleted Content added
m Add to category Processes and Threads
m Bot: Replace deprecated source tag with syntaxhighlight
 
(2 intermediate revisions by one other user not shown)
Line 1:
Thread Local Storage (TLS) are per-thread global variables. Compilers such as [[GCC]] provide a <tt>__thread</tt> keyword to mark global variables as per-thread. Support is required in the program loader and thread creator.
<sourcesyntaxhighlight lang="c">
__thread int errno;
int get_errno() { return errno; }
</syntaxhighlight>
</source>
A [[x86-64]] [[System V ABI]] compiler would compile this code into assembly like this:
<pre>
Line 24:
The program contains a master copy of its thread local storage (with its initialized-at-compile-time values) which is used when creating threads. This special segment is created by the linker from the <tt>.tdata</tt> (initialized tls) and <tt>.tbss</tt> (zero-initialized tls) sections. You can find it by searching the [[ELF]] program headers for a segment with type <tt>PT_TLS</tt> (decimal value 7) (as opposed to the normal <tt>PT_LOAD</tt>).
 
The virtual address of the tlsthread local storage master segment is meaningless as it isn't loaded anywhere specific, you decide where you wish to load it. Mind that the segment does have alignment constraints like normal segments (but the linker placed those for you). Besides deciding yourself where to load the segment, you load this segment like a normal <tt>PT_LOAD</tt> segment.
 
=== Per-thread allocation ===
Line 44:
The thread local storage (after having its size rounded up to its alignment) is located immediately prior to the user-space thread structure. The offsets are negative. To place the user-space thread structure and the thread local storage, do this:
 
<sourcesyntaxhighlight lang="c">
size_t allocation_alignment = max(master_tls_alignment, alignof(struct uthread));
size_t allocation_size = alignup(master_tls_size, allocation_alignment) + sizeof(struct uthread);
Line 50:
struct uthread* uthread = allocation + alignup(master_tls_size, allocation_alignment);
unsigned char* tls = ((unsigned char*) uthread) - alignup(master_tls_size, master_tls_alignment);
</syntaxhighlight>
</source>
 
Do note that the thread local structure might not be at the beginning of the per-thread allocation if it its alignment is less of that than struct uthread. It is crucial that both the thread local storage and the user-space thread structure are properly aligned. You then initialize the user-space thread structure's self pointer and the tlsthread local storage:
 
<sourcesyntaxhighlight lang="c">
uthread->self_pointer = uthread;
memcpy(tls, master_tls, master_tls_size);
</syntaxhighlight>
</source>
 
=== x86-64 ===
Line 64:
 
The per-thread allocation is arranged and placed as described under [[#i386]].
 
=== Other ===
 
See the <tt>tls.pdf</tt> document below and please document the specifics here afterwards. :)
 
== Implementation ==
Line 83 ⟶ 87:
# Set the thread-self-pointer register of the new thread to the new thread's user-space thread structure.
 
Some Unix kernels such as Linux actually doesn't set up the thread local storage for the main thread. The libc is required to parse the ELF executable of the program to locate and load the master thread local storage copy itself and bootstrap the main thread. This has the obvious disadvantages of having early times where language features doesn't work and that every executable gets linked in an ELF loader (in case it uses TLSthread local storage).
 
== See Also ==