Andrew Pinski wrote:
> I would have hoped people actually read:
> http://gcc.gnu.org/onlinedocs/gcc/C99-Thread_002dLocal-Edits.html
> 
> Which actually describes the edits to the C99 standard to how  
> __thread is supposed to behave.

Thanks for the reference.  Per that proposal, __thread is a
storage-class specifier, which makes sense.  I may have
confused the issue by offering up an example using 'const'
-- the point of the example was really just to show that
the implementor of the __thread check wasn't lazy, but was
following suit on the qualifier check.

Given that __thread is a proposed extension, there isn't much
precedent to lean on, because generally 'extern' can only refer
to block scope identifiers and those objects are
inherently global, and from the point of view of the "C" program
referring to the objects, the actual method used to link, load,
and access those objects is implementation defined.

(Btw, personally, I'd prefer that a propoasl to extend the "C"
language use something other than a keyword beginning
with __ as a way of doing that.  For example, a compound keyword
such as "thread local" would read better and is unlikely to clobber
many existing programs.  If the idea of a compound keyword
is too offensive, then thread_local seems a lot better than __thread
to me.)

Applying the proposed standard to the following:

Dave Korn wrote:
> Reasons like this are why we have 6.2.7.2 in the C language spec, aren't
> they?
> 
> "All declarations that refer to the same object or function shall have
> compatible type; otherwise, the behavior is undefined."

The answer is probably, no.  Because the presence or absence of storage
specifiers shouldn't affect type compatibilty.

In reply to my question:
> > What are the technical reasons for the front-end enforcing this 
> restriction,
> > when apparently some linkers will handle the TLS linkage fine?  
> If in fact
> > it is required that __thread be added to the extern, is the 
> compiler simply
> > accommodating a limitation/bug in the linker?

Seongbae Park wrote:
> Because the compiler has to generate different code
> for accesses to __thread vs non __thread variable

In my view, this is implementation-defined, and generally can vary
depending upon the underlying linker and OS technology.  Further,
there is at least one known platform (IA64) which seems to not impose
this restriction.  A few implementation techniques come to mind,
where the programmer would not need to explicitly tag 'extern's
with __thread:

1. The linker can fix up external references to __thread variables
   by inserting jumps to a "thunk" that executes the appropriate
   instuctions and then jumps back to the point following the
   original instruction.  The IA64 linker might already be
   doing that.

2. The entire program might be compiled in some sort of PIC mode,
   where all external references go through some sort of indirect
   table, or some small subroutine is called to load the proper
   address, and there is no distinction between regular extern
   references and extern __thread references.

3. The linker coallesces __thread objects into a special linkage
   segment, and the OS allocates a new instance of this segment
   when it instantiates a thread.  From the thread's point of view,
   access to this per-thread segment is just a regular memory
   reference.  Thread creation may be slower, but access to TLS
   data is faster.

Thus, I don't think gcc should be checking for the presence of
the __thread specifier applied to an extern when the referenced
object is also declared as having __thread persistance, and both
declarations happen to be visible in a given compilation unit.
If this check must remain, I think it should be down-graded to
a warning (with a flag to turn off the warning), and the check
should be target-tuple specific, with possible further
target-dependent checks (such as special PIC modes, etc.).

This part of the proposed spec.:

"The declaration of an identifier for a variable that
has block scope that specifies __thread shall also
specify either extern or static."

seems to indicate that following declaration (at block scope)
is erroneous:
    int __thread x;
because it has neither "static" nor "extern" preceding it.
Interestingly, when declared at an inner scope, the
declaration above appears to be allowed, because __thread
is a storage specifier.

Perhaps the "C" standard says somewhere that a bare
block scope declaration implies "extern", but the
language in the spec. seems to call out precisely
the presence of either "static" or "extern" ahead
of __thread in block scope declarations.

Thus, it seems that if gcc is going to move towards the
proposed standard, it should also deprecate block scope
declarations that aren't preceeded with either
"extern" or "static"?  (and perhaps it should do this
in preference to matching up bare declartions with
extern declarations).

If extern is required for block scoped objects
then it seems to imply that those objects can't be statically
initialized, where those declared with "static" may be. 

Regarding Mike's conjecture that a bare extern should be able
to match up with a more fully qualified declaration, it would
be interesting to hear what the language lawyers think, but
that is a separate question from making the check for matching
uses of __thread.

Reply via email to