On 07/21/2010 04:23 PM, Hans-Peter Diettrich wrote:
. And since the segment registers are only changed on process/thread switches, the resulting overhead is kept to the absolute minimum.
Same with using a segment registers the base for the threadvar area. This only needs to be initiated when a thread is created. This is a quite rare occasion, as you will use a thread-pool if a threaded application needs to switch between multiple active/passive threads, anyway.

Apart from that, I've heard that segment registers have no special effect in 64 bit mode at all? How can these registers ever be used, in 64 bit code? Safe bet: don't touch them ever, use only as documented (for FS/GS).
I did not do any research yet regarding X86/64 :(.

When an OS does not provide an API to create segments (in a 32 bit flat model), there exist no values (segment selectors) that can be loaded into a segment register at all, by application code.
If the OS does not provide an API that defines the use of the registers and the OS manufacturer does not provide a documentation that tells us otherwise, I think we are allowed to presume that these registers are "just registers" that work as documented in the way the hardware documentation describes and thus a user application is free to use them anywhere and the OS guaranteed that they are save regarding preemption. AFAIK, this is commonly done with ES, and so I don't see why it's not true with GS. It seems that on thread start in Windows, FS is predefined with a pointer to some Windows specific thread information, but that does not mean that it's not allowed to assign some other value to FS and that it will not be safe.

Of course this would be nice, but till then it's simply wise to not use such undocumented registers at all, neither in compiler created code, nor in ASM.
Hmm, is BX explicitly documented ?

IMO the OS provides means to allocate an thread-local memory block (Thread Local Storage), whose content *can* be used for threadvars.
AFAI understand, in Linux (any architecture) the OS just preserves a count of registers and the (e.g. C) compiler just uses one of them as a pointer to the threadvars. When creating a thread the thread library (e.g. libc) creates the threadvar block and assigns the pointer to the said register.
It's not up to the API or ABI to bother with the "record" layout of that TLS memory block, that's all application/compiler specific.
The way how threadvars are don _is_ compiler specific. Of course it does make sense if all compilers working for a certain OS use the same paradigm here, so the OS _should_ provide a documentation how they should do it,. In Linux of course the gnu C compiler team takes care of all this.

A threadvar simply is a member of that record, and the API specified register contains the (direct or indirect) address of the TLS.
I suppose this is the Windows specific way....

IMO also no physical/logical separation exists, between application (main thread) and other thread memory, everything exists in the overall process memory. It's up to the compiler/coder, to prevent unsynchronized access to memory locations that could be updated concurrently by multiple threads.
Of course this is correct. But the compiler only has two options to do this. Either do an OS API call foe each access to a global threadvar (very slow) or dedicate a register a a pointer to the block of global threadvars. I know that e.g. NIOS (that is similar to ARM or MIPS) just uses one of it's 32 general purpose registers for this. X86/32 does not have many registers, so it's a good idea to use a segment register. This is what Linux GNUC is officially documented to do and what the "unsafe" documentation mentioned in this thread states for Windows as well (here in fact maybe as a pointer to a pointer to the threadvar block).

BTW, the definition of "threadvar" is not a very practical one. In practice it should be possible to assign threadvars to *specific* threads, otherwise *every* thread has to allocate an TLS containing *all* the threadvars of the entire application. Furthermore it would be sufficient to have all "threadvars" in the specific TThread-derived classes, eliminating the need for any additional TLS.
The programmer is free to do this by using just another indirection. You may use a single global threadvar that holds the address of an Object (or record) that a thread allocates on the heap when it starts. The Object or Record now can hold any thread specific information.

Many global threadvars only make sense if you start the same code in many threads.

-Michael
_______________________________________________
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
http://lists.freepascal.org/mailman/listinfo/fpc-devel

Reply via email to