Author: Owen Anderson Date: 2023-01-09T21:21:38-07:00 New Revision: ef9aa34f0274cdbfa82c47f8ab99f02679fd0d13
URL: https://github.com/llvm/llvm-project/commit/ef9aa34f0274cdbfa82c47f8ab99f02679fd0d13 DIFF: https://github.com/llvm/llvm-project/commit/ef9aa34f0274cdbfa82c47f8ab99f02679fd0d13.diff LOG: Revert "Remove the ThreadLocal template from LLVM." This reverts commit 54d78b639b9c18b42abd4fac5c6e76105f06b3ef. Added: llvm/include/llvm/Support/ThreadLocal.h llvm/lib/Support/ThreadLocal.cpp llvm/lib/Support/Unix/ThreadLocal.inc llvm/lib/Support/Windows/ThreadLocal.inc llvm/unittests/Support/ThreadLocalTest.cpp Modified: clang-tools-extra/clangd/support/ThreadCrashReporter.cpp llvm/lib/Support/CMakeLists.txt llvm/lib/Support/CrashRecoveryContext.cpp llvm/unittests/Support/CMakeLists.txt mlir/include/mlir/Support/ThreadLocalCache.h Removed: ################################################################################ diff --git a/clang-tools-extra/clangd/support/ThreadCrashReporter.cpp b/clang-tools-extra/clangd/support/ThreadCrashReporter.cpp index 9551bbfda43c1..05afb3b25f28e 100644 --- a/clang-tools-extra/clangd/support/ThreadCrashReporter.cpp +++ b/clang-tools-extra/clangd/support/ThreadCrashReporter.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "support/ThreadCrashReporter.h" +#include "llvm/Support/ThreadLocal.h" #include <atomic> namespace clang { diff --git a/llvm/include/llvm/Support/ThreadLocal.h b/llvm/include/llvm/Support/ThreadLocal.h new file mode 100644 index 0000000000000..d6838c15fc345 --- /dev/null +++ b/llvm/include/llvm/Support/ThreadLocal.h @@ -0,0 +1,62 @@ +//===- llvm/Support/ThreadLocal.h - Thread Local Data ------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares the llvm::sys::ThreadLocal class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_THREADLOCAL_H +#define LLVM_SUPPORT_THREADLOCAL_H + +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Threading.h" +#include <cassert> + +namespace llvm { + namespace sys { + // ThreadLocalImpl - Common base class of all ThreadLocal instantiations. + // YOU SHOULD NEVER USE THIS DIRECTLY. + class ThreadLocalImpl { + typedef uint64_t ThreadLocalDataTy; + /// Platform-specific thread local data. + /// + /// This is embedded in the class and we avoid malloc'ing/free'ing it, + /// to make this class more safe for use along with CrashRecoveryContext. + union { + char data[sizeof(ThreadLocalDataTy)]; + ThreadLocalDataTy align_data; + }; + public: + ThreadLocalImpl(); + virtual ~ThreadLocalImpl(); + void setInstance(const void* d); + void *getInstance(); + void removeInstance(); + }; + + /// ThreadLocal - A class used to abstract thread-local storage. It holds, + /// for each thread, a pointer a single object of type T. + template<class T> + class ThreadLocal : public ThreadLocalImpl { + public: + ThreadLocal() : ThreadLocalImpl() { } + + /// get - Fetches a pointer to the object associated with the current + /// thread. If no object has yet been associated, it returns NULL; + T* get() { return static_cast<T*>(getInstance()); } + + // set - Associates a pointer to an object with the current thread. + void set(T* d) { setInstance(d); } + + // erase - Removes the pointer associated with the current thread. + void erase() { removeInstance(); } + }; + } +} + +#endif diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt index 9b5402fa54f0f..46469c6e9e624 100644 --- a/llvm/lib/Support/CMakeLists.txt +++ b/llvm/lib/Support/CMakeLists.txt @@ -260,6 +260,7 @@ add_llvm_component_library(LLVMSupport Program.cpp RWMutex.cpp Signals.cpp + ThreadLocal.cpp Threading.cpp Valgrind.cpp Watchdog.cpp diff --git a/llvm/lib/Support/CrashRecoveryContext.cpp b/llvm/lib/Support/CrashRecoveryContext.cpp index 9e792d1f51777..c7c384c9edc22 100644 --- a/llvm/lib/Support/CrashRecoveryContext.cpp +++ b/llvm/lib/Support/CrashRecoveryContext.cpp @@ -11,6 +11,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ExitCodes.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/ThreadLocal.h" #include "llvm/Support/thread.h" #include <mutex> #include <setjmp.h> @@ -20,7 +21,11 @@ using namespace llvm; namespace { struct CrashRecoveryContextImpl; -LLVM_THREAD_LOCAL static const CrashRecoveryContextImpl *CurrentContext; + +sys::ThreadLocal<const CrashRecoveryContextImpl> &getCurrentContext() { + static sys::ThreadLocal<const CrashRecoveryContextImpl> CurrentContext; + return CurrentContext; +} struct CrashRecoveryContextImpl { // When threads are disabled, this links up all active @@ -38,12 +43,12 @@ struct CrashRecoveryContextImpl { public: CrashRecoveryContextImpl(CrashRecoveryContext *CRC) noexcept : CRC(CRC), Failed(false), SwitchedThread(false), ValidJumpBuffer(false) { - Next = CurrentContext; - CurrentContext = this; + Next = getCurrentContext().get(); + getCurrentContext().set(this); } ~CrashRecoveryContextImpl() { if (!SwitchedThread) - CurrentContext = Next; + getCurrentContext().set(Next); } /// Called when the separate crash-recovery thread was finished, to @@ -61,7 +66,7 @@ struct CrashRecoveryContextImpl { void HandleCrash(int RetCode, uintptr_t Context) { // Eliminate the current context entry, to avoid re-entering in case the // cleanup code crashes. - CurrentContext = Next; + getCurrentContext().set(Next); assert(!Failed && "Crash recovery context already failed!"); Failed = true; @@ -87,7 +92,10 @@ std::mutex &getCrashRecoveryContextMutex() { static bool gCrashRecoveryEnabled = false; -LLVM_THREAD_LOCAL static const CrashRecoveryContext *IsRecoveringFromCrash; +sys::ThreadLocal<const CrashRecoveryContext> &getIsRecoveringFromCrash() { + static sys::ThreadLocal<const CrashRecoveryContext> IsRecoveringFromCrash; + return IsRecoveringFromCrash; +} } // namespace @@ -106,8 +114,8 @@ CrashRecoveryContext::CrashRecoveryContext() { CrashRecoveryContext::~CrashRecoveryContext() { // Reclaim registered resources. CrashRecoveryContextCleanup *i = head; - const CrashRecoveryContext *PC = IsRecoveringFromCrash; - IsRecoveringFromCrash = this; + const CrashRecoveryContext *PC = getIsRecoveringFromCrash().get(); + getIsRecoveringFromCrash().set(this); while (i) { CrashRecoveryContextCleanup *tmp = i; i = tmp->next; @@ -115,21 +123,21 @@ CrashRecoveryContext::~CrashRecoveryContext() { tmp->recoverResources(); delete tmp; } - IsRecoveringFromCrash = PC; + getIsRecoveringFromCrash().set(PC); CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl; delete CRCI; } bool CrashRecoveryContext::isRecoveringFromCrash() { - return IsRecoveringFromCrash != nullptr; + return getIsRecoveringFromCrash().get() != nullptr; } CrashRecoveryContext *CrashRecoveryContext::GetCurrent() { if (!gCrashRecoveryEnabled) return nullptr; - const CrashRecoveryContextImpl *CRCI = CurrentContext; + const CrashRecoveryContextImpl *CRCI = getCurrentContext().get(); if (!CRCI) return nullptr; @@ -199,7 +207,7 @@ static void uninstallExceptionOrSignalHandlers() {} // occur inside the __except evaluation block static int ExceptionFilter(_EXCEPTION_POINTERS *Except) { // Lookup the current thread local recovery object. - const CrashRecoveryContextImpl *CRCI = CurrentContext; + const CrashRecoveryContextImpl *CRCI = getCurrentContext().get(); if (!CRCI) { // Something has gone horribly wrong, so let's just tell everyone @@ -276,7 +284,7 @@ static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) } // Lookup the current thread local recovery object. - const CrashRecoveryContextImpl *CRCI = CurrentContext; + const CrashRecoveryContextImpl *CRCI = getCurrentContext().get(); if (!CRCI) { // Something has gone horribly wrong, so let's just tell everyone @@ -350,7 +358,7 @@ static struct sigaction PrevActions[NumSignals]; static void CrashRecoverySignalHandler(int Signal) { // Lookup the current thread local recovery object. - const CrashRecoveryContextImpl *CRCI = CurrentContext; + const CrashRecoveryContextImpl *CRCI = getCurrentContext().get(); if (!CRCI) { // We didn't find a crash recovery context -- this means either we got a diff --git a/llvm/lib/Support/ThreadLocal.cpp b/llvm/lib/Support/ThreadLocal.cpp new file mode 100644 index 0000000000000..44e6223cf17b6 --- /dev/null +++ b/llvm/lib/Support/ThreadLocal.cpp @@ -0,0 +1,47 @@ +//===- ThreadLocal.cpp - Thread Local Data ----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the llvm::sys::ThreadLocal class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/ThreadLocal.h" +#include "llvm/Config/llvm-config.h" +#include "llvm/Support/Compiler.h" + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only TRULY operating system +//=== independent code. +//===----------------------------------------------------------------------===// + +#if !defined(LLVM_ENABLE_THREADS) || LLVM_ENABLE_THREADS == 0 +// Define all methods as no-ops if threading is explicitly disabled +namespace llvm { +using namespace sys; +ThreadLocalImpl::ThreadLocalImpl() : data() { } +ThreadLocalImpl::~ThreadLocalImpl() { } +void ThreadLocalImpl::setInstance(const void* d) { + static_assert(sizeof(d) <= sizeof(data), "size too big"); + void **pd = reinterpret_cast<void**>(&data); + *pd = const_cast<void*>(d); +} +void *ThreadLocalImpl::getInstance() { + void **pd = reinterpret_cast<void**>(&data); + return *pd; +} +void ThreadLocalImpl::removeInstance() { + setInstance(nullptr); +} +} +#elif defined(LLVM_ON_UNIX) +#include "Unix/ThreadLocal.inc" +#elif defined( _WIN32) +#include "Windows/ThreadLocal.inc" +#else +#warning Neither LLVM_ON_UNIX nor _WIN32 set in Support/ThreadLocal.cpp +#endif diff --git a/llvm/lib/Support/Unix/ThreadLocal.inc b/llvm/lib/Support/Unix/ThreadLocal.inc new file mode 100644 index 0000000000000..483c5b0d324e1 --- /dev/null +++ b/llvm/lib/Support/Unix/ThreadLocal.inc @@ -0,0 +1,57 @@ +//=== llvm/Support/Unix/ThreadLocal.inc - Unix Thread Local Data -*- C++ +//-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the Unix specific (non-pthread) ThreadLocal class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" + +#include <cassert> +#include <pthread.h> +#include <stdlib.h> + +namespace llvm { +using namespace sys; + +ThreadLocalImpl::ThreadLocalImpl() : data() { + static_assert(sizeof(pthread_key_t) <= sizeof(data), "size too big"); + pthread_key_t *key = reinterpret_cast<pthread_key_t *>(&data); + int errorcode = pthread_key_create(key, nullptr); + assert(errorcode == 0); + (void)errorcode; +} + +ThreadLocalImpl::~ThreadLocalImpl() { + pthread_key_t *key = reinterpret_cast<pthread_key_t *>(&data); + int errorcode = pthread_key_delete(*key); + assert(errorcode == 0); + (void)errorcode; +} + +void ThreadLocalImpl::setInstance(const void *d) { + pthread_key_t *key = reinterpret_cast<pthread_key_t *>(&data); + int errorcode = pthread_setspecific(*key, d); + assert(errorcode == 0); + (void)errorcode; +} + +void *ThreadLocalImpl::getInstance() { + pthread_key_t *key = reinterpret_cast<pthread_key_t *>(&data); + return pthread_getspecific(*key); +} + +void ThreadLocalImpl::removeInstance() { setInstance(nullptr); } + +} // namespace llvm diff --git a/llvm/lib/Support/Windows/ThreadLocal.inc b/llvm/lib/Support/Windows/ThreadLocal.inc new file mode 100644 index 0000000000000..900444d11b25c --- /dev/null +++ b/llvm/lib/Support/Windows/ThreadLocal.inc @@ -0,0 +1,50 @@ +//= llvm/Support/Win32/ThreadLocal.inc - Win32 Thread Local Data -*- C++ +//-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the Win32 specific (non-pthread) ThreadLocal class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic Win32 code that +//=== is guaranteed to work on *all* Win32 variants. +//===----------------------------------------------------------------------===// + +#include "llvm/Support/ThreadLocal.h" +#include "llvm/Support/Windows/WindowsSupport.h" + +namespace llvm { + +sys::ThreadLocalImpl::ThreadLocalImpl() : data() { + static_assert(sizeof(DWORD) <= sizeof(data), "size too big"); + DWORD *tls = reinterpret_cast<DWORD *>(&data); + *tls = TlsAlloc(); + assert(*tls != TLS_OUT_OF_INDEXES); +} + +sys::ThreadLocalImpl::~ThreadLocalImpl() { + DWORD *tls = reinterpret_cast<DWORD *>(&data); + TlsFree(*tls); +} + +void *sys::ThreadLocalImpl::getInstance() { + DWORD *tls = reinterpret_cast<DWORD *>(&data); + return TlsGetValue(*tls); +} + +void sys::ThreadLocalImpl::setInstance(const void *d) { + DWORD *tls = reinterpret_cast<DWORD *>(&data); + int errorcode = TlsSetValue(*tls, const_cast<void *>(d)); + assert(errorcode != 0); + (void)errorcode; +} + +void sys::ThreadLocalImpl::removeInstance() { setInstance(0); } + +} // namespace llvm diff --git a/llvm/unittests/Support/CMakeLists.txt b/llvm/unittests/Support/CMakeLists.txt index d987d65db13ea..ccffb42e267eb 100644 --- a/llvm/unittests/Support/CMakeLists.txt +++ b/llvm/unittests/Support/CMakeLists.txt @@ -80,6 +80,7 @@ add_llvm_unittest(SupportTests SymbolRemappingReaderTest.cpp TarWriterTest.cpp TaskQueueTest.cpp + ThreadLocalTest.cpp ThreadPool.cpp Threading.cpp TimerTest.cpp diff --git a/llvm/unittests/Support/ThreadLocalTest.cpp b/llvm/unittests/Support/ThreadLocalTest.cpp new file mode 100644 index 0000000000000..454e4f21a05fe --- /dev/null +++ b/llvm/unittests/Support/ThreadLocalTest.cpp @@ -0,0 +1,54 @@ +//===- llvm/unittest/Support/ThreadLocalTest.cpp - ThreadLocal tests ------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/ThreadLocal.h" +#include "gtest/gtest.h" +#include <type_traits> + +using namespace llvm; +using namespace sys; + +namespace { + +class ThreadLocalTest : public ::testing::Test { +}; + +struct S { + int i; +}; + +TEST_F(ThreadLocalTest, Basics) { + ThreadLocal<const S> x; + + static_assert(std::is_const_v<std::remove_pointer_t<decltype(x.get())>>, + "ThreadLocal::get didn't return a pointer to const object"); + + EXPECT_EQ(nullptr, x.get()); + + S s; + x.set(&s); + EXPECT_EQ(&s, x.get()); + + x.erase(); + EXPECT_EQ(nullptr, x.get()); + + ThreadLocal<S> y; + + static_assert(!std::is_const_v<std::remove_pointer_t<decltype(y.get())>>, + "ThreadLocal::get returned a pointer to const object"); + + EXPECT_EQ(nullptr, y.get()); + + y.set(&s); + EXPECT_EQ(&s, y.get()); + + y.erase(); + EXPECT_EQ(nullptr, y.get()); +} + +} diff --git a/mlir/include/mlir/Support/ThreadLocalCache.h b/mlir/include/mlir/Support/ThreadLocalCache.h index e98fae6b117ae..083956b717422 100644 --- a/mlir/include/mlir/Support/ThreadLocalCache.h +++ b/mlir/include/mlir/Support/ThreadLocalCache.h @@ -18,6 +18,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Mutex.h" +#include "llvm/Support/ThreadLocal.h" namespace mlir { /// This class provides support for defining a thread local object with non _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits