xref: /aosp_15_r20/external/compiler-rt/lib/sanitizer_common/sanitizer_lfstack.h (revision 7c3d14c8b49c529e04be81a3ce6f5cc23712e4c6)
1*7c3d14c8STreehugger Robot //===-- sanitizer_lfstack.h -=-----------------------------------*- C++ -*-===//
2*7c3d14c8STreehugger Robot //
3*7c3d14c8STreehugger Robot //                     The LLVM Compiler Infrastructure
4*7c3d14c8STreehugger Robot //
5*7c3d14c8STreehugger Robot // This file is distributed under the University of Illinois Open Source
6*7c3d14c8STreehugger Robot // License. See LICENSE.TXT for details.
7*7c3d14c8STreehugger Robot //
8*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
9*7c3d14c8STreehugger Robot //
10*7c3d14c8STreehugger Robot // Lock-free stack.
11*7c3d14c8STreehugger Robot // Uses 32/17 bits as ABA-counter on 32/64-bit platforms.
12*7c3d14c8STreehugger Robot // The memory passed to Push() must not be ever munmap'ed.
13*7c3d14c8STreehugger Robot // The type T must contain T *next field.
14*7c3d14c8STreehugger Robot //
15*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
16*7c3d14c8STreehugger Robot 
17*7c3d14c8STreehugger Robot #ifndef SANITIZER_LFSTACK_H
18*7c3d14c8STreehugger Robot #define SANITIZER_LFSTACK_H
19*7c3d14c8STreehugger Robot 
20*7c3d14c8STreehugger Robot #include "sanitizer_internal_defs.h"
21*7c3d14c8STreehugger Robot #include "sanitizer_common.h"
22*7c3d14c8STreehugger Robot #include "sanitizer_atomic.h"
23*7c3d14c8STreehugger Robot 
24*7c3d14c8STreehugger Robot namespace __sanitizer {
25*7c3d14c8STreehugger Robot 
26*7c3d14c8STreehugger Robot template<typename T>
27*7c3d14c8STreehugger Robot struct LFStack {
ClearLFStack28*7c3d14c8STreehugger Robot   void Clear() {
29*7c3d14c8STreehugger Robot     atomic_store(&head_, 0, memory_order_relaxed);
30*7c3d14c8STreehugger Robot   }
31*7c3d14c8STreehugger Robot 
EmptyLFStack32*7c3d14c8STreehugger Robot   bool Empty() const {
33*7c3d14c8STreehugger Robot     return (atomic_load(&head_, memory_order_relaxed) & kPtrMask) == 0;
34*7c3d14c8STreehugger Robot   }
35*7c3d14c8STreehugger Robot 
PushLFStack36*7c3d14c8STreehugger Robot   void Push(T *p) {
37*7c3d14c8STreehugger Robot     u64 cmp = atomic_load(&head_, memory_order_relaxed);
38*7c3d14c8STreehugger Robot     for (;;) {
39*7c3d14c8STreehugger Robot       u64 cnt = (cmp & kCounterMask) + kCounterInc;
40*7c3d14c8STreehugger Robot       u64 xch = (u64)(uptr)p | cnt;
41*7c3d14c8STreehugger Robot       p->next = (T*)(uptr)(cmp & kPtrMask);
42*7c3d14c8STreehugger Robot       if (atomic_compare_exchange_weak(&head_, &cmp, xch,
43*7c3d14c8STreehugger Robot                                        memory_order_release))
44*7c3d14c8STreehugger Robot         break;
45*7c3d14c8STreehugger Robot     }
46*7c3d14c8STreehugger Robot   }
47*7c3d14c8STreehugger Robot 
PopLFStack48*7c3d14c8STreehugger Robot   T *Pop() {
49*7c3d14c8STreehugger Robot     u64 cmp = atomic_load(&head_, memory_order_acquire);
50*7c3d14c8STreehugger Robot     for (;;) {
51*7c3d14c8STreehugger Robot       T *cur = (T*)(uptr)(cmp & kPtrMask);
52*7c3d14c8STreehugger Robot       if (!cur)
53*7c3d14c8STreehugger Robot         return nullptr;
54*7c3d14c8STreehugger Robot       T *nxt = cur->next;
55*7c3d14c8STreehugger Robot       u64 cnt = (cmp & kCounterMask);
56*7c3d14c8STreehugger Robot       u64 xch = (u64)(uptr)nxt | cnt;
57*7c3d14c8STreehugger Robot       if (atomic_compare_exchange_weak(&head_, &cmp, xch,
58*7c3d14c8STreehugger Robot                                        memory_order_acquire))
59*7c3d14c8STreehugger Robot         return cur;
60*7c3d14c8STreehugger Robot     }
61*7c3d14c8STreehugger Robot   }
62*7c3d14c8STreehugger Robot 
63*7c3d14c8STreehugger Robot   // private:
64*7c3d14c8STreehugger Robot   static const int kCounterBits = FIRST_32_SECOND_64(32, 17);
65*7c3d14c8STreehugger Robot   static const u64 kPtrMask = ((u64)-1) >> kCounterBits;
66*7c3d14c8STreehugger Robot   static const u64 kCounterMask = ~kPtrMask;
67*7c3d14c8STreehugger Robot   static const u64 kCounterInc = kPtrMask + 1;
68*7c3d14c8STreehugger Robot 
69*7c3d14c8STreehugger Robot   atomic_uint64_t head_;
70*7c3d14c8STreehugger Robot };
71*7c3d14c8STreehugger Robot } // namespace __sanitizer
72*7c3d14c8STreehugger Robot 
73*7c3d14c8STreehugger Robot #endif // SANITIZER_LFSTACK_H
74