1254721Semaste//===------------------SharedCluster.h --------------------------*- C++ -*-===//
2254721Semaste//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6254721Semaste//
7254721Semaste//===----------------------------------------------------------------------===//
8254721Semaste
9254721Semaste#ifndef utility_SharedCluster_h_
10254721Semaste#define utility_SharedCluster_h_
11254721Semaste
12309124Sdim#include "lldb/Utility/LLDBAssert.h"
13254721Semaste#include "lldb/Utility/SharingPtr.h"
14254721Semaste
15276479Sdim#include "llvm/ADT/SmallPtrSet.h"
16276479Sdim
17341825Sdim#include <mutex>
18341825Sdim
19254721Semastenamespace lldb_private {
20254721Semaste
21314564Sdimnamespace imp {
22314564Sdimtemplate <typename T>
23314564Sdimclass shared_ptr_refcount : public lldb_private::imp::shared_count {
24314564Sdimpublic:
25314564Sdim  template <class Y>
26314564Sdim  shared_ptr_refcount(Y *in) : shared_count(0), manager(in) {}
27296417Sdim
28314564Sdim  shared_ptr_refcount() : shared_count(0) {}
29254721Semaste
30314564Sdim  ~shared_ptr_refcount() override {}
31314564Sdim
32314564Sdim  void on_zero_shared() override { manager->DecrementRefCount(); }
33314564Sdim
34314564Sdimprivate:
35314564Sdim  T *manager;
36314564Sdim};
37314564Sdim
38254721Semaste} // namespace imp
39254721Semaste
40314564Sdimtemplate <class T> class ClusterManager {
41254721Semastepublic:
42314564Sdim  ClusterManager() : m_objects(), m_external_ref(0), m_mutex() {}
43309124Sdim
44314564Sdim  ~ClusterManager() {
45314564Sdim    for (typename llvm::SmallPtrSet<T *, 16>::iterator pos = m_objects.begin(),
46314564Sdim                                                       end = m_objects.end();
47314564Sdim         pos != end; ++pos) {
48314564Sdim      T *object = *pos;
49314564Sdim      delete object;
50254721Semaste    }
51309124Sdim
52341825Sdim    // Decrement refcount should have been called on this ClusterManager, and
53341825Sdim    // it should have locked the mutex, now we will unlock it before we destroy
54341825Sdim    // it...
55314564Sdim    m_mutex.unlock();
56314564Sdim  }
57309124Sdim
58314564Sdim  void ManageObject(T *new_object) {
59314564Sdim    std::lock_guard<std::mutex> guard(m_mutex);
60314564Sdim    m_objects.insert(new_object);
61314564Sdim  }
62314564Sdim
63314564Sdim  typename lldb_private::SharingPtr<T> GetSharedPointer(T *desired_object) {
64254721Semaste    {
65314564Sdim      std::lock_guard<std::mutex> guard(m_mutex);
66314564Sdim      m_external_ref++;
67314564Sdim      if (0 == m_objects.count(desired_object)) {
68314564Sdim        lldbassert(false && "object not found in shared cluster when expected");
69314564Sdim        desired_object = nullptr;
70314564Sdim      }
71254721Semaste    }
72314564Sdim    return typename lldb_private::SharingPtr<T>(
73314564Sdim        desired_object, new imp::shared_ptr_refcount<ClusterManager>(this));
74314564Sdim  }
75309124Sdim
76254721Semasteprivate:
77314564Sdim  void DecrementRefCount() {
78314564Sdim    m_mutex.lock();
79314564Sdim    m_external_ref--;
80314564Sdim    if (m_external_ref == 0)
81314564Sdim      delete this;
82314564Sdim    else
83314564Sdim      m_mutex.unlock();
84314564Sdim  }
85309124Sdim
86314564Sdim  friend class imp::shared_ptr_refcount<ClusterManager>;
87309124Sdim
88314564Sdim  llvm::SmallPtrSet<T *, 16> m_objects;
89314564Sdim  int m_external_ref;
90314564Sdim  std::mutex m_mutex;
91254721Semaste};
92254721Semaste
93254721Semaste} // namespace lldb_private
94296417Sdim
95254721Semaste#endif // utility_SharedCluster_h_
96