sanitizer_ring_buffer.h 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. //===-- sanitizer_ring_buffer.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. // Simple ring buffer.
  10. //
  11. //===----------------------------------------------------------------------===//
  12. #ifndef SANITIZER_RING_BUFFER_H
  13. #define SANITIZER_RING_BUFFER_H
  14. #include "sanitizer_common.h"
  15. namespace __sanitizer {
  16. // RingBuffer<T>: fixed-size ring buffer optimized for speed of push().
  17. // T should be a POD type and sizeof(T) should be divisible by sizeof(void*).
  18. // At creation, all elements are zero.
  19. template<class T>
  20. class RingBuffer {
  21. public:
  22. COMPILER_CHECK(sizeof(T) % sizeof(void *) == 0);
  23. static RingBuffer *New(uptr Size) {
  24. void *Ptr = MmapOrDie(SizeInBytes(Size), "RingBuffer");
  25. RingBuffer *RB = reinterpret_cast<RingBuffer*>(Ptr);
  26. uptr End = reinterpret_cast<uptr>(Ptr) + SizeInBytes(Size);
  27. RB->last_ = RB->next_ = reinterpret_cast<T*>(End - sizeof(T));
  28. return RB;
  29. }
  30. void Delete() {
  31. UnmapOrDie(this, SizeInBytes(size()));
  32. }
  33. uptr size() const {
  34. return last_ + 1 -
  35. reinterpret_cast<T *>(reinterpret_cast<uptr>(this) +
  36. 2 * sizeof(T *));
  37. }
  38. static uptr SizeInBytes(uptr Size) {
  39. return Size * sizeof(T) + 2 * sizeof(T*);
  40. }
  41. uptr SizeInBytes() { return SizeInBytes(size()); }
  42. void push(T t) {
  43. *next_ = t;
  44. next_--;
  45. static_assert((sizeof(T) % sizeof(T *)) == 0,
  46. "The condition below works only if sizeof(T) is divisible by "
  47. "sizeof(T*).");
  48. if (next_ <= reinterpret_cast<T*>(&next_))
  49. next_ = last_;
  50. }
  51. T operator[](uptr Idx) const {
  52. CHECK_LT(Idx, size());
  53. sptr IdxNext = Idx + 1;
  54. if (IdxNext > last_ - next_)
  55. IdxNext -= size();
  56. return next_[IdxNext];
  57. }
  58. private:
  59. RingBuffer() {}
  60. ~RingBuffer() {}
  61. RingBuffer(const RingBuffer&) = delete;
  62. // Data layout:
  63. // LNDDDDDDDD
  64. // D: data elements.
  65. // L: last_, always points to the last data element.
  66. // N: next_, initially equals to last_, is decremented on every push,
  67. // wraps around if it's less or equal than its own address.
  68. T *last_;
  69. T *next_;
  70. T data_[1]; // flexible array.
  71. };
  72. // A ring buffer with externally provided storage that encodes its state in 8
  73. // bytes. Has significant constraints on size and alignment of storage.
  74. // See a comment in hwasan/hwasan_thread_list.h for the motivation behind this.
  75. #if SANITIZER_WORDSIZE == 64
  76. template <class T>
  77. class CompactRingBuffer {
  78. // Top byte of long_ stores the buffer size in pages.
  79. // Lower bytes store the address of the next buffer element.
  80. static constexpr int kPageSizeBits = 12;
  81. static constexpr int kSizeShift = 56;
  82. static constexpr int kSizeBits = 64 - kSizeShift;
  83. static constexpr uptr kNextMask = (1ULL << kSizeShift) - 1;
  84. uptr GetStorageSize() const { return (long_ >> kSizeShift) << kPageSizeBits; }
  85. static uptr SignExtend(uptr x) { return ((sptr)x) << kSizeBits >> kSizeBits; }
  86. void Init(void *storage, uptr size) {
  87. CHECK_EQ(sizeof(CompactRingBuffer<T>), sizeof(void *));
  88. CHECK(IsPowerOfTwo(size));
  89. CHECK_GE(size, 1 << kPageSizeBits);
  90. CHECK_LE(size, 128 << kPageSizeBits);
  91. CHECK_EQ(size % 4096, 0);
  92. CHECK_EQ(size % sizeof(T), 0);
  93. uptr st = (uptr)storage;
  94. CHECK_EQ(st % (size * 2), 0);
  95. CHECK_EQ(st, SignExtend(st & kNextMask));
  96. long_ = (st & kNextMask) | ((size >> kPageSizeBits) << kSizeShift);
  97. }
  98. void SetNext(const T *next) {
  99. long_ = (long_ & ~kNextMask) | ((uptr)next & kNextMask);
  100. }
  101. public:
  102. CompactRingBuffer(void *storage, uptr size) {
  103. Init(storage, size);
  104. }
  105. // A copy constructor of sorts.
  106. CompactRingBuffer(const CompactRingBuffer &other, void *storage) {
  107. uptr size = other.GetStorageSize();
  108. internal_memcpy(storage, other.StartOfStorage(), size);
  109. Init(storage, size);
  110. uptr Idx = other.Next() - (const T *)other.StartOfStorage();
  111. SetNext((const T *)storage + Idx);
  112. }
  113. T *Next() const { return (T *)(SignExtend(long_ & kNextMask)); }
  114. void *StartOfStorage() const {
  115. return (void *)((uptr)Next() & ~(GetStorageSize() - 1));
  116. }
  117. void *EndOfStorage() const {
  118. return (void *)((uptr)StartOfStorage() + GetStorageSize());
  119. }
  120. uptr size() const { return GetStorageSize() / sizeof(T); }
  121. void push(T t) {
  122. T *next = Next();
  123. *next = t;
  124. next++;
  125. next = (T *)((uptr)next & ~GetStorageSize());
  126. SetNext(next);
  127. }
  128. const T &operator[](uptr Idx) const {
  129. CHECK_LT(Idx, size());
  130. const T *Begin = (const T *)StartOfStorage();
  131. sptr StorageIdx = Next() - Begin;
  132. StorageIdx -= (sptr)(Idx + 1);
  133. if (StorageIdx < 0)
  134. StorageIdx += size();
  135. return Begin[StorageIdx];
  136. }
  137. public:
  138. ~CompactRingBuffer() {}
  139. CompactRingBuffer(const CompactRingBuffer &) = delete;
  140. uptr long_;
  141. };
  142. #endif
  143. } // namespace __sanitizer
  144. #endif // SANITIZER_RING_BUFFER_H