Bug 15523 – extern(C++) support TLS (C++ 'thread_local') linkage?

Status
NEW
Severity
enhancement
Priority
P4
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2016-01-07T01:47:40Z
Last change time
2024-12-13T18:46:22Z
Keywords
C++, pull
Assigned to
No Owner
Creator
Manu
Moved to GitHub: dmd#19084 →

Comments

Comment #0 by turkeyman — 2016-01-07T01:47:40Z
We typically use __gshared when extern(C++) to global data. 'thread_local' is becoming common in C++ code (I have quite a few); is it possible to support non-gshared extern(C++) to mangle as C++ 'thread_local' variables? The obvious question is, is D's TLS and C++'s TLS strategy compatible? Possible to support C++ TLS in D? I'm sure this is trivial for GCC and Clang, I expect it's nothing more than mangling there?
Comment #1 by doob — 2016-01-07T08:16:28Z
I'm not sure if there's any different between thread_local and __thread. But for __thread there's no specific mangling, at least not on OS X. Have you tried and see what happens? Unfortunately I cannot do that on OS X, since neither thread_local is supported (__thread works though) and the D implementation of TLS on OS X is not compatible with the C implementation.
Comment #2 by turkeyman — 2016-01-08T05:35:41Z
Wow, you seem to be right, 'thread_local' doesn't appear to affect the mangling... that's astonishing! Surely that can only lead to really-hard-to-track link related bugs... Okay, well then, the question is, can we support C++ 'thread_local' semantics for extern(C++) of non-__gshared?
Comment #3 by doob — 2016-01-08T07:51:27Z
(In reply to Manu from comment #2) > Okay, well then, the question is, can we support C++ 'thread_local' > semantics for extern(C++) of non-__gshared? As with everything, it's just a matter of someone implementing it. Although, if "__thread" and "thread_local" have different semantics, I wonder what syntax to use in D then. // foo.cpp __thread int a; thread_local int b; // foo.d extern(C++) extern int a; // this will have the semantics of __thread extern(C++) extern /* __thread_local ? */ int b; // what should this syntax be?
Comment #4 by turkeyman — 2016-01-08T09:29:09Z
I would suggest that since 'thread_local' is C++11 standard, then that should be the one. Since '__thread' is not standard, I imagine it would be best supported by GDC(/Clang?) via the @attribute("__thread") mechanism that they support for their compiler-specific attributes. extern(C++): // Standard: extern int i; // thread_local // GCC(/Clang?): @attribute("__thread") extern int i; // __thread (this is probably very easy for those toolchains to implement)
Comment #5 by turkeyman — 2016-01-08T09:30:32Z
(In reply to Manu from comment #4) > > // GCC(/Clang?): ** GDC(/LDC) ;)
Comment #6 by doob — 2016-01-08T14:39:21Z
(In reply to Manu from comment #4) > I would suggest that since 'thread_local' is C++11 standard, then that > should be the one. That would be a breaking change. > Since '__thread' is not standard, I imagine it would be best supported by > GDC(/Clang?) via the @attribute("__thread") mechanism that they support for > their compiler-specific attributes. thread_local is not supported by the version of Clang supplied by Apple. The one most likely installed. > extern(C++): > > // Standard: > extern int i; // thread_local > > // GCC(/Clang?): > @attribute("__thread") extern int i; // __thread (this is probably very easy > for those toolchains to implement) DMD need to be able to handle it as well. Perhaps through a pragma? This would only affect extern(C++)? Would it be confusing to need to specify @attribute("__thread") only when the linkage is C++? I found this stackoverflow thread explaning the different sematnics of __thread and thread_local [1]. It looks like if you use thread_local for any use case that __thread is valid, it will behave the same, except when it's declared "extern". [1] http://stackoverflow.com/questions/13106049/c11-gcc-4-8-thread-local-performance-penalty
Comment #7 by turkeyman — 2016-01-08T14:56:55Z
(In reply to Jacob Carlborg from comment #6) > (In reply to Manu from comment #4) > > I would suggest that since 'thread_local' is C++11 standard, then that > > should be the one. > > That would be a breaking change. How? We have no support at all right now... there's nothing to break? > > Since '__thread' is not standard, I imagine it would be best supported by > > GDC(/Clang?) via the @attribute("__thread") mechanism that they support for > > their compiler-specific attributes. > > thread_local is not supported by the version of Clang supplied by Apple. The > one most likely installed. For real? How old is that compiler? That still doesn't change that it's non-standard, and I would reserve default behaviour for the standard keyword, which I'm astonished isn't in the Clang release. ** google reveals a lot of people also complaining that __thread doesn't work on Apple compilers either. > > extern(C++): > > > > // Standard: > > extern int i; // thread_local > > > > // GCC(/Clang?): > > @attribute("__thread") extern int i; // __thread (this is probably very easy > > for those toolchains to implement) > > DMD need to be able to handle it as well. Perhaps through a pragma? > > This would only affect extern(C++)? Would it be confusing to need to specify > @attribute("__thread") only when the linkage is C++? I don't really think so; __thread is a C++ attribute, so I think it only makes sense if you extern(C++) aswell. > I found this stackoverflow thread explaning the different sematnics of > __thread and thread_local [1]. It looks like if you use thread_local for any > use case that __thread is valid, it will behave the same, except when it's > declared "extern". > > [1] > http://stackoverflow.com/questions/13106049/c11-gcc-4-8-thread-local- > performance-penalty Yeah, I saw the same article. My guess was that the extern case generates a function call such that they can change the ABI if they like. Doesn't seem like a problem to me, and actually, should make it really easy to implement! Just lower to a little stub with the proper mangled name.
Comment #8 by turkeyman — 2016-01-08T15:03:45Z
(In reply to Manu from comment #7) > (In reply to Jacob Carlborg from comment #6) > > > > This would only affect extern(C++)? Would it be confusing to need to specify > > @attribute("__thread") only when the linkage is C++? > > I don't really think so; __thread is a C++ attribute, so I think it only > makes sense if you extern(C++) aswell. Then again, __thread specifies only an ABI and no functions or mangling, so it could theoretically apply to D variables just as readily as extern(C++). thread_local only really makes sense for extern(C++) though, and that's what I'm concerned with here. I think it makes good sense that non-__gshared extern(C++) should follow the standard, and I'm sure Apple will come to the party before too long.
Comment #9 by doob — 2016-01-08T16:05:28Z
(In reply to Manu from comment #7) > How? We have no support at all right now... there's nothing to break? Hmm, yeah. I kind of assumed it already worked, at least for built-in types, like int. > For real? How old is that compiler? Xcode 7.2 was released Dec 8, 2015. > That still doesn't change that it's non-standard, and I would reserve > default behaviour for the standard keyword, which I'm astonished isn't in > the Clang release. __thread is supported, but not thread_local. See this stackoverflow post [1] explaining why. Something about ABI compatibility. > ** google reveals a lot of people also complaining that __thread doesn't > work on Apple compilers either. It's supported since OS X 10.7, quite old by now. > I don't really think so; __thread is a C++ attribute, so I think it only > makes sense if you extern(C++) aswell. You mean "thread_local"? > Yeah, I saw the same article. > My guess was that the extern case generates a function call such that they > can change the ABI if they like. Doesn't seem like a problem to me, and > actually, should make it really easy to implement! Just lower to a little > stub with the proper mangled name. Yeah, as long as you know how the compiler works ;) [1] http://stackoverflow.com/a/29929949
Comment #10 by iamthewilsonator — 2019-06-11T09:01:57Z
extern(C++): // Standard: extern int iiiiiiiii; // thread_local void foo() { iiiiiiiii = 42; } Generates with LDC: @iiiiiiiii = external thread_local global i32, align 4 DMD: extrn iiiiiiiii _Z3foov: ... lea RDI,iiiiiiiii@TLSGD[RIP] There are no mangling issues. Can this issue be closed?
Comment #11 by turkeyman — 2019-06-11T09:13:43Z
This isn't a mangling issue, it's an ABI issue. It's not clear if extern C++ and D TLS vars can link to each other.
Comment #12 by iamthewilsonator — 2019-06-11T09:16:05Z
I meant there were also no mangling issues. The examples above are codegen tests (albeit textual), I'm saying the problem is like already fixed. If you can verify that the the ticket can be closed.
Comment #13 by turkeyman — 2019-06-11T09:22:47Z
I'm not sure this problem has ever been attempted. Are there unit tests that show they link and read/write from each other?
Comment #14 by iamthewilsonator — 2019-06-11T09:27:09Z
(I realised I typo'd likely as like in the above post) There are no unit tests that I know of, but they shouldn't be hard to write. I'll do one up tomorrow and submit it to the test suite if you don't beat me to it.
Comment #15 by turkeyman — 2019-06-11T18:58:27Z
test.cpp: --------- thread_local int x = 100; extern thread_local int y; void test() { x += y; y += x; } test.d: ------- import std.stdio; extern(C++) extern int x; extern(C++) int y = 200; extern(C++) void test(); int main() { test(); assert(x == 300); assert(y == 500); x += y; y += x; assert(x == 800); assert(y == 1300); return 0; } ------------------------- 1>test.d(6): error : variable `test.y` Internal Compiler Error: C++ static non-__gshared non-extern variables not supported So, that's the first issue... But then, it's possible that GDC/LDC will TLS the same as GCC/Clang, but I wonder if DMD will be compatible with any of the others, and Windows...?
Comment #16 by dlang-bot — 2021-03-26T03:54:48Z
@thewilsonator created dlang/dmd pull request #12309 "Fix issue 15523- extern(C++) support TLS (C++ 'thread_local') linkage" fixing this issue: - Fix issue 15523- extern(C++) support TLS (C++ 'thread_local') linkage https://github.com/dlang/dmd/pull/12309
Comment #17 by robert.schadek — 2024-12-13T18:46:22Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/dmd/issues/19084 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB