sanitizer_lfstack.h 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. //===-- sanitizer_lfstack.h -=-----------------------------------*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // Lock-free stack.
  10. // Uses 32/17 bits as ABA-counter on 32/64-bit platforms.
  11. // The memory passed to Push() must not be ever munmap'ed.
  12. // The type T must contain T *next field.
  13. //
  14. //===----------------------------------------------------------------------===//
  15. #ifndef SANITIZER_LFSTACK_H
  16. #define SANITIZER_LFSTACK_H
  17. #include "sanitizer_internal_defs.h"
  18. #include "sanitizer_common.h"
  19. #include "sanitizer_atomic.h"
  20. namespace __sanitizer {
  21. template<typename T>
  22. struct LFStack {
  23. void Clear() {
  24. atomic_store(&head_, 0, memory_order_relaxed);
  25. }
  26. bool Empty() const {
  27. return (atomic_load(&head_, memory_order_relaxed) & kPtrMask) == 0;
  28. }
  29. void Push(T *p) {
  30. u64 cmp = atomic_load(&head_, memory_order_relaxed);
  31. for (;;) {
  32. u64 cnt = (cmp & kCounterMask) + kCounterInc;
  33. u64 xch = (u64)(uptr)p | cnt;
  34. p->next = (T*)(uptr)(cmp & kPtrMask);
  35. if (atomic_compare_exchange_weak(&head_, &cmp, xch,
  36. memory_order_release))
  37. break;
  38. }
  39. }
  40. T *Pop() {
  41. u64 cmp = atomic_load(&head_, memory_order_acquire);
  42. for (;;) {
  43. T *cur = (T*)(uptr)(cmp & kPtrMask);
  44. if (!cur)
  45. return nullptr;
  46. T *nxt = cur->next;
  47. u64 cnt = (cmp & kCounterMask);
  48. u64 xch = (u64)(uptr)nxt | cnt;
  49. if (atomic_compare_exchange_weak(&head_, &cmp, xch,
  50. memory_order_acquire))
  51. return cur;
  52. }
  53. }
  54. // private:
  55. static const int kCounterBits = FIRST_32_SECOND_64(32, 17);
  56. static const u64 kPtrMask = ((u64)-1) >> kCounterBits;
  57. static const u64 kCounterMask = ~kPtrMask;
  58. static const u64 kCounterInc = kPtrMask + 1;
  59. atomic_uint64_t head_;
  60. };
  61. } // namespace __sanitizer
  62. #endif // SANITIZER_LFSTACK_H