Bitcoin ABC 0.30.5
P2P Digital Currency
rcu.h
Go to the documentation of this file.
1// Copyright (c) 2018-2019 The Bitcoin developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#ifndef BITCOIN_RCU_H
6#define BITCOIN_RCU_H
7
8#include <atomic>
9#include <cassert>
10#include <cstdint>
11#include <functional>
12#include <map>
13#include <ostream>
14#include <type_traits>
15#include <utility>
16
17class RCUInfos;
18class RCUReadLock;
19
20class RCUInfos {
21 std::atomic<uint64_t> state;
22 std::atomic<RCUInfos *> next;
23
24 bool isCleaningUp = false;
25 class RCUCleanupGuard;
26
27 std::map<uint64_t, std::function<void()>> cleanups;
28
29 // The largest revision possible means unlocked.
30 static const uint64_t UNLOCKED = -uint64_t(1);
31
32 RCUInfos();
33 ~RCUInfos();
34
35 void readLock() {
36 assert(!isLocked());
37 state.store(revision.load());
38 }
39
40 void readFree() {
42 state.store(UNLOCKED);
43 }
44
45 bool isLocked() const { return state.load() != UNLOCKED; }
46 void registerCleanup(const std::function<void()> &f) {
47 cleanups.emplace(++revision, f);
48 }
49
50 void synchronize();
51 void runCleanups();
52 uint64_t hasSyncedTo(uint64_t cutoff = UNLOCKED);
53
54 friend class RCULock;
55 friend struct RCUTest;
56
57 static std::atomic<uint64_t> revision;
58 static thread_local RCUInfos infos;
59};
60
61class RCULock {
63
64 explicit RCULock(RCUInfos *infosIn) : infos(infosIn) { infos->readLock(); }
65 friend class RCUInfos;
66
67public:
70 infos->readFree();
72 }
73
74 RCULock(const RCULock &) = delete;
75 RCULock &operator=(const RCULock &) = delete;
76
77 static bool isLocked() { return RCUInfos::infos.isLocked(); }
78 static void registerCleanup(const std::function<void()> &f) {
80 }
81
83};
84
85template <typename T> class RCUPtr {
86 T *ptr;
87
88 // Private construction, so factories have to be used.
89 explicit RCUPtr(T *ptrIn) : ptr(ptrIn) {}
90
91public:
92 RCUPtr() : ptr(nullptr) {}
93
95 if (ptr != nullptr) {
96 ptr->decrementRefCount();
97 }
98 }
99
103 static RCUPtr acquire(T *&ptrIn) {
104 RCUPtr ret(ptrIn);
105 ptrIn = nullptr;
106 return ret;
107 }
108
112 template <typename... Args> static RCUPtr make(Args &&...args) {
113 return RCUPtr(new T(std::forward<Args>(args)...));
114 }
115
119 static RCUPtr copy(T *ptr) {
120 if (ptr != nullptr) {
121 ptr->incrementRefCount();
122 }
123
124 return RCUPtr::acquire(ptr);
125 }
126
130 RCUPtr(const RCUPtr &src) : ptr(src.ptr) {
131 if (ptr != nullptr) {
132 ptr->incrementRefCount();
133 }
134 }
135
136 RCUPtr &operator=(const RCUPtr &rhs) {
137 RCUPtr tmp(rhs);
138 std::swap(ptr, tmp.ptr);
139 return *this;
140 }
141
146 template <typename U> RCUPtr(const RCUPtr<U> &src) : ptr(src.get()) {
147 if (ptr != nullptr) {
148 ptr->incrementRefCount();
149 }
150 }
151
152 template <typename U> RCUPtr &operator=(const RCUPtr<U> &rhs) {
153 RCUPtr tmp(rhs);
154 std::swap(ptr, tmp.ptr);
155 return *this;
156 }
157
161 RCUPtr(RCUPtr &&src) : RCUPtr() { std::swap(ptr, src.ptr); }
163 std::swap(ptr, rhs.ptr);
164 return *this;
165 }
166
170 T *get() { return ptr; }
171 const T *get() const { return ptr; }
172
176 T *release() {
177 T *oldPtr = ptr;
178 ptr = nullptr;
179 return oldPtr;
180 }
181
185 T *operator->() { return ptr; }
186 const T *operator->() const { return ptr; }
187
188 T &operator*() { return *ptr; }
189 const T &operator*() const { return *ptr; }
190
191 explicit operator bool() const { return ptr != nullptr; }
192
196 friend bool operator==(const RCUPtr &lhs, const T *rhs) {
197 return lhs.get() == rhs;
198 }
199
200 friend bool operator==(const RCUPtr &lhs, const RCUPtr &rhs) {
201 return lhs == rhs.get();
202 }
203
204 friend bool operator!=(const RCUPtr &lhs, const T *rhs) {
205 return !(lhs == rhs);
206 }
207
208 friend bool operator!=(const RCUPtr &lhs, const RCUPtr &rhs) {
209 return !(lhs == rhs);
210 }
211
215 friend std::ostream &operator<<(std::ostream &stream, const RCUPtr &rhs) {
216 return stream << rhs.ptr;
217 }
218};
219
220#define IMPLEMENT_RCU_REFCOUNT(T) \
221private: \
222 mutable std::atomic<T> refcount{0}; \
223 \
224 void incrementRefCount() const { \
225 refcount++; \
226 } \
227 \
228 bool tryDecrement() const { \
229 T count = refcount.load(); \
230 while (count > 0) { \
231 if (refcount.compare_exchange_weak(count, count - 1)) { \
232 return true; \
233 } \
234 } \
235 \
236 return false; \
237 } \
238 \
239 void decrementRefCount() const { \
240 if (tryDecrement()) { \
241 return; \
242 } \
243 \
244 RCULock::registerCleanup([this] { \
245 if (tryDecrement()) { \
246 return; \
247 } \
248 \
249 delete this; \
250 }); \
251 } \
252 \
253 static_assert(std::is_integral<T>::value, "T must be an integral type."); \
254 static_assert(std::is_unsigned<T>::value, "T must be unsigned."); \
255 \
256 template <typename> friend class ::RCUPtr
257
259namespace std {
260template <typename T> struct hash<RCUPtr<T>> {
261 size_t operator()(const RCUPtr<T> &ptr) const noexcept {
262 return hash<decltype(ptr.get())>()(ptr.get());
263 }
264};
265} // end namespace std
266
267#endif // BITCOIN_RCU_H
Definition: rcu.h:20
bool isLocked() const
Definition: rcu.h:45
uint64_t hasSyncedTo(uint64_t cutoff=UNLOCKED)
Definition: rcu.cpp:235
std::atomic< RCUInfos * > next
Definition: rcu.h:22
void runCleanups()
Definition: rcu.cpp:208
~RCUInfos()
Definition: rcu.cpp:117
static const uint64_t UNLOCKED
Definition: rcu.h:30
static thread_local RCUInfos infos
Definition: rcu.h:58
std::map< uint64_t, std::function< void()> > cleanups
Definition: rcu.h:27
std::atomic< uint64_t > state
Definition: rcu.h:21
void readFree()
Definition: rcu.h:40
friend struct RCUTest
Definition: rcu.h:55
static std::atomic< uint64_t > revision
Definition: rcu.h:57
void registerCleanup(const std::function< void()> &f)
Definition: rcu.h:46
void synchronize()
Definition: rcu.cpp:169
bool isCleaningUp
Definition: rcu.h:24
RCUInfos()
Definition: rcu.cpp:107
void readLock()
Definition: rcu.h:35
Definition: rcu.h:61
static void registerCleanup(const std::function< void()> &f)
Definition: rcu.h:78
RCUInfos * infos
Definition: rcu.h:62
RCULock()
Definition: rcu.h:68
static bool isLocked()
Definition: rcu.h:77
RCULock & operator=(const RCULock &)=delete
RCULock(RCUInfos *infosIn)
Definition: rcu.h:64
static void synchronize()
Definition: rcu.h:82
RCULock(const RCULock &)=delete
~RCULock()
Definition: rcu.h:69
Definition: rcu.h:85
RCUPtr(RCUPtr &&src)
Move semantic.
Definition: rcu.h:161
const T * get() const
Definition: rcu.h:171
RCUPtr & operator=(const RCUPtr &rhs)
Definition: rcu.h:136
friend bool operator!=(const RCUPtr &lhs, const RCUPtr &rhs)
Definition: rcu.h:208
const T * operator->() const
Definition: rcu.h:186
friend bool operator!=(const RCUPtr &lhs, const T *rhs)
Definition: rcu.h:204
~RCUPtr()
Definition: rcu.h:94
friend bool operator==(const RCUPtr &lhs, const RCUPtr &rhs)
Definition: rcu.h:200
T * get()
Get allows to access the undelying pointer.
Definition: rcu.h:170
T * ptr
Definition: rcu.h:86
RCUPtr(T *ptrIn)
Definition: rcu.h:89
RCUPtr(const RCUPtr< U > &src)
Implicit converting constructor from RCUPtr to RCUPtr<T>, where U * is implicitely convertible to T *...
Definition: rcu.h:146
static RCUPtr acquire(T *&ptrIn)
Acquire ownership of some pointer.
Definition: rcu.h:103
static RCUPtr make(Args &&...args)
Construct a new object that is owned by the pointer.
Definition: rcu.h:112
T & operator*()
Definition: rcu.h:188
T * release()
Release transfers ownership of the pointer from RCUPtr to the caller.
Definition: rcu.h:176
RCUPtr()
Definition: rcu.h:92
friend std::ostream & operator<<(std::ostream &stream, const RCUPtr &rhs)
ostream support.
Definition: rcu.h:215
RCUPtr & operator=(const RCUPtr< U > &rhs)
Definition: rcu.h:152
T * operator->()
Operator overloading for convenience.
Definition: rcu.h:185
static RCUPtr copy(T *ptr)
Construct a new RCUPtr without transferring owership.
Definition: rcu.h:119
RCUPtr(const RCUPtr &src)
Copy semantic.
Definition: rcu.h:130
friend bool operator==(const RCUPtr &lhs, const T *rhs)
Equality checks.
Definition: rcu.h:196
RCUPtr & operator=(RCUPtr &&rhs)
Definition: rcu.h:162
const T & operator*() const
Definition: rcu.h:189
Implement std::hash so RCUPtr can be used as a key for maps or sets.
Definition: rcu.h:259
size_t operator()(const RCUPtr< T > &ptr) const noexcept
Definition: rcu.h:261
assert(!tx.IsCoinBase())