[fpc-devel] threadvar implementation
Michael Schnell
mschnell at lumino.de
Fri Jul 30 09:34:00 CEST 2010
On 07/29/2010 09:41 PM, Hans-Peter Diettrich wrote:
>
> What makes you think that this is different from x86?
With X86/32 Linux, the "application"address of a threadvar in the ASM
instruction is the same for all threads. The ASM instruction is done
with a "GS:" prefix, thus instead of the DS sector, (that is used
without the prefix), GS is used as a selector. Now the 16 bit selector
reads an entry in an OS-provided table and same is added to the address
given in the instruction. The OS provides a different table for each
thread and thus the resulting memory address is different, even though
the GS selector value itself is the same for each thread.
With X86/32 Windows, the "application"address of a thread var in the ASM
instruction is the same for all threads, as well. The access is done
reading a structure that exists for each thread, using the "FS:" prefix
in the ASM instruction (this results in using the appropriate thread's
structure, as - like with Linux - the OS provides a different selecting
table for each thread and thus the resulting memory address is
different, even though the FS selector value itself is the same for each
thread. Now the threadvar is accessed using this pointer and the
standard DS selector. One indirection more than is Linux, slightly less
efficient.
With NIOS (and supposedly similar with ARM), there is no "selector"
hardware. Instead, one of the 32 registers (R26, called GP ("General
Pointer") ) is used to address normal static and global variables. Now
another register (R23) is used to address threadvars. Within a running
application the value of R26 is always the same, while the value of R23
is different for each thread (of course all registers are preemption-safe).
Regarding pointers this yields:
With X86/32 Linux, with C you can define a pointer type "__thread int
i*". So this pointer knows that is handles a threadvar and thus the
compiler can generate code accessing the threadvar via GS even when a
pointer is used (I did not test yet whether this really works). With
Pascal this is not possible (AFAIK). So using a pointer, a value is
always accessed via DS. AFAIK, when calculating the pointer value it's
technically not possible to "rebase" the address from GS to DS, as the
selector tables can't be read from user space. Catch 22.
With X86/32 Windows, The threadvar is finally accessed via DS anyway. So
no problem here. If you save the address of a threadvar in a global
variable, a different thread will be able to access the threadvar of the
thread that saved the pointer. I should test if FP really gives thread
specific address-values for pointers to threadvars in Windows but not in
Linux. (IMHO different behavior would be erroneous.)
With NIOS (and supposedly similar with ARM), the pointer value for a
threadvar will be calculated adding the offset to R23 creating a normal
memory address. So no problem here. If you save the address of a
threadvar in a global variable, a different thread will 'be able to
access the threadvar of the thread that saved the pointer.
- Michael
PS.: maybe some might be willing to help enhancing this list with real
ARM, X86/64 Linux and X86/64 Windows knowledge,
More information about the fpc-devel
mailing list