Boost logo

Boost :

From: David Abrahams (dave_at_[hidden])
Date: 2003-02-20 12:12:33

"Ken Hagan" <K.Hagan_at_[hidden]> writes:

> Reading various replies, we appear to have a couple of things that
> aren't completely pinned down: the type of "&k" and the implementation
> of TLS.

I think you may be missing the point that in some sense &k doesn't
have to have a single type. At compile-time it can be manipulated as
though it's a different type of thing from other (non-TLS)
pointers-to-objects, while at runtime it will of course always be an
ordinary pointer.

> 1 If "&k" is a regular pointer to integer and TLS is implemented by
> tweaking page tables for each thread, then "&k" has the same value
> in each thread and C<&k> is the same type, but any member of C<&K>
> that uses its template parameter will behave differently from one
> thread to another.

The behavior you describe above is IMO the only reasonable one, but
IMO we don't need the implementation details (tweaking page tables) in
order to achieve it.

> Is this a problem. I don't think so. Consider...
> __declspec(thread) k
> int foo() { return k; }
> We can easily write a template, C, and instantiate it "C<&k>" and
> have its behaviour vary per-thread, although the value of the
> template parameter is the same.
> With this TLS implementation, we can't expose TLS data to another
> thread except by copying it. The workaround is simply to store a
> pointer to the actual data or object.
> 2 If "&k" is a regular pointer and TLS is implemented by allocating
> separate blocks for each thread and storing the addresses in a
> register, then "&k" has a different value in each thread and is no
> longer a compile time constant so you can't write the template.

I disagree with your conclusion. As I've said elsewhere, &k can be a
compile-time constant in the same way that &X::k is a compile-time
constant. This is simple to accomplish from a conceptual POV, though
existing compilers may need some modification to support it.
Conceptually, the compile-time representation of addresses would have
to be something like this:

   struct address
        type t; // the type of object being pointed at
        bool thread_local; // whether it's thread-local
        unsigned logical_address;

logical addresses would be assigned for TLS entities in the same way
as other "globals." Typically physical addresses are not determined
until link-time.

> 3 If "&k" is a special pointer, then we can implement TLS either way,
> but we must define a conversion between special and regular pointers.
> For ordinary functions expecting "int*" the compiler simply invokes
> this conversion when passing the argument and no-one gets upset.
> However, for the template case, that conversion is a run-time
> operation so it clearly can't apply.

I don't know what you mean by "special pointer", and I don't see what
argument-passing has to do with it. It's simply a matter of what code
gets generated to retrieve &k at the compile-time/runtime boundary.
Having different ways to get the address is no different conceptually
from having near and far variables, or variables which are local or in
some other DLL.

> 3a If we allow C<&k>, then "&k" is the offset into the TLS table, the
> instantiated code includes the conversion, and C<&k> is the same
> type in every thread because the offset is the same. It is then
> possible to initialise static variables with the converted value
> of "&k" and the results depend on the thread that ran first. Again,
> we have the same "problem" passing a pointer to a function, so I'm
> not bothered by this.

I don't understand how this is different from the other options above.

Dave Abrahams
Boost Consulting

Boost list run by bdawes at, gregod at, cpdaniel at, john at