LLDB mainline
Locked.h
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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 LLDB_UTILITY_LOCKED_H
10#define LLDB_UTILITY_LOCKED_H
11
12#include "llvm/Support/RWMutex.h"
13
14#include <cassert>
15#include <memory>
16#include <mutex>
17#include <shared_mutex>
18#include <type_traits>
19#include <utility>
20
21namespace lldb_private {
22
23namespace detail {
24/// Common pointer-like accessors shared by `Locked` and `SharedLocked`.
25template <typename Derived, typename PtrT> class LockedAccessors {
26public:
27 auto operator->() const { return Raw(); }
28 decltype(auto) operator*() const { return *Self()->m_ptr; }
29 auto get() const { return Raw(); }
30 explicit operator bool() const { return Raw() != nullptr; }
31
32private:
33 const Derived *Self() const { return static_cast<const Derived *>(this); }
34
35 auto Raw() const {
36 if constexpr (std::is_pointer_v<PtrT>)
37 return Self()->m_ptr;
38 else
39 return Self()->m_ptr.get();
40 }
41};
42} // namespace detail
43
44/// A move-only RAII handle that pairs a pointer-like value with an exclusive
45/// lock on a caller-supplied mutex. While the handle is alive the borrowed
46/// pointer is serialized against other threads that go through the same
47/// mutex.
48///
49/// `PtrT` is the pointer-like value: a raw pointer (`T*`),
50/// `std::shared_ptr<T>`, or `std::unique_ptr<T>`. `Mutex` may be any type
51/// that satisfies `Lockable` — `std::mutex`, `std::recursive_mutex`,
52/// `std::shared_mutex`, or `llvm::sys::RWMutex` all work. Use the
53/// `LockedPtr`, `LockedSP`, `LockedUP` aliases for the common combinations.
54template <typename PtrT, typename Mutex = std::recursive_mutex>
55class Locked : public detail::LockedAccessors<Locked<PtrT, Mutex>, PtrT> {
56 friend class detail::LockedAccessors<Locked<PtrT, Mutex>, PtrT>;
57
58public:
59 using mutex_type = Mutex;
60 using lock_type = std::unique_lock<Mutex>;
61
62 Locked() = default;
63 Locked(mutex_type &m, PtrT p) : m_lock(m), m_ptr(std::move(p)) {}
64 Locked(lock_type lock, PtrT p)
65 : m_lock(std::move(lock)), m_ptr(std::move(p)) {
66 assert(m_lock.owns_lock() && "Locked requires an owning lock");
67 }
68
69 Locked(Locked &&other)
70 : m_lock(std::move(other.m_lock)),
71 m_ptr(std::exchange(other.m_ptr, PtrT{})) {}
73 m_lock = std::move(other.m_lock);
74 m_ptr = std::exchange(other.m_ptr, PtrT{});
75 return *this;
76 }
77 Locked(const Locked &) = delete;
78 Locked &operator=(const Locked &) = delete;
79
80private:
82 PtrT m_ptr{};
83};
84
85/// A copyable RAII handle that pairs a pointer-like value with a shared
86/// (reader) lock on a caller-supplied mutex. Copies share the same
87/// underlying reader lock through reference counting; the lock is released
88/// when the last copy is destroyed. This makes a `SharedLocked` cheap to
89/// pass through code paths that branch or fan out without each leaf having
90/// to re-acquire.
91///
92/// The borrowed pointer is `const`-qualified so callers cannot mutate the
93/// pointee while holding only a reader's lock. `Mutex` must satisfy
94/// `SharedLockable` — `llvm::sys::RWMutex` (the LLDB convention) or
95/// `std::shared_mutex`. Use the `SharedLockedPtr`, `SharedLockedSP`,
96/// `SharedLockedUP` aliases for the common combinations.
97template <typename PtrT, typename Mutex = llvm::sys::RWMutex>
99 : public detail::LockedAccessors<SharedLocked<PtrT, Mutex>, PtrT> {
100 friend class detail::LockedAccessors<SharedLocked<PtrT, Mutex>, PtrT>;
101
102 // The class is intended to be instantiated only via the
103 // SharedLockedPtr/SP/UP aliases, which all bake in `const`. Enforcing it
104 // here catches direct uses that would otherwise hand readers a mutable
105 // pointer.
106 static constexpr bool PointeeIsConst = []() {
107 if constexpr (std::is_pointer_v<PtrT>)
108 return std::is_const_v<std::remove_pointer_t<PtrT>>;
109 else
110 return std::is_const_v<typename PtrT::element_type>;
111 }();
112 static_assert(PointeeIsConst,
113 "SharedLocked requires a pointer to a const-qualified type; "
114 "use the SharedLockedPtr/SP/UP aliases.");
115
116public:
117 using mutex_type = Mutex;
118 using lock_type = std::shared_lock<Mutex>;
119
120 SharedLocked() = default;
122 : m_lock(std::make_shared<lock_type>(m)), m_ptr(std::move(p)) {}
124 : m_lock(std::make_shared<lock_type>(std::move(lock))),
125 m_ptr(std::move(p)) {
126 assert(m_lock->owns_lock() && "SharedLocked requires an owning lock");
127 }
128
129 SharedLocked(const SharedLocked &) = default;
132 : m_lock(std::move(other.m_lock)),
133 m_ptr(std::exchange(other.m_ptr, PtrT{})) {}
135 m_lock = std::move(other.m_lock);
136 m_ptr = std::exchange(other.m_ptr, PtrT{});
137 return *this;
138 }
139
140private:
141 std::shared_ptr<lock_type> m_lock;
142 PtrT m_ptr{};
143};
144
145/// Exclusive (write) access aliases. The default mutex is
146/// `std::recursive_mutex` to match the existing LLDB synchronization style.
147/// @{
148template <typename T, typename Mutex = std::recursive_mutex>
150
151template <typename T, typename Mutex = std::recursive_mutex>
153
154template <typename T, typename Mutex = std::recursive_mutex>
156/// @}
157
158/// Shared (read) access aliases. The default mutex is `llvm::sys::RWMutex`,
159/// the LLDB convention for read/write locks.
160/// @{
161template <typename T, typename Mutex = llvm::sys::RWMutex>
163
164template <typename T, typename Mutex = llvm::sys::RWMutex>
166
167template <typename T, typename Mutex = llvm::sys::RWMutex>
169/// @}
170
171} // namespace lldb_private
172
173#endif // LLDB_UTILITY_LOCKED_H
A move-only RAII handle that pairs a pointer-like value with an exclusive lock on a caller-supplied m...
Definition Locked.h:55
Locked(const Locked &)=delete
Locked(lock_type lock, PtrT p)
Definition Locked.h:64
Locked(mutex_type &m, PtrT p)
Definition Locked.h:63
Locked(Locked &&other)
Definition Locked.h:69
std::unique_lock< Mutex > lock_type
Definition Locked.h:60
Locked & operator=(const Locked &)=delete
Locked & operator=(Locked &&other)
Definition Locked.h:72
A copyable RAII handle that pairs a pointer-like value with a shared (reader) lock on a caller-suppli...
Definition Locked.h:99
SharedLocked(lock_type lock, PtrT p)
Definition Locked.h:123
SharedLocked(const SharedLocked &)=default
std::shared_lock< Mutex > lock_type
Definition Locked.h:118
SharedLocked & operator=(SharedLocked &&other)
Definition Locked.h:134
std::shared_ptr< lock_type > m_lock
Definition Locked.h:141
SharedLocked(SharedLocked &&other)
Definition Locked.h:131
SharedLocked(mutex_type &m, PtrT p)
Definition Locked.h:121
SharedLocked & operator=(const SharedLocked &)=default
Common pointer-like accessors shared by Locked and SharedLocked.
Definition Locked.h:25
const Derived * Self() const
Definition Locked.h:33
A class that represents a running process on the host machine.
SharedLocked< std::shared_ptr< const T >, Mutex > SharedLockedSP
Definition Locked.h:165
SharedLocked< std::unique_ptr< const T >, Mutex > SharedLockedUP
Definition Locked.h:168
Locked< T *, Mutex > LockedPtr
Exclusive (write) access aliases.
Definition Locked.h:149
Locked< std::unique_ptr< T >, Mutex > LockedUP
Definition Locked.h:155
Locked< std::shared_ptr< T >, Mutex > LockedSP
Definition Locked.h:152
SharedLocked< const T *, Mutex > SharedLockedPtr
Shared (read) access aliases.
Definition Locked.h:162