sammccall created this revision. sammccall added reviewers: ilya-biryukov, bkramer. Herald added subscribers: cfe-commits, ioeric, jkorous-apple, klimek.
thread_local has nice syntax and semantics, but requires __cxa_thread_atexit, and some not-ancient runtime libraries don't provide it. The clang-x86_64-linux-selfhost-modules buildbot is one example :-) It works on windows, and the other platforms clang-tools-extra supports should all have the relevant pthread API. So we just use that if it's available, falling back to thread_local (so if a platform has neither, we'll fail to link). The fallback should really be the other way, that would require cmake changes. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D42742 Files: clangd/Context.cpp Index: clangd/Context.cpp =================================================================== --- clangd/Context.cpp +++ clangd/Context.cpp @@ -8,8 +8,48 @@ //===---------------------------------------------------------------------===// #include "Context.h" +#include "llvm/Config/config.h" #include <cassert> +// The thread-local Context is scoped in a function to avoid init-order issues. +// It's created by currentContext() when first needed. + +#ifdef HAVE_PTHREAD_GETSPECIFIC +// We'd love to use thread_local everywhere. +// It requires support from the runtime: __cxa_thread_atexit. +// Rather than detect this, we use the pthread API where available. +#include <pthread.h> +static clang::clangd::Context ¤tContext() { + using clang::clangd::Context; + static pthread_key_t CtxKey; + + // Once (across threads), set up pthread TLS for Context, and its destructor. + static int Dummy = [] { // Create key only once, for all threads. + if (auto Err = pthread_key_create(&CtxKey, /*destructor=*/+[](void *Ctx) { + delete reinterpret_cast<Context *>(Ctx); + })) + llvm_unreachable(strerror(Err)); + return 0; + }(); + (void)Dummy; + + // Now grab the current context from TLS, and create it if it doesn't exist. + void *Ctx = pthread_getspecific(CtxKey); + if (!Ctx) { + Ctx = new Context(); + if (auto Err = pthread_setspecific(CtxKey, Ctx)) + llvm_unreachable(strerror(Err)); + } + return *reinterpret_cast<Context *>(Ctx); +} +#else +// Only supported platform without pthread is windows, and thread_local works. +static clang::clangd::Context ¤tContext() { + static thread_local auto C = clang::clangd::Context::empty(); + return C; +} +#endif + namespace clang { namespace clangd { @@ -20,13 +60,6 @@ Context Context::clone() const { return Context(DataPtr); } -// The thread-local Context is scoped in a function to avoid -// initialization-order issues. It's created when first needed. -static Context ¤tContext() { - static thread_local Context C = Context::empty(); - return C; -} - const Context &Context::current() { return currentContext(); } Context Context::swapCurrent(Context Replacement) {
Index: clangd/Context.cpp =================================================================== --- clangd/Context.cpp +++ clangd/Context.cpp @@ -8,8 +8,48 @@ //===---------------------------------------------------------------------===// #include "Context.h" +#include "llvm/Config/config.h" #include <cassert> +// The thread-local Context is scoped in a function to avoid init-order issues. +// It's created by currentContext() when first needed. + +#ifdef HAVE_PTHREAD_GETSPECIFIC +// We'd love to use thread_local everywhere. +// It requires support from the runtime: __cxa_thread_atexit. +// Rather than detect this, we use the pthread API where available. +#include <pthread.h> +static clang::clangd::Context ¤tContext() { + using clang::clangd::Context; + static pthread_key_t CtxKey; + + // Once (across threads), set up pthread TLS for Context, and its destructor. + static int Dummy = [] { // Create key only once, for all threads. + if (auto Err = pthread_key_create(&CtxKey, /*destructor=*/+[](void *Ctx) { + delete reinterpret_cast<Context *>(Ctx); + })) + llvm_unreachable(strerror(Err)); + return 0; + }(); + (void)Dummy; + + // Now grab the current context from TLS, and create it if it doesn't exist. + void *Ctx = pthread_getspecific(CtxKey); + if (!Ctx) { + Ctx = new Context(); + if (auto Err = pthread_setspecific(CtxKey, Ctx)) + llvm_unreachable(strerror(Err)); + } + return *reinterpret_cast<Context *>(Ctx); +} +#else +// Only supported platform without pthread is windows, and thread_local works. +static clang::clangd::Context ¤tContext() { + static thread_local auto C = clang::clangd::Context::empty(); + return C; +} +#endif + namespace clang { namespace clangd { @@ -20,13 +60,6 @@ Context Context::clone() const { return Context(DataPtr); } -// The thread-local Context is scoped in a function to avoid -// initialization-order issues. It's created when first needed. -static Context ¤tContext() { - static thread_local Context C = Context::empty(); - return C; -} - const Context &Context::current() { return currentContext(); } Context Context::swapCurrent(Context Replacement) {
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits