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 <map> | |||||
class RCUInfos; | class RCUInfos; | ||||
class RCUReadLock; | class RCUReadLock; | ||||
class RCUInfos { | class RCUInfos { | ||||
std::atomic<RCUInfos *> next; | |||||
std::atomic<uint64_t> state; | std::atomic<uint64_t> state; | ||||
std::atomic<RCUInfos *> next; | |||||
std::map<uint64_t, std::function<void()>> cleanups; | |||||
// The largest revision possible means unlocked. | // The largest revision possible means unlocked. | ||||
static const uint64_t UNLOCKED = -uint64_t(1); | static const uint64_t UNLOCKED = -uint64_t(1); | ||||
RCUInfos(); | RCUInfos(); | ||||
~RCUInfos(); | ~RCUInfos(); | ||||
void readLock() { | void readLock() { | ||||
assert(!isLocked()); | assert(!isLocked()); | ||||
state.store(revision.load()); | state.store(revision.load()); | ||||
} | } | ||||
void readFree() { | void readFree() { | ||||
assert(isLocked()); | assert(isLocked()); | ||||
state.store(UNLOCKED); | state.store(UNLOCKED); | ||||
} | } | ||||
bool isLocked() const { return state.load() != UNLOCKED; } | bool isLocked() const { return state.load() != UNLOCKED; } | ||||
void registerCleanup(const std::function<void()> &f) { | |||||
cleanups.emplace(++revision, f); | |||||
} | |||||
void synchronize(); | void synchronize(); | ||||
bool hasSynced(uint64_t syncRev); | void runCleanups(); | ||||
uint64_t hasSyncedTo(uint64_t cutoff = UNLOCKED); | |||||
friend class RCULock; | friend class RCULock; | ||||
friend struct RCUTest; | friend struct RCUTest; | ||||
static std::atomic<uint64_t> revision; | static std::atomic<uint64_t> revision; | ||||
static thread_local RCUInfos infos; | static thread_local RCUInfos infos; | ||||
}; | }; | ||||
class RCULock : public boost::noncopyable { | class RCULock : public boost::noncopyable { | ||||
RCUInfos *infos; | RCUInfos *infos; | ||||
RCULock(RCUInfos *infosIn) : infos(infosIn) { infos->readLock(); } | RCULock(RCUInfos *infosIn) : infos(infosIn) { infos->readLock(); } | ||||
friend class RCUInfos; | friend class RCUInfos; | ||||
public: | public: | ||||
RCULock() : RCULock(&RCUInfos::infos) {} | RCULock() : RCULock(&RCUInfos::infos) {} | ||||
~RCULock() { infos->readFree(); } | ~RCULock() { infos->readFree(); } | ||||
static void synchronize() { RCUInfos::infos.synchronize(); } | |||||
static bool isLocked() { return RCUInfos::infos.isLocked(); } | static bool isLocked() { return RCUInfos::infos.isLocked(); } | ||||
static void registerCleanup(const std::function<void()> &f) { | |||||
RCUInfos::infos.registerCleanup(f); | |||||
} | |||||
static void synchronize() { RCUInfos::infos.synchronize(); } | |||||
}; | }; | ||||
#endif // BITCOIN_RCU_H | #endif // BITCOIN_RCU_H |