[libc-commits] [libc] [libc][arc4random][patch 2/4] add ABA protected MPMCStack (PR #151361)
via libc-commits
libc-commits at lists.llvm.org
Wed Aug 13 23:06:20 PDT 2025
================
@@ -0,0 +1,89 @@
+//===-- 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 "hdr/types/size_t.h"
+#include "src/__support/CPP/atomic.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_t 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 (;;) {
+ cpp::AtomicRef<typename Impl::Atomic> ref(impl.atomic);
+ typename Impl::Atomic snapshot, next;
+ snapshot = ref.load(cpp::MemoryOrder::RELAXED);
+ next.ptr = op(snapshot.ptr);
+ // Wrapping add for unsigned integers.
+ next.tag = snapshot.tag + 1;
+ // Redo transaction can be costly, so we use strong version.
+ if (ref.compare_exchange_strong(snapshot, next,
+ cpp::MemoryOrder::ACQ_REL,
+ cpp::MemoryOrder::RELAXED))
+ return;
+ }
+ } else {
+ // Acquire the lock.
+ cpp::AtomicRef<bool> ref(impl.mutex.locked);
+ while (ref.exchange(true, cpp::MemoryOrder::ACQUIRE))
+ while (ref.load(cpp::MemoryOrder::RELAXED))
+ LIBC_NAMESPACE::sleep_briefly();
+
+ impl.mutex.ptr = op(impl.mutex.ptr);
+ // Release the lock.
+ ref.store(false, cpp::MemoryOrder::RELEASE);
+ }
+ }
+
+ LIBC_INLINE T *get() const {
+ if constexpr (IsAtomic) {
+ // Weak micro-architectures typically regards simultaneous partial word
+ // loading and full word loading as a race condition. While there are
+ // implementations that uses racy read anyway, we still load the whole
+ // word to avoid any complications.
+ typename Impl::Atomic snapshot;
+ cpp::AtomicRef<typename Impl::Atomic> ref(impl.atomic);
+ snapshot = ref.load(cpp::MemoryOrder::RELAXED);
+ return snapshot.ptr;
+ } else {
+ return impl.mutex.ptr;
+ }
+ }
+};
+
+template <class T> using AbaPtr = AbaPtrImpl<T, LIBC_ABA_PTR_IS_ATOMIC>;
+} // namespace LIBC_NAMESPACE_DECL
+
+#undef LIBC_ABA_PTR_IS_ATOMIC
----------------
lntue wrote:
why do we need to `undef` this?
https://github.com/llvm/llvm-project/pull/151361
More information about the libc-commits
mailing list