SharedCluster.h revision 353358
138363Swpaul//===------------------SharedCluster.h --------------------------*- C++ -*-===//
238363Swpaul//
338363Swpaul// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
438363Swpaul// See https://llvm.org/LICENSE.txt for license information.
538363Swpaul// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
638363Swpaul//
738363Swpaul//===----------------------------------------------------------------------===//
838363Swpaul
938363Swpaul#ifndef utility_SharedCluster_h_
1038363Swpaul#define utility_SharedCluster_h_
1138363Swpaul
1238363Swpaul#include "lldb/Utility/LLDBAssert.h"
1338363Swpaul#include "lldb/Utility/SharingPtr.h"
1438363Swpaul
1538363Swpaul#include "llvm/ADT/SmallPtrSet.h"
1638363Swpaul
1738363Swpaul#include <mutex>
1838363Swpaul
1938363Swpaulnamespace lldb_private {
2038363Swpaul
2138363Swpaulnamespace imp {
2238363Swpaultemplate <typename T>
2338363Swpaulclass shared_ptr_refcount : public lldb_private::imp::shared_count {
2438363Swpaulpublic:
2538363Swpaul  template <class Y>
2638363Swpaul  shared_ptr_refcount(Y *in) : shared_count(0), manager(in) {}
2738363Swpaul
2838363Swpaul  shared_ptr_refcount() : shared_count(0) {}
2938363Swpaul
3038363Swpaul  ~shared_ptr_refcount() override {}
3138363Swpaul
3246514Swpaul  void on_zero_shared() override { manager->DecrementRefCount(); }
3338363Swpaul
3438363Swpaulprivate:
3538363Swpaul  T *manager;
3638363Swpaul};
3738363Swpaul
3838363Swpaul} // namespace imp
3938363Swpaul
4038363Swpaultemplate <class T> class ClusterManager {
4138363Swpaulpublic:
4238363Swpaul  ClusterManager() : m_objects(), m_external_ref(0), m_mutex() {}
4338363Swpaul
4438363Swpaul  ~ClusterManager() {
4538363Swpaul    for (typename llvm::SmallPtrSet<T *, 16>::iterator pos = m_objects.begin(),
4638363Swpaul                                                       end = m_objects.end();
4738363Swpaul         pos != end; ++pos) {
4838363Swpaul      T *object = *pos;
4938363Swpaul      delete object;
5038363Swpaul    }
5138363Swpaul
5238363Swpaul    // Decrement refcount should have been called on this ClusterManager, and
5338363Swpaul    // it should have locked the mutex, now we will unlock it before we destroy
5438363Swpaul    // it...
5538363Swpaul    m_mutex.unlock();
5638363Swpaul  }
5738363Swpaul
5838363Swpaul  void ManageObject(T *new_object) {
5938363Swpaul    std::lock_guard<std::mutex> guard(m_mutex);
6038363Swpaul    m_objects.insert(new_object);
6138363Swpaul  }
6238363Swpaul
6338363Swpaul  typename lldb_private::SharingPtr<T> GetSharedPointer(T *desired_object) {
6438363Swpaul    {
6538363Swpaul      std::lock_guard<std::mutex> guard(m_mutex);
6638363Swpaul      m_external_ref++;
6738363Swpaul      if (0 == m_objects.count(desired_object)) {
6838363Swpaul        lldbassert(false && "object not found in shared cluster when expected");
6938363Swpaul        desired_object = nullptr;
7038363Swpaul      }
7138363Swpaul    }
7238363Swpaul    return typename lldb_private::SharingPtr<T>(
7338363Swpaul        desired_object, new imp::shared_ptr_refcount<ClusterManager>(this));
7438363Swpaul  }
7538363Swpaul
7638363Swpaulprivate:
7738363Swpaul  void DecrementRefCount() {
7838363Swpaul    m_mutex.lock();
7938363Swpaul    m_external_ref--;
8038363Swpaul    if (m_external_ref == 0)
8138363Swpaul      delete this;
8238363Swpaul    else
8338363Swpaul      m_mutex.unlock();
8438363Swpaul  }
8538363Swpaul
8638363Swpaul  friend class imp::shared_ptr_refcount<ClusterManager>;
8738363Swpaul
8838363Swpaul  llvm::SmallPtrSet<T *, 16> m_objects;
8938363Swpaul  int m_external_ref;
9038363Swpaul  std::mutex m_mutex;
9138363Swpaul};
9238363Swpaul
9338363Swpaul} // namespace lldb_private
9438363Swpaul
9538363Swpaul#endif // utility_SharedCluster_h_
9638363Swpaul