[fpc-devel] threadvar implementation

Hans-Peter Diettrich DrDiettrich1 at aol.com
Fri Jul 30 20:01:04 CEST 2010


Michael Schnell schrieb:

>> What makes you think that this is different from x86?
> With X86/32 Linux, the "application"address of a threadvar

Please distinguish: Segmented or Flat address?

Only FS and GS can add an non-zero offset, to the *offset* given in the 
instruction. The sum of both is the flat "address" (effectively another 
offset), that can be stored in a pointer variable. In 32/64 bit flat 
memory models all pointers are "near", i.e. they don't include an 
segment selector, and a zero-based segment is implied (DS...).

> 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.

Thus GS provides an thread specific segment offset, to an block (record) 
of threadvars.

> 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.

Here FS provides the thread specific segment offset.

> Now the threadvar is accessed using this pointer and the 
> standard DS selector. One indirection more than is Linux, slightly less 
> efficient.

I.e. the intermediate result is a pointer to an block (record) of 
threadvars.


> 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).

Here a register provides the offset to the block of threadvars.


> 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).

Kind of a near pointer, with the thread segement (offset) implied.

> 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.

You only have to determine the flat address, before storing it in the 
pointer variable - @MyThreadvar?

> 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.

The only question is, whether you want the (absolute, flat) address of 
the threadvar of an *specific* thread, or the address of the threadvar 
in the *current* thread. Since the current thread can change, the offset 
of the threadvar record will change accordingly, and must be determined 
by the appropriate means (via segment or other address register).

DoDi




More information about the fpc-devel mailing list