[libc-commits] [libc] [libc][rework] arc4random with vDSO support (PR #151361)

Schrodinger ZHU Yifan via libc-commits libc-commits at lists.llvm.org
Wed Jul 30 09:52:51 PDT 2025


https://github.com/SchrodingerZhu updated https://github.com/llvm/llvm-project/pull/151361

>From ec5d9715dfc448ac2329dff4a48b344d6954c185 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Wed, 30 Jul 2025 12:47:24 -0400
Subject: [PATCH 1/2] wip

---
 libc/src/__support/aba_ptr.h    | 70 ++++++++++++++++++++++++++++++
 libc/src/__support/mpmc_stack.h | 75 +++++++++++++++++++++++++++++++++
 2 files changed, 145 insertions(+)
 create mode 100644 libc/src/__support/aba_ptr.h
 create mode 100644 libc/src/__support/mpmc_stack.h

diff --git a/libc/src/__support/aba_ptr.h b/libc/src/__support/aba_ptr.h
new file mode 100644
index 0000000000000..c702aae017502
--- /dev/null
+++ b/libc/src/__support/aba_ptr.h
@@ -0,0 +1,70 @@
+//===-- Transactional Ptr for ABA prevention --------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_TAGGED_POINTER_H
+#define LLVM_LIBC_SRC___SUPPORT_TAGGED_POINTER_H
+
+#include "src/__support/common.h"
+#include "src/__support/threads/sleep.h"
+
+#ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16
+#define LIBC_ABA_PTR_IS_ATOMIC true
+#else
+#define LIBC_ABA_PTR_IS_ATOMIC false
+#endif
+
+namespace LIBC_NAMESPACE_DECL {
+
+template <class T, bool IsAtomic> struct AbaPtrImpl {
+  union Impl {
+    struct alignas(2 * alignof(void *)) Atomic {
+      T *ptr;
+      __SIZE_TYPE__ tag;
+    } atomic;
+    struct Mutex {
+      T *ptr;
+      bool locked;
+    } mutex;
+  } impl;
+
+  LIBC_INLINE constexpr AbaPtrImpl(T *ptr)
+      : impl(IsAtomic ? Impl{.atomic{ptr, 0}} : Impl{.mutex{ptr, false}}) {}
+
+  /// User must guarantee that operation is redoable.
+  template <class Op> LIBC_INLINE void transaction(Op &&op) {
+    if constexpr (IsAtomic) {
+      for (;;) {
+        typename Impl::Atomic snapshot, next;
+        __atomic_load(&impl.atomic, &snapshot, __ATOMIC_RELAXED);
+        next.ptr = op(snapshot.ptr);
+        // Wrapping add for unsigned integers.
+        next.tag = snapshot.tag + 1;
+        if (__atomic_compare_exchange(&impl.atomic, &snapshot, &next, true,
+                                      __ATOMIC_ACQ_REL, __ATOMIC_RELAXED)) {
+          return;
+        }
+      }
+    } else {
+      // Acquire the lock.
+      while (__atomic_exchange_n(&impl.mutex.locked, true, __ATOMIC_ACQUIRE)) {
+        while (__atomic_load_n(&impl.mutex.locked, __ATOMIC_RELAXED)) {
+          LIBC_NAMESPACE::sleep_briefly();
+        }
+      }
+      impl.mutex.ptr = op(impl.mutex.ptr);
+      // Release the lock.
+      __atomic_store_n(&impl.mutex.locked, false, __ATOMIC_RELEASE);
+    }
+  }
+};
+
+template <class T> using AbaPtr = AbaPtrImpl<T, LIBC_ABA_PTR_IS_ATOMIC>;
+} // namespace LIBC_NAMESPACE_DECL
+
+#undef LIBC_ABA_PTR_IS_ATOMIC
+#endif
diff --git a/libc/src/__support/mpmc_stack.h b/libc/src/__support/mpmc_stack.h
new file mode 100644
index 0000000000000..4892c3926b4b0
--- /dev/null
+++ b/libc/src/__support/mpmc_stack.h
@@ -0,0 +1,75 @@
+//===-- Simple Lock-free MPMC Stack -----------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_MPMC_STACK_H
+#define LLVM_LIBC_SRC___SUPPORT_MPMC_STACK_H
+
+#include "src/__support/CPP/atomic.h"
+#include "src/__support/CPP/new.h"
+#include "src/__support/CPP/optional.h"
+#include "src/__support/aba_ptr.h"
+
+namespace LIBC_NAMESPACE_DECL {
+template <class T> class MPMCStack {
+  struct Node {
+    cpp::Atomic<size_t> visitor;
+    AbaPtr<Node> next;
+    T value;
+
+    LIBC_INLINE Node(T val) : visitor(0), next(nullptr), value(val) {}
+  };
+  AbaPtr<Node> head;
+
+public:
+  static_assert(cpp::is_copy_constructible<T>::value,
+                "T must be copy constructible");
+  LIBC_INLINE MPMCStack() : head(nullptr) {}
+  LIBC_INLINE bool push(T value) {
+    AllocChecker ac;
+    Node *new_node = new Node(value, ac);
+    if (!ac) {
+      return false;
+    }
+    head.transaction([new_node](Node *old_head) {
+      new_node->next = old_head;
+      return new_node;
+    });
+    return true;
+  }
+  LIBC_INLINE cpp::optional<T> pop() {
+    cpp::optional<T> res;
+    Node *node;
+    head.transaction([&](Node *current_head) {
+      if (!current_head) {
+        res = cpp::nullopt;
+        return nullptr;
+      }
+      node = current_head;
+      node->visitor.fetch_add(1);
+      res = node->value;
+      auto next = node->next;
+      node->visitor.fetch_sub(1);
+      return next;
+    });
+    // On a successful transaction, a node is popped by us. So we must delete
+    // it. When we are at here, no one else can acquire
+    // new reference to the node, but we still need to wait until other threads
+    // inside the transaction who may potentially be holding a reference to the
+    // node.
+    if (res) {
+      // Spin until the node is no longer in use.
+      while (node->visitor.load() != 0)
+        LIBC_NAMESPACE::sleep_briefly();
+      delete node;
+    }
+    return res;
+  }
+};
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif

>From 0eac3c6dde7115a8c1d760f2892b963b3eebd3ef Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Wed, 30 Jul 2025 12:52:35 -0400
Subject: [PATCH 2/2] remove some extra braces

---
 libc/src/__support/aba_ptr.h    | 10 ++++------
 libc/src/__support/mpmc_stack.h |  3 +--
 2 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/libc/src/__support/aba_ptr.h b/libc/src/__support/aba_ptr.h
index c702aae017502..f7ed601dfbe70 100644
--- a/libc/src/__support/aba_ptr.h
+++ b/libc/src/__support/aba_ptr.h
@@ -45,17 +45,15 @@ template <class T, bool IsAtomic> struct AbaPtrImpl {
         // Wrapping add for unsigned integers.
         next.tag = snapshot.tag + 1;
         if (__atomic_compare_exchange(&impl.atomic, &snapshot, &next, true,
-                                      __ATOMIC_ACQ_REL, __ATOMIC_RELAXED)) {
+                                      __ATOMIC_ACQ_REL, __ATOMIC_RELAXED))
           return;
-        }
       }
     } else {
       // Acquire the lock.
-      while (__atomic_exchange_n(&impl.mutex.locked, true, __ATOMIC_ACQUIRE)) {
-        while (__atomic_load_n(&impl.mutex.locked, __ATOMIC_RELAXED)) {
+      while (__atomic_exchange_n(&impl.mutex.locked, true, __ATOMIC_ACQUIRE))
+        while (__atomic_load_n(&impl.mutex.locked, __ATOMIC_RELAXED))
           LIBC_NAMESPACE::sleep_briefly();
-        }
-      }
+
       impl.mutex.ptr = op(impl.mutex.ptr);
       // Release the lock.
       __atomic_store_n(&impl.mutex.locked, false, __ATOMIC_RELEASE);
diff --git a/libc/src/__support/mpmc_stack.h b/libc/src/__support/mpmc_stack.h
index 4892c3926b4b0..819433f24380c 100644
--- a/libc/src/__support/mpmc_stack.h
+++ b/libc/src/__support/mpmc_stack.h
@@ -32,9 +32,8 @@ template <class T> class MPMCStack {
   LIBC_INLINE bool push(T value) {
     AllocChecker ac;
     Node *new_node = new Node(value, ac);
-    if (!ac) {
+    if (!ac)
       return false;
-    }
     head.transaction([new_node](Node *old_head) {
       new_node->next = old_head;
       return new_node;



More information about the libc-commits mailing list