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