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