Changeset View
Changeset View
Standalone View
Standalone View
src/rcu.h
| // Copyright (c) 2018 The Bitcoin developers | // Copyright (c) 2018 The Bitcoin developers | ||||
| // Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
| // file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
| #ifndef BITCOIN_RCU_H | #ifndef BITCOIN_RCU_H | ||||
| #define BITCOIN_RCU_H | #define BITCOIN_RCU_H | ||||
| #include <boost/noncopyable.hpp> | #include <boost/noncopyable.hpp> | ||||
| #include <atomic> | #include <atomic> | ||||
| #include <cassert> | #include <cassert> | ||||
| #include <cstdint> | #include <cstdint> | ||||
| #include <functional> | #include <functional> | ||||
| #include <map> | #include <map> | ||||
| #include <type_traits> | |||||
| #include <utility> | |||||
| class RCUInfos; | class RCUInfos; | ||||
| class RCUReadLock; | class RCUReadLock; | ||||
| class RCUInfos { | class RCUInfos { | ||||
| std::atomic<uint64_t> state; | std::atomic<uint64_t> state; | ||||
| std::atomic<RCUInfos *> next; | std::atomic<RCUInfos *> next; | ||||
| ▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | public: | ||||
| static bool isLocked() { return RCUInfos::infos.isLocked(); } | static bool isLocked() { return RCUInfos::infos.isLocked(); } | ||||
| static void registerCleanup(const std::function<void()> &f) { | static void registerCleanup(const std::function<void()> &f) { | ||||
| RCUInfos::infos.registerCleanup(f); | RCUInfos::infos.registerCleanup(f); | ||||
| } | } | ||||
| static void synchronize() { RCUInfos::infos.synchronize(); } | static void synchronize() { RCUInfos::infos.synchronize(); } | ||||
| }; | }; | ||||
| template <typename T> class RCUPtr { | |||||
| T *ptr; | |||||
| public: | |||||
| RCUPtr() : ptr(nullptr) {} | |||||
| explicit RCUPtr(T *ptrIn) : ptr(ptrIn) {} | |||||
| ~RCUPtr() { | |||||
| if (ptr != nullptr) { | |||||
| ptr->release(); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Copy semantic. | |||||
| */ | |||||
| RCUPtr(const RCUPtr &src) : ptr(src.ptr) { | |||||
| if (ptr != nullptr) { | |||||
| ptr->acquire(); | |||||
| } | |||||
| } | |||||
| RCUPtr &operator=(const RCUPtr &rhs) { | |||||
| RCUPtr tmp(rhs); | |||||
| std::swap(ptr, tmp.ptr); | |||||
| return *this; | |||||
| } | |||||
| /** | |||||
| * Move semantic. | |||||
| */ | |||||
| RCUPtr(RCUPtr &&src) : RCUPtr() { std::swap(ptr, src.ptr); } | |||||
| RCUPtr &operator=(RCUPtr &&rhs) { | |||||
| std::swap(ptr, rhs.ptr); | |||||
| return *this; | |||||
| } | |||||
| /** | |||||
| * Accessors | |||||
| */ | |||||
| T *operator->() { return ptr; } | |||||
| }; | |||||
| //! Builds a RCUPtr from a newly allocated object. | |||||
| template <typename T, typename... Args> RCUPtr<T> make_rcuptr(Args &&... args) { | |||||
| return RCUPtr<T>(new T(std::forward<Args>(args)...)); | |||||
| } | |||||
| #define IMPLEMENT_RCU_REFCOUNT(T) \ | |||||
| private: \ | |||||
| std::atomic<T> refcount{0}; \ | |||||
| \ | |||||
| void acquire() { refcount++; } \ | |||||
| \ | |||||
| bool tryDecrement() { \ | |||||
| T count = refcount.load(); \ | |||||
| while (count > 0) { \ | |||||
| if (refcount.compare_exchange_weak(count, count - 1)) { \ | |||||
| return true; \ | |||||
| } \ | |||||
| } \ | |||||
| \ | |||||
| return false; \ | |||||
| } \ | |||||
| \ | |||||
| void release() { \ | |||||
| if (tryDecrement()) { \ | |||||
| return; \ | |||||
| } \ | |||||
| \ | |||||
| RCULock::registerCleanup([this] { \ | |||||
| if (tryDecrement()) { \ | |||||
| return; \ | |||||
| } \ | |||||
| \ | |||||
| delete this; \ | |||||
| }); \ | |||||
| } \ | |||||
| \ | |||||
| static_assert(std::is_integral<T>::value, "T must be an integral type."); \ | |||||
| static_assert(std::is_unsigned<T>::value, "T must be unsigned."); \ | |||||
| \ | |||||
| template <typename> friend class ::RCUPtr | |||||
| #endif // BITCOIN_RCU_H | #endif // BITCOIN_RCU_H | ||||