I've generally found that thread-local storage is easily misused. My general rule of thumb is to avoid thread-locals wherever possible, but if they are required keep thread-local state constant sized, not one per object. The memory usage can grow rapidly when your library is used with many objects and many threads. In places where you would want one thread-local per object, instead try core-locals.
Sure. Sometimes, people use TLS to implement Lisp-style "dynamic scope" in an effort to reduce the amount of information passed from call-frame to call-frame via explict parameters. This approach suffers from the same drawback that dynamic scope does, and it's usually (but not always!) better to be explicit.
I don't understand why the linker and kernel need to be involved? Why isn't storing the address of the thread-local memory in the register enough? That only needs to involve the compiler to know about the register and the runtime to set it. The article talks about needing the kernel to set a privileged register, but we've got tons of general purpose registers we could store the thread-local address in.
In 32-bit x86 there aren't very many registers to play with, and there were legacy ABIs that didn't preserve registers for TLS, so the segment registers were used instead. When x86-64 arrived, it had a lot more registers (but still less than many other architectures) and a clean ABI break, but it kept enough segment register functionality to use for TLS, so it continued to be used to free up that one register - why not, after all?
Because it seems to need the kernel to set it? But I guess that's only done once each time you create a new thread and you're already doing a syscall in that case, so it's probably better than taking up a general purpose register.
regardless of where you stash the state, if the kernel is responsible for preemptively changing threads, it needs to swap out the TLS pointer when it does so.
on the linker side - you're right, there isn't any fundamental reason why. but since traditionally the linker does address assignment for symbols, and TLS variables are general symbols/storage with an annotation...then it seems natural to extend it to allocate out of .tdata and .tbss for multiple objects.
Hmm but the kernel doesn't need to know you're using a register for TLS. That's like saying that the kernel is involved in arithmetic because it needs to swap your temporary values in and out of registers that you're using on context switches.
You can’t set FS/GS from user space on x64-64 until the FSGSBASE instructions were introduced in Ivy Bridge. The kernel only needs to be involved as its privilege is needed to set the register; the kernel doesn’t “know” that they’re being used for TLS.
9 comments
[ 2.6 ms ] story [ 31.5 ms ] threadNot the clearest abbreviation ;)
Because it seems to need the kernel to set it? But I guess that's only done once each time you create a new thread and you're already doing a syscall in that case, so it's probably better than taking up a general purpose register.
on the linker side - you're right, there isn't any fundamental reason why. but since traditionally the linker does address assignment for symbols, and TLS variables are general symbols/storage with an annotation...then it seems natural to extend it to allocate out of .tdata and .tbss for multiple objects.