Getting tls symbols out of the compiler.

Iain Buclaw ibuclaw at ubuntu.com
Thu May 30 02:42:17 PDT 2013


On 30 May 2013 09:25, Johannes Pfau <nospam at example.com> wrote:
> Am Thu, 30 May 2013 01:19:10 +0200
> schrieb "Iain Buclaw" <ibuclaw at ubuntu.com>:
>
>> OK, from today till the end of the week I'm going to be sitting
>> down and thinking through this, as I'd really like the emitting
>> of _tlsstart and _tlsend out of the compiler by hook or by crook.
>>
>>
>> Phase one - start:
>>
>> We have rt/tls.S.  Have added this to the libdruntime builds, and
>> I see no immediate problems running this through the testsuite
>> (though - that is never really a good indicator of anything).
>> Drawbacks, this is only available for linux at the moment. But
>> that's fine if we keep this temporary for the week.
>
> Do you know what that comment in that file "Sadly, this does not work
> because ld orders [...]" is about?
>

It's the same problem with what we currently have.  LD when it gets
all reference symbols that are to go into the tls section (for Linux,
at least) has the right to reorder the symbols.  As such, trying to
push _tlsstart as the first symbol in the compiler has no guarantees
it will be the first symbol in the object file.


>> Phase two - plan:
>>
>> The GC has a hook gc_addRoot used for the purpose of tracking GC
>> allocated memory in C-land.  The idea I've got turning over in my
>> head at the moment is that any thread local decls that are
>> 'new-able' (classes, pointers, d arrays) are added as a root upon
>> 'new' declaration,  this is safe-guarded by a thread-local static
>> to prevent multiple calls to gc_addRoot.
>>
>
> The good part part is that this will work with non-contiguous TLS, i.e
> GCC emulated TLS. The bad part is that it'll be very slow so it should
> really only be a fallback. And what about non-newable types?
>

Non-newable types aren't collected because they never reference new
memory...   This is true for basic types (int, float, complex,
vectors).  The same is also true for static arrays (although array[] =
[1,2,3,4] calls _d_arrayliteral, the allocated memory is copied so can
be free'd immediately afterwards).   For structures we can check
((TypeStruct *) t)->hasPointers() at compile time - if false then we
can be safely assured that this will never be referencing allocated
memory.  Classes, pointers and D arrays I've already mentioned.
Forgot to mention associative arrays, which would also be added as a
root upon initialisation.


> Why don't we register all thread local variables in a module
> constructor instead (in the C one or in the D one)?
>
> static int a;
> static void* b;
>
> static this()
> {
>     gc_addRoot(&a);
>     gc_addRoot(&b);
> }
>

This is more of a lazy init that won't affect start-up speed.  Note:
this idea is based off what C++ (g++) does for say - static A a = new
A();


> Then unload in the module destructor. We could try to optimize that,
> although we have to be careful:
>
> static this() //pseudo code
> {
>     void*[2] roots;
>     roots[0] = &a;
>     roots[1] = &b;
>     if(isContiguous(roots[])) //Sort. need to allow alignment though
>        gc_addRange(roots[0], roots[$] + size) //probably need to keep a
>        size array as well
>     else
>         foreach(ptr; roots)
>               gc_addRoot(ptr);
> }
>

This is a lot more work to describe in the compiler.  :)



> This can detect if the TLS memory is contiguous and then only add one
> range per module. Maybe it's not worth the effort as long as it's only
> a slow fallback (and even with the optimization it'll still be slow)
>

I don't think it would have much slow down.  Albeit the first
initialisation would jump through the druntime library twice, but
there after it's a single/two instruction test.  Pretty negligible -
but I'm not a speeeeeeeeed demon or freak who wants everything
compiled with -fOMG-fast. =)


>> Though this should not be required if we have a proper TLS GC in
>> place.
>
> Do you mean Martin Nowak's shared library/TLS work? That indeed sounds
> like the proper solution.
>

It should certainly mean that we don't have to worry about removing
roots once they've been added.


> (And maybe the D community should develop a sane standard interface to
> the runtime linker to access sections. Then go lobbying all major libcs
> out there...)

You mean binutils?  :-)

See binutils/ld/scripttempl  for the ldscripts used to lay out the tls
data sections.  (Note, only a few actually have a TLS section - and
only winpe defines a _tls_start__ and _tls_end__ symbol).


Regards
--
Iain Buclaw

*(p < e ? p++ : p) = (c & 0x0f) + '0';


More information about the D.gnu mailing list