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 
19 namespace lldb_private {
20 
21 namespace imp {
22 template <typename T>
23 class shared_ptr_refcount : public lldb_private::imp::shared_count {
24 public:
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 
34 private:
35   T *manager;
36 };
37 
38 } // namespace imp
39 
40 template <class T> class ClusterManager {
41 public:
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 
76 private:
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