[libcxx-commits] [libcxx] [libc++] Impelement P2545R4 Read-Copy Update (RCU) (PR #175451)

via libcxx-commits libcxx-commits at lists.llvm.org
Sun Jan 25 02:48:21 PST 2026


github-actions[bot] wrote:

<!--LLVM CODE FORMAT COMMENT: {clang-format}-->


:warning: C/C++ code formatter, clang-format found issues in your code. :warning:

<details>
<summary>
You can test this locally with the following command:
</summary>

``````````bash
git-clang-format --diff origin/main HEAD --extensions ,cpp,inc,h -- libcxx/include/__rcu/rcu_domain.h libcxx/include/__rcu/rcu_list.h libcxx/include/__rcu/rcu_obj_base.h libcxx/include/rcu libcxx/test/std/language.support/support.limits/support.limits.general/rcu.version.compile.pass.cpp libcxx/test/std/thread/saferecl/saferecl.rcu/general.pass.cpp libcxx/test/std/thread/saferecl/saferecl.rcu/read_write_lock_compare.pass.cpp libcxx/test/std/thread/saferecl/saferecl.rcu/retire.pass.cpp libcxx/include/__configuration/experimental.h libcxx/include/version libcxx/modules/std/rcu.inc libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp --diff_from_common_commit
``````````

:warning:
The reproduction instructions above might return results for more than one PR
in a stack if you are using a stacked PR workflow. You can limit the results by
changing `origin/main` to the base branch/commit you want to compare against.
:warning:

</details>

<details>
<summary>
View the diff from clang-format here.
</summary>

``````````diff
diff --git a/libcxx/include/__rcu/rcu_domain.h b/libcxx/include/__rcu/rcu_domain.h
index 3ac359728..75439fce4 100644
--- a/libcxx/include/__rcu/rcu_domain.h
+++ b/libcxx/include/__rcu/rcu_domain.h
@@ -148,7 +148,7 @@ class rcu_domain {
   void __synchronize() noexcept {
     __cxx_atomic_thread_fence(memory_order_seq_cst);
     std::unique_lock __lk(__grace_period_mutex_);
-    //std::printf("rcu_domain::__synchronize() going through phase 1\n");
+    // std::printf("rcu_domain::__synchronize() going through phase 1\n");
     auto __ready_callbacks = __update_phase_and_wait();
 
     // Invoke the ready callbacks outside of the grace period mutex
@@ -157,7 +157,7 @@ class rcu_domain {
     __lk.lock();
 
     __barrier();
-    //std::printf("rcu_domain::__synchronize() going through phase 2\n");
+    // std::printf("rcu_domain::__synchronize() going through phase 2\n");
     __ready_callbacks = __update_phase_and_wait();
 
     // Invoke the ready callbacks outside of the grace period mutex
@@ -175,7 +175,7 @@ class rcu_domain {
     auto __old_phase =
         __global_reader_phase_.fetch_xor(__reader_states::__grace_period_phase_mask, std::memory_order_relaxed);
     auto __new_phase = __old_phase ^ __reader_states::__grace_period_phase_mask;
-    //std::printf("rcu_domain::__update_phase_and_wait() new phase: 0x%04x\n", __new_phase);
+    // std::printf("rcu_domain::__update_phase_and_wait() new phase: 0x%04x\n", __new_phase);
 
     __barrier();
     // Wait for all threads to quiesce in the old phase
diff --git a/libcxx/include/__rcu/rcu_list.h b/libcxx/include/__rcu/rcu_list.h
index 2547d7223..933d2faec 100644
--- a/libcxx/include/__rcu/rcu_list.h
+++ b/libcxx/include/__rcu/rcu_list.h
@@ -71,7 +71,6 @@ public:
   }
 };
 
-
 #endif // _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_THREADS && _LIBCPP_HAS_EXPERIMENTAL_RCU
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__rcu/rcu_obj_base.h b/libcxx/include/__rcu/rcu_obj_base.h
index 3d1de3536..41a1c107a 100644
--- a/libcxx/include/__rcu/rcu_obj_base.h
+++ b/libcxx/include/__rcu/rcu_obj_base.h
@@ -28,8 +28,7 @@ class rcu_obj_base : private __rcu_node {
 public:
   void retire(D d = D(), rcu_domain& dom = rcu_default_domain()) noexcept {
     auto ptr = static_cast<T*>(this);
-    dom.__retire_callback(
-        [ptr, d = std::move(d)]() mutable { d(ptr); });
+    dom.__retire_callback([ptr, d = std::move(d)]() mutable { d(ptr); });
   }
 
 protected:
@@ -39,7 +38,6 @@ protected:
   rcu_obj_base& operator=(const rcu_obj_base&) = default;
   rcu_obj_base& operator=(rcu_obj_base&&)      = default;
   ~rcu_obj_base()                              = default;
-
 };
 
 #endif // _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_THREADS && _LIBCPP_HAS_EXPERIMENTAL_RCU
diff --git a/libcxx/modules/std/rcu.inc b/libcxx/modules/std/rcu.inc
index 0dbad7264..26b39a90c 100644
--- a/libcxx/modules/std/rcu.inc
+++ b/libcxx/modules/std/rcu.inc
@@ -16,5 +16,5 @@ export namespace std {
   using std::rcu_barrier;
   using std::rcu_retire;
   using std::rcu_synchronize;
-#  endif // _LIBCPP_STD_VER >= 23
+#endif // _LIBCPP_STD_VER >= 23
 } // namespace std
diff --git a/libcxx/test/std/thread/saferecl/saferecl.rcu/general.pass.cpp b/libcxx/test/std/thread/saferecl/saferecl.rcu/general.pass.cpp
index 88412976f..d85861d9b 100644
--- a/libcxx/test/std/thread/saferecl/saferecl.rcu/general.pass.cpp
+++ b/libcxx/test/std/thread/saferecl/saferecl.rcu/general.pass.cpp
@@ -39,7 +39,7 @@ int main(int, char**) {
       std::this_thread::sleep_for(std::chrono::seconds(1));
       log(start, "t1: leaving rcu read-side critical section " + std::to_string(i));
       dom.unlock();
-       log(start, "t1: printing all reader states");
+      log(start, "t1: printing all reader states");
       dom.printAllReaderStatesInHex();
     }
   });
@@ -54,7 +54,7 @@ int main(int, char**) {
       std::this_thread::sleep_for(std::chrono::seconds(1));
       log(start, "t2: leaving rcu read-side critical section " + std::to_string(i));
       dom.unlock();
-       log(start, "t2: printing all reader states");
+      log(start, "t2: printing all reader states");
       dom.printAllReaderStatesInHex();
     }
   });
@@ -69,7 +69,7 @@ int main(int, char**) {
       std::this_thread::sleep_for(std::chrono::seconds(1));
       log(start, "t3: leaving rcu read-side critical section " + std::to_string(i));
       dom.unlock();
-       log(start, "t3: printing all reader states");
+      log(start, "t3: printing all reader states");
       dom.printAllReaderStatesInHex();
     }
   });
@@ -83,7 +83,7 @@ int main(int, char**) {
       std::this_thread::sleep_for(std::chrono::seconds(1));
       log(start, "t4: leaving rcu read-side critical section " + std::to_string(i));
       dom.unlock();
-       log(start, "t4: printing all reader states");
+      log(start, "t4: printing all reader states");
       dom.printAllReaderStatesInHex();
     }
   });
@@ -99,15 +99,13 @@ int main(int, char**) {
   });  */
 
   std::this_thread::sleep_for(std::chrono::milliseconds(10));
-  for (int i = 0; i < loop_num+5; ++i) {
-
-  log(start, "t0: calling rcu_synchronize" + std::to_string(i));
-  std::rcu_synchronize();
-  log(start, "t0: rcu_synchronize returned" + std::to_string(i));
+  for (int i = 0; i < loop_num + 5; ++i) {
+    log(start, "t0: calling rcu_synchronize" + std::to_string(i));
+    std::rcu_synchronize();
+    log(start, "t0: rcu_synchronize returned" + std::to_string(i));
     std::this_thread::sleep_for(std::chrono::seconds(1));
   }
 
-
   t1.join();
   t2.join();
   t3.join();
diff --git a/libcxx/test/std/thread/saferecl/saferecl.rcu/read_write_lock_compare.pass.cpp b/libcxx/test/std/thread/saferecl/saferecl.rcu/read_write_lock_compare.pass.cpp
index 2fc790139..4ac3f1b8d 100644
--- a/libcxx/test/std/thread/saferecl/saferecl.rcu/read_write_lock_compare.pass.cpp
+++ b/libcxx/test/std/thread/saferecl/saferecl.rcu/read_write_lock_compare.pass.cpp
@@ -45,7 +45,6 @@ struct alignas(128) MyObject : public std::rcu_obj_base<MyObject> {
   }
 };
 
-
 void test_read_write_lock() {
   MyObject* globalObjRWLock = new MyObject();
   std::shared_mutex globalObjMutex;
@@ -92,7 +91,7 @@ void test_read_write_lock() {
 }
 
 void test_rcu() {
-  std::rcu_domain& dom = std::rcu_default_domain();
+  std::rcu_domain& dom                  = std::rcu_default_domain();
   std::atomic<MyObject*> global_obj_rcu = new MyObject();
 
   std::vector<std::jthread> readers;
diff --git a/libcxx/test/std/thread/saferecl/saferecl.rcu/retire.pass.cpp b/libcxx/test/std/thread/saferecl/saferecl.rcu/retire.pass.cpp
index dde6cdd32..4267e8656 100644
--- a/libcxx/test/std/thread/saferecl/saferecl.rcu/retire.pass.cpp
+++ b/libcxx/test/std/thread/saferecl/saferecl.rcu/retire.pass.cpp
@@ -35,9 +35,7 @@ struct MyObject : public std::rcu_obj_base<MyObject> {
   inline static int instance_count = 0;
   MyObject() : data_(std::to_string(instance_count++) + " instance very very very long string") {}
 
-  ~MyObject() {
-    std::println(std::cout, "MyObject {} destructor called", data_);
-  }
+  ~MyObject() { std::println(std::cout, "MyObject {} destructor called", data_); }
 };
 
 std::atomic<MyObject*> global_obj = nullptr;
@@ -52,8 +50,9 @@ int main(int, char**) {
       auto obj = global_obj.load();
       log(start, "t1: reading: " + (obj ? obj->data_ : "nullptr"));
       std::this_thread::sleep_for(std::chrono::seconds(1));
-      log(start, "t1: leaving rcu read-side critical section " + std::to_string(i) + " with object " +
-                         (obj ? obj->data_ : "nullptr"));
+      log(start,
+          "t1: leaving rcu read-side critical section " + std::to_string(i) + " with object " +
+              (obj ? obj->data_ : "nullptr"));
       dom.unlock();
       log(start, "t1: printing all reader states");
       dom.printAllReaderStatesInHex();
@@ -69,8 +68,9 @@ int main(int, char**) {
       auto obj = global_obj.load();
       log(start, "t2: reading: " + (obj ? obj->data_ : "nullptr"));
       std::this_thread::sleep_for(std::chrono::seconds(1));
-      log(start, "t2: leaving rcu read-side critical section " + std::to_string(i) + " with object " +
-                         (obj ? obj->data_ : "nullptr"));
+      log(start,
+          "t2: leaving rcu read-side critical section " + std::to_string(i) + " with object " +
+              (obj ? obj->data_ : "nullptr"));
       dom.unlock();
       log(start, "t2: printing all reader states");
       dom.printAllReaderStatesInHex();
@@ -86,8 +86,9 @@ int main(int, char**) {
       auto obj = global_obj.load();
       log(start, "t3: reading: " + (obj ? obj->data_ : "nullptr"));
       std::this_thread::sleep_for(std::chrono::seconds(1));
-      log(start, "t3: leaving rcu read-side critical section " + std::to_string(i) + " with object " +
-                         (obj ? obj->data_ : "nullptr"));
+      log(start,
+          "t3: leaving rcu read-side critical section " + std::to_string(i) + " with object " +
+              (obj ? obj->data_ : "nullptr"));
       dom.unlock();
       log(start, "t3: printing all reader states");
       dom.printAllReaderStatesInHex();
@@ -102,8 +103,9 @@ int main(int, char**) {
       auto obj = global_obj.load();
       log(start, "t4: reading: " + (obj ? obj->data_ : "nullptr"));
       std::this_thread::sleep_for(std::chrono::seconds(1));
-      log(start, "t4: leaving rcu read-side critical section " + std::to_string(i) + " with object " +
-                         (obj ? obj->data_ : "nullptr"));
+      log(start,
+          "t4: leaving rcu read-side critical section " + std::to_string(i) + " with object " +
+              (obj ? obj->data_ : "nullptr"));
       dom.unlock();
       log(start, "t4: printing all reader states");
       dom.printAllReaderStatesInHex();

``````````

</details>


https://github.com/llvm/llvm-project/pull/175451


More information about the libcxx-commits mailing list