[−][src]Module sunrise_libuser::thread_local_storage
Thread Local Storage on x86
Usage
You declare a thread-local using the #[thread_local] attribute :
#![feature(thread_local)] #[thread_local] static MY_THREAD_LOCAL: core::cell::Cell<u8> = core::cell::Cell::new(42);
and access it as if it was a regular static, only that each thread will have its own view of the static.
The compiler is responsible for generating code that will access the right address, provided we configured TLS correctly.
Early startup
Note that you can't access a thread-local static before init_main_thread
is called, because
the thread-local area for the main thread isn't initialized yet, and this will likely result to
a page fault or UB.
Inner workings
We implement the TLS according to conventions laid out by Ulrich Drepper's paper on TLS which is followed by LLVM and most compilers.
Since we're running on i386, we're following variant II.
Each thread's gs
segment points to a thread local memory area where thread-local statics live.
thread-local statics are simply accessed through an offset from gs
.
The linker is in charge of creating an ELF segment of type PT_TLS
where an initialization image
for cpu local regions can be found, and is meant to be copy-pasted for every thread we create.
on SunriseOS
On Surnise, the area where gs
points to is per-thread and user-controlled, we set it at the
startup of every thread with the set_thread_area
syscall.
The TLS initialisation image is supposed to be retrieved from our own program headers, which is a really weird design. Since we don't have access to our program headers, we instead use the linker to expose the following symbols:
__tls_init_image_addr__
,p_vaddr
: the address of our TLS initialisation image.__tls_file_size__
,p_filesz
: the size of our TLS initialisation image.__tls_mem_size__
,p_memsz
: the total size of our TLS segment.__tls_align__
,p_align
: the alignment of our TLS segment.
Those symbols are the addresses of the initialization in our .tdata
, so it can directly be copied.
dtv and __tls_get_addr
Since we don't do dynamic loading (yet ?), we know our TLS model will be static (either
Initial Exec or Local Exec).
Those models always access thread-locals directly via gs
, and always short-circuit the dtv.
So we don't even bother allocating a dtv array at all. Neither do we define a __tls_get_addr
function.
This might change in the future when we will want to support dynamic loading.
Structs
ThreadControlBlock | Elf TLS TCB |
ThreadLocalStaticRegion | Represents an allocated thread local static region. |
TlsElf | The Thread Local Storage manager for a thread |
Statics
__tls_align__ | The alignment of the TLS segment. |
__tls_file_size__ | The size of the TLS initialisation image in our |
__tls_init_image_addr__ | The address of the start of the TLS initialisation image in our |
__tls_mem_size__ | The total memsize of the TLS segment: .tdata + .tbss |
Functions
tls_align_up | The |