SharedCluster.h revision 353358
1219019Sgabor//===------------------SharedCluster.h --------------------------*- C++ -*-===//
2264497Stijl//
3219019Sgabor// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4219019Sgabor// See https://llvm.org/LICENSE.txt for license information.
5219019Sgabor// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6219019Sgabor//
7219019Sgabor//===----------------------------------------------------------------------===//
8219019Sgabor
9219019Sgabor#ifndef utility_SharedCluster_h_
10219019Sgabor#define utility_SharedCluster_h_
11219019Sgabor
12219019Sgabor#include "lldb/Utility/LLDBAssert.h"
13219019Sgabor#include "lldb/Utility/SharingPtr.h"
14219019Sgabor
15219019Sgabor#include "llvm/ADT/SmallPtrSet.h"
16219019Sgabor
17219019Sgabor#include <mutex>
18219019Sgabor
19219019Sgabornamespace lldb_private {
20219019Sgabor
21219019Sgabornamespace imp {
22219019Sgabortemplate <typename T>
23219019Sgaborclass shared_ptr_refcount : public lldb_private::imp::shared_count {
24219019Sgaborpublic:
25219019Sgabor  template <class Y>
26219019Sgabor  shared_ptr_refcount(Y *in) : shared_count(0), manager(in) {}
27219019Sgabor
28219019Sgabor  shared_ptr_refcount() : shared_count(0) {}
29219019Sgabor
30219019Sgabor  ~shared_ptr_refcount() override {}
31219019Sgabor
32219019Sgabor  void on_zero_shared() override { manager->DecrementRefCount(); }
33219019Sgabor
34219019Sgaborprivate:
35219019Sgabor  T *manager;
36219019Sgabor};
37219019Sgabor
38219019Sgabor} // namespace imp
39219019Sgabor
40219019Sgabortemplate <class T> class ClusterManager {
41219019Sgaborpublic:
42219019Sgabor  ClusterManager() : m_objects(), m_external_ref(0), m_mutex() {}
43219019Sgabor
44219019Sgabor  ~ClusterManager() {
45219019Sgabor    for (typename llvm::SmallPtrSet<T *, 16>::iterator pos = m_objects.begin(),
46219019Sgabor                                                       end = m_objects.end();
47219019Sgabor         pos != end; ++pos) {
48219019Sgabor      T *object = *pos;
49219019Sgabor      delete object;
50219019Sgabor    }
51219019Sgabor
52219019Sgabor    // Decrement refcount should have been called on this ClusterManager, and
53219019Sgabor    // it should have locked the mutex, now we will unlock it before we destroy
54219019Sgabor    // it...
55219019Sgabor    m_mutex.unlock();
56219019Sgabor  }
57219019Sgabor
58219019Sgabor  void ManageObject(T *new_object) {
59219019Sgabor    std::lock_guard<std::mutex> guard(m_mutex);
60219019Sgabor    m_objects.insert(new_object);
61219019Sgabor  }
62219019Sgabor
63219019Sgabor  typename lldb_private::SharingPtr<T> GetSharedPointer(T *desired_object) {
64219019Sgabor    {
65219019Sgabor      std::lock_guard<std::mutex> guard(m_mutex);
66219019Sgabor      m_external_ref++;
67219019Sgabor      if (0 == m_objects.count(desired_object)) {
68219019Sgabor        lldbassert(false && "object not found in shared cluster when expected");
69219019Sgabor        desired_object = nullptr;
70219019Sgabor      }
71219019Sgabor    }
72219019Sgabor    return typename lldb_private::SharingPtr<T>(
73219019Sgabor        desired_object, new imp::shared_ptr_refcount<ClusterManager>(this));
74219019Sgabor  }
75219019Sgabor
76219019Sgaborprivate:
77219019Sgabor  void DecrementRefCount() {
78219019Sgabor    m_mutex.lock();
79219019Sgabor    m_external_ref--;
80219019Sgabor    if (m_external_ref == 0)
81219019Sgabor      delete this;
82219019Sgabor    else
83219019Sgabor      m_mutex.unlock();
84219019Sgabor  }
85219019Sgabor
86219019Sgabor  friend class imp::shared_ptr_refcount<ClusterManager>;
87219019Sgabor
88219019Sgabor  llvm::SmallPtrSet<T *, 16> m_objects;
89219019Sgabor  int m_external_ref;
90219019Sgabor  std::mutex m_mutex;
91219019Sgabor};
92219019Sgabor
93219019Sgabor} // namespace lldb_private
94219019Sgabor
95219019Sgabor#endif // utility_SharedCluster_h_
96219019Sgabor