1//===------------------SharedCluster.h --------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef utility_SharedCluster_h_
10#define utility_SharedCluster_h_
11
12#include "lldb/Utility/LLDBAssert.h"
13#include "lldb/Utility/SharingPtr.h"
14
15#include "llvm/ADT/SmallPtrSet.h"
16
17#include <mutex>
18
19namespace lldb_private {
20
21namespace imp {
22template <typename T>
23class shared_ptr_refcount : public lldb_private::imp::shared_count {
24public:
25  template <class Y>
26  shared_ptr_refcount(Y *in) : shared_count(0), manager(in) {}
27
28  shared_ptr_refcount() : shared_count(0) {}
29
30  ~shared_ptr_refcount() override {}
31
32  void on_zero_shared() override { manager->DecrementRefCount(); }
33
34private:
35  T *manager;
36};
37
38} // namespace imp
39
40template <class T> class ClusterManager {
41public:
42  ClusterManager() : m_objects(), m_external_ref(0), m_mutex() {}
43
44  ~ClusterManager() {
45    for (typename llvm::SmallPtrSet<T *, 16>::iterator pos = m_objects.begin(),
46                                                       end = m_objects.end();
47         pos != end; ++pos) {
48      T *object = *pos;
49      delete object;
50    }
51
52    // Decrement refcount should have been called on this ClusterManager, and
53    // it should have locked the mutex, now we will unlock it before we destroy
54    // it...
55    m_mutex.unlock();
56  }
57
58  void ManageObject(T *new_object) {
59    std::lock_guard<std::mutex> guard(m_mutex);
60    m_objects.insert(new_object);
61  }
62
63  typename lldb_private::SharingPtr<T> GetSharedPointer(T *desired_object) {
64    {
65      std::lock_guard<std::mutex> guard(m_mutex);
66      m_external_ref++;
67      if (0 == m_objects.count(desired_object)) {
68        lldbassert(false && "object not found in shared cluster when expected");
69        desired_object = nullptr;
70      }
71    }
72    return typename lldb_private::SharingPtr<T>(
73        desired_object, new imp::shared_ptr_refcount<ClusterManager>(this));
74  }
75
76private:
77  void DecrementRefCount() {
78    m_mutex.lock();
79    m_external_ref--;
80    if (m_external_ref == 0)
81      delete this;
82    else
83      m_mutex.unlock();
84  }
85
86  friend class imp::shared_ptr_refcount<ClusterManager>;
87
88  llvm::SmallPtrSet<T *, 16> m_objects;
89  int m_external_ref;
90  std::mutex m_mutex;
91};
92
93} // namespace lldb_private
94
95#endif // utility_SharedCluster_h_
96