Commit fdac3c4e authored by Victor Zverovich's avatar Victor Zverovich Committed by Facebook Github Bot

Minor improvements to Rcu.h

Summary:
Minor improvements to `Rcu.h`:
* Spell out the first use of RCU for the sake of people who are not familiar
  with the abbreviation.
* Correct the default template argument type in the comment: it's `RcuTag`, not
  `void`.
* Don't expose `rcu_token` constructor to the users because it's only supposed
  to be obtained via `lock_shared`.
* Make other single-argument constructors explicit to prevent undesirable
  conversions.
* Parameterize `rcu_token` on the tag type to prevent cross-domain use.

Reviewed By: yfeldblum

Differential Revision: D13510133

fbshipit-source-id: d5d214cfa3b30d0857c14ac293da6e4310db1100
parent c3dd651c
...@@ -63,7 +63,7 @@ class AtomicReadMostlyMainPtr { ...@@ -63,7 +63,7 @@ class AtomicReadMostlyMainPtr {
ReadMostlySharedPtr<T> load( ReadMostlySharedPtr<T> load(
std::memory_order order = std::memory_order_seq_cst) const { std::memory_order order = std::memory_order_seq_cst) const {
rcu_token token = detail::atomicReadMostlyDomain->lock_shared(); auto token = detail::atomicReadMostlyDomain->lock_shared();
// Synchronization point with the store in storeLocked(). // Synchronization point with the store in storeLocked().
auto index = curMainPtrIndex_.load(order); auto index = curMainPtrIndex_.load(order);
auto result = mainPtrs_[index].getShared(); auto result = mainPtrs_[index].getShared();
......
...@@ -50,16 +50,16 @@ rcu_domain<Tag>::~rcu_domain() { ...@@ -50,16 +50,16 @@ rcu_domain<Tag>::~rcu_domain() {
} }
template <typename Tag> template <typename Tag>
rcu_token rcu_domain<Tag>::lock_shared() { rcu_token<Tag> rcu_domain<Tag>::lock_shared() {
auto idx = version_.load(std::memory_order_acquire); auto idx = version_.load(std::memory_order_acquire);
idx &= 1; idx &= 1;
counters_.increment(idx); counters_.increment(idx);
return idx; return rcu_token<Tag>(idx);
} }
template <typename Tag> template <typename Tag>
void rcu_domain<Tag>::unlock_shared(rcu_token&& token) { void rcu_domain<Tag>::unlock_shared(rcu_token<Tag>&& token) {
DCHECK(0 == token.epoch_ || 1 == token.epoch_); DCHECK(0 == token.epoch_ || 1 == token.epoch_);
counters_.decrement(token.epoch_); counters_.decrement(token.epoch_);
} }
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include <folly/synchronization/detail/ThreadCachedInts.h> #include <folly/synchronization/detail/ThreadCachedInts.h>
#include <folly/synchronization/detail/ThreadCachedLists.h> #include <folly/synchronization/detail/ThreadCachedLists.h>
// Implementation of proposed RCU C++ API // Implementation of proposed Read-Copy-Update (RCU) C++ API
// http://open-std.org/JTC1/SC22/WG21/docs/papers/2017/p0566r3.pdf // http://open-std.org/JTC1/SC22/WG21/docs/papers/2017/p0566r3.pdf
// Overview // Overview
...@@ -175,7 +175,7 @@ ...@@ -175,7 +175,7 @@
// callers should only ever use the default, global domain. // callers should only ever use the default, global domain.
// //
// Creation of a domain takes a template tag argument, which // Creation of a domain takes a template tag argument, which
// defaults to void. To access different domains, you have to pass a // defaults to RcuTag. To access different domains, you have to pass a
// different tag. The global domain is preferred for almost all // different tag. The global domain is preferred for almost all
// purposes, unless a different executor is required. // purposes, unless a different executor is required.
// //
...@@ -288,9 +288,9 @@ class rcu_domain; ...@@ -288,9 +288,9 @@ class rcu_domain;
// Opaque token used to match up lock_shared() and unlock_shared() // Opaque token used to match up lock_shared() and unlock_shared()
// pairs. // pairs.
template <typename Tag>
class rcu_token { class rcu_token {
public: public:
rcu_token(uint64_t epoch) : epoch_(epoch) {}
rcu_token() {} rcu_token() {}
~rcu_token() = default; ~rcu_token() = default;
...@@ -300,8 +300,9 @@ class rcu_token { ...@@ -300,8 +300,9 @@ class rcu_token {
rcu_token& operator=(rcu_token&& other) = default; rcu_token& operator=(rcu_token&& other) = default;
private: private:
template <typename Tag> explicit rcu_token(uint64_t epoch) : epoch_(epoch) {}
friend class rcu_domain;
friend class rcu_domain<Tag>;
uint64_t epoch_; uint64_t epoch_;
}; };
...@@ -317,7 +318,7 @@ class rcu_domain { ...@@ -317,7 +318,7 @@ class rcu_domain {
* If an executor is passed, it is used to run calls and delete * If an executor is passed, it is used to run calls and delete
* retired objects. * retired objects.
*/ */
rcu_domain(Executor* executor = nullptr) noexcept; explicit rcu_domain(Executor* executor = nullptr) noexcept;
rcu_domain(const rcu_domain&) = delete; rcu_domain(const rcu_domain&) = delete;
rcu_domain(rcu_domain&&) = delete; rcu_domain(rcu_domain&&) = delete;
...@@ -330,8 +331,8 @@ class rcu_domain { ...@@ -330,8 +331,8 @@ class rcu_domain {
// all preceding lock_shared() sections are finished. // all preceding lock_shared() sections are finished.
// Note: can potentially allocate on thread first use. // Note: can potentially allocate on thread first use.
FOLLY_ALWAYS_INLINE rcu_token lock_shared(); FOLLY_ALWAYS_INLINE rcu_token<Tag> lock_shared();
FOLLY_ALWAYS_INLINE void unlock_shared(rcu_token&&); FOLLY_ALWAYS_INLINE void unlock_shared(rcu_token<Tag>&&);
// Call a function after concurrent critical sections have finished. // Call a function after concurrent critical sections have finished.
// Does not block unless the queue is full, then may block to wait // Does not block unless the queue is full, then may block to wait
...@@ -390,10 +391,10 @@ inline rcu_domain<RcuTag>* rcu_default_domain() { ...@@ -390,10 +391,10 @@ inline rcu_domain<RcuTag>* rcu_default_domain() {
template <typename Tag = RcuTag> template <typename Tag = RcuTag>
class rcu_reader_domain { class rcu_reader_domain {
public: public:
FOLLY_ALWAYS_INLINE rcu_reader_domain( explicit FOLLY_ALWAYS_INLINE rcu_reader_domain(
rcu_domain<Tag>* domain = rcu_default_domain()) noexcept rcu_domain<Tag>* domain = rcu_default_domain()) noexcept
: epoch_(domain->lock_shared()), domain_(domain) {} : epoch_(domain->lock_shared()), domain_(domain) {}
rcu_reader_domain( explicit rcu_reader_domain(
std::defer_lock_t, std::defer_lock_t,
rcu_domain<Tag>* domain = rcu_default_domain()) noexcept rcu_domain<Tag>* domain = rcu_default_domain()) noexcept
: domain_(domain) {} : domain_(domain) {}
...@@ -433,7 +434,7 @@ class rcu_reader_domain { ...@@ -433,7 +434,7 @@ class rcu_reader_domain {
} }
private: private:
Optional<rcu_token> epoch_; Optional<rcu_token<Tag>> epoch_;
rcu_domain<Tag>* domain_; rcu_domain<Tag>* domain_;
}; };
......
...@@ -212,7 +212,7 @@ TEST(RcuTest, MoveReaderBetweenThreads) { ...@@ -212,7 +212,7 @@ TEST(RcuTest, MoveReaderBetweenThreads) {
} }
TEST(RcuTest, ForkTest) { TEST(RcuTest, ForkTest) {
rcu_token epoch; rcu_token<RcuTag> epoch;
std::thread t([&]() { epoch = rcu_default_domain()->lock_shared(); }); std::thread t([&]() { epoch = rcu_default_domain()->lock_shared(); });
t.join(); t.join();
auto pid = fork(); auto pid = fork();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment