[Mlir-commits] [mlir] 44003d7 - Revert "Fix tsan problem where the per-thread shared_ptr() can be locked right before the cache is destroyed causing a race where it tries to remove an entry from a destroyed cache."

Mitch Phillips llvmlistbot at llvm.org
Wed Feb 1 10:36:30 PST 2023


Author: Mitch Phillips
Date: 2023-02-01T10:35:56-08:00
New Revision: 44003d719dd3e39df2ba122fc91865d8bff738c3

URL: https://github.com/llvm/llvm-project/commit/44003d719dd3e39df2ba122fc91865d8bff738c3
DIFF: https://github.com/llvm/llvm-project/commit/44003d719dd3e39df2ba122fc91865d8bff738c3.diff

LOG: Revert "Fix tsan problem where the per-thread shared_ptr() can be locked right before the cache is destroyed causing a race where it tries to remove an entry from a destroyed cache."

This reverts commit bcc10817d5569172ee065015747e226280e9b698.

Reason: Broke the aarch64-asan bot. More information available in the
Phabricator review: https://reviews.llvm.org/D140931

Added: 
    

Modified: 
    mlir/include/mlir/Support/ThreadLocalCache.h

Removed: 
    


################################################################################
diff  --git a/mlir/include/mlir/Support/ThreadLocalCache.h b/mlir/include/mlir/Support/ThreadLocalCache.h
index 1be94ca14bcfa..e98fae6b117ae 100644
--- a/mlir/include/mlir/Support/ThreadLocalCache.h
+++ b/mlir/include/mlir/Support/ThreadLocalCache.h
@@ -25,40 +25,12 @@ namespace mlir {
 /// cache has very large lock contention.
 template <typename ValueT>
 class ThreadLocalCache {
-  // Keep a separate shared_ptr protected state that can be acquired atomically
-  // instead of using shared_ptr's for each value. This avoids a problem
-  // where the instance shared_ptr is locked() successfully, and then the
-  // ThreadLocalCache gets destroyed before remove() can be called successfully.
-  struct PerInstanceState {
-    /// Remove the given value entry. This is generally called when a thread
-    /// local cache is destructing.
-    void remove(ValueT *value) {
-      // Erase the found value directly, because it is guaranteed to be in the
-      // list.
-      llvm::sys::SmartScopedLock<true> threadInstanceLock(instanceMutex);
-      auto it =
-          llvm::find_if(instances, [&](std::unique_ptr<ValueT> &instance) {
-            return instance.get() == value;
-          });
-      assert(it != instances.end() && "expected value to exist in cache");
-      instances.erase(it);
-    }
-
-    /// Owning pointers to all of the values that have been constructed for this
-    /// object in the static cache.
-    SmallVector<std::unique_ptr<ValueT>, 1> instances;
-
-    /// A mutex used when a new thread instance has been added to the cache for
-    /// this object.
-    llvm::sys::SmartMutex<true> instanceMutex;
-  };
-
   /// The type used for the static thread_local cache. This is a map between an
   /// instance of the non-static cache and a weak reference to an instance of
   /// ValueT. We use a weak reference here so that the object can be destroyed
   /// without needing to lock access to the cache itself.
-  struct CacheType
-      : public llvm::SmallDenseMap<PerInstanceState *, std::weak_ptr<ValueT>> {
+  struct CacheType : public llvm::SmallDenseMap<ThreadLocalCache<ValueT> *,
+                                                std::weak_ptr<ValueT>> {
     ~CacheType() {
       // Remove the values of this cache that haven't already expired.
       for (auto &it : *this)
@@ -88,16 +60,15 @@ class ThreadLocalCache {
   ValueT &get() {
     // Check for an already existing instance for this thread.
     CacheType &staticCache = getStaticCache();
-    std::weak_ptr<ValueT> &threadInstance = staticCache[perInstanceState.get()];
+    std::weak_ptr<ValueT> &threadInstance = staticCache[this];
     if (std::shared_ptr<ValueT> value = threadInstance.lock())
       return *value;
 
     // Otherwise, create a new instance for this thread.
-    llvm::sys::SmartScopedLock<true> threadInstanceLock(
-        perInstanceState->instanceMutex);
-    perInstanceState->instances.push_back(std::make_unique<ValueT>());
-    ValueT *instance = perInstanceState->instances.back().get();
-    threadInstance = std::shared_ptr<ValueT>(perInstanceState, instance);
+    llvm::sys::SmartScopedLock<true> threadInstanceLock(instanceMutex);
+    instances.push_back(std::make_shared<ValueT>());
+    std::shared_ptr<ValueT> &instance = instances.back();
+    threadInstance = instance;
 
     // Before returning the new instance, take the chance to clear out any used
     // entries in the static map. The cache is only cleared within the same
@@ -119,8 +90,26 @@ class ThreadLocalCache {
     return cache;
   }
 
-  std::shared_ptr<PerInstanceState> perInstanceState =
-      std::make_shared<PerInstanceState>();
+  /// Remove the given value entry. This is generally called when a thread local
+  /// cache is destructing.
+  void remove(ValueT *value) {
+    // Erase the found value directly, because it is guaranteed to be in the
+    // list.
+    llvm::sys::SmartScopedLock<true> threadInstanceLock(instanceMutex);
+    auto it = llvm::find_if(instances, [&](std::shared_ptr<ValueT> &instance) {
+      return instance.get() == value;
+    });
+    assert(it != instances.end() && "expected value to exist in cache");
+    instances.erase(it);
+  }
+
+  /// Owning pointers to all of the values that have been constructed for this
+  /// object in the static cache.
+  SmallVector<std::shared_ptr<ValueT>, 1> instances;
+
+  /// A mutex used when a new thread instance has been added to the cache for
+  /// this object.
+  llvm::sys::SmartMutex<true> instanceMutex;
 };
 } // namespace mlir
 


        


More information about the Mlir-commits mailing list