[libcxx-commits] [libcxx] [libc++] Implement P2545R4 Read-Copy Update (RCU) (PR #175451)
via libcxx-commits
libcxx-commits at lists.llvm.org
Sun Sep 13 13:27:10 PDT 2026
================
@@ -0,0 +1,237 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <atomic>
+#include <cstdint>
+#include <memory>
+#include <mutex>
+#include <rcu>
+
+#include "include/rcu/rcu_list.h"
+#include "include/rcu/thread_local_container.h"
+
+// todo: remove debug print
+#include <cstdio>
+//
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+
+namespace {
+
+// Adopted the 2-phase implementation in the section
+// "3) General-Purpose RCU" of the paper
+// http://www.rdrop.com/users/paulmck/RCU/urcu-supp-accepted.2011.08.30a.pdf
+
+struct reader_states {
+ // bit 15 is the grace period phase 0 or 1
+ // bits 0-14 is the reader nest level
+ //
+ // a thread can have nested reader locks, such as
+ // domain.lock(); // nest level = 1
+ // domain.lock(); // nest level = 2
+ // ...
+ // domain.unlock(); // nest level = 1
+ // domain.unlock(); // nest level = 0
+
+ static constexpr uint16_t grace_period_phase_mask = 0b1000'0000'0000'0000;
+ static constexpr uint16_t reader_nest_level_mask = 0b0111'1111'1111'1111;
+
+ using state_type = uint16_t;
+
+ std::atomic<state_type> state_{};
+
+ bool is_quiescent_state() const noexcept {
+ return get_reader_nest_level(state_.load(std::memory_order_relaxed)) == 0;
+ }
+
+ bool is_grace_period_ongoing_at_phase(state_type global_phase) const noexcept {
+ auto state = state_.load(std::memory_order_relaxed);
+ return !is_quiescent_state(state) && get_grace_period_phase(state) == global_phase;
+ }
+
+ void set_state(state_type grace_period_phase, state_type reader_nest_level) {
+ auto state = (grace_period_phase & grace_period_phase_mask) | (reader_nest_level & reader_nest_level_mask);
+ state_.store(state, memory_order_relaxed);
+ }
+
+ void increment_nest_level() noexcept { state_.fetch_add(1, memory_order_relaxed); }
+
+ // return previous nested level
+ uint16_t decrement_nest_level() noexcept {
+ auto old_state = state_.fetch_sub(1, memory_order_relaxed);
+ return get_reader_nest_level(old_state);
+ }
+
+ state_type debug_get_state() const noexcept { return state_.load(); }
+
+private:
+ static uint16_t get_grace_period_phase(state_type state) noexcept { return state & grace_period_phase_mask; }
+ static bool is_quiescent_state(state_type state) noexcept { return get_reader_nest_level(state) == 0; }
+
+ static uint16_t get_reader_nest_level(state_type state) noexcept { return state & reader_nest_level_mask; }
+};
+
+class rcu_domain_impl {
+ using per_thread_states = thread_local_container<reader_states>;
----------------
huixie90 wrote:
A design question:
If a user calls `lock` on a reader thread, and forgot to `unlock` before the thread dies, with current implementation, of collector threads are waiting for this `lock`, the collector thread will deadlock. A simple QoI improvement is that we can unlock the reader state and notify all the waiters at thread destruction. but on the other hand, we could document that you should always use `lock_guard` or `unique_lock` instead of plain `lock`/`unlock`
https://github.com/llvm/llvm-project/pull/175451
More information about the libcxx-commits
mailing list