[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