123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- //===-- sanitizer_ring_buffer.h ---------------------------------*- 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
- //
- //===----------------------------------------------------------------------===//
- //
- // Simple ring buffer.
- //
- //===----------------------------------------------------------------------===//
- #ifndef SANITIZER_RING_BUFFER_H
- #define SANITIZER_RING_BUFFER_H
- #include "sanitizer_common.h"
- namespace __sanitizer {
- // RingBuffer<T>: fixed-size ring buffer optimized for speed of push().
- // T should be a POD type and sizeof(T) should be divisible by sizeof(void*).
- // At creation, all elements are zero.
- template<class T>
- class RingBuffer {
- public:
- COMPILER_CHECK(sizeof(T) % sizeof(void *) == 0);
- static RingBuffer *New(uptr Size) {
- void *Ptr = MmapOrDie(SizeInBytes(Size), "RingBuffer");
- RingBuffer *RB = reinterpret_cast<RingBuffer*>(Ptr);
- uptr End = reinterpret_cast<uptr>(Ptr) + SizeInBytes(Size);
- RB->last_ = RB->next_ = reinterpret_cast<T*>(End - sizeof(T));
- return RB;
- }
- void Delete() {
- UnmapOrDie(this, SizeInBytes(size()));
- }
- uptr size() const {
- return last_ + 1 -
- reinterpret_cast<T *>(reinterpret_cast<uptr>(this) +
- 2 * sizeof(T *));
- }
- static uptr SizeInBytes(uptr Size) {
- return Size * sizeof(T) + 2 * sizeof(T*);
- }
- uptr SizeInBytes() { return SizeInBytes(size()); }
- void push(T t) {
- *next_ = t;
- next_--;
- // The condition below works only if sizeof(T) is divisible by sizeof(T*).
- if (next_ <= reinterpret_cast<T*>(&next_))
- next_ = last_;
- }
- T operator[](uptr Idx) const {
- CHECK_LT(Idx, size());
- sptr IdxNext = Idx + 1;
- if (IdxNext > last_ - next_)
- IdxNext -= size();
- return next_[IdxNext];
- }
- private:
- RingBuffer() {}
- ~RingBuffer() {}
- RingBuffer(const RingBuffer&) = delete;
- // Data layout:
- // LNDDDDDDDD
- // D: data elements.
- // L: last_, always points to the last data element.
- // N: next_, initially equals to last_, is decremented on every push,
- // wraps around if it's less or equal than its own address.
- T *last_;
- T *next_;
- T data_[1]; // flexible array.
- };
- // A ring buffer with externally provided storage that encodes its state in 8
- // bytes. Has significant constraints on size and alignment of storage.
- // See a comment in hwasan/hwasan_thread_list.h for the motivation behind this.
- #if SANITIZER_WORDSIZE == 64
- template <class T>
- class CompactRingBuffer {
- // Top byte of long_ stores the buffer size in pages.
- // Lower bytes store the address of the next buffer element.
- static constexpr int kPageSizeBits = 12;
- static constexpr int kSizeShift = 56;
- static constexpr int kSizeBits = 64 - kSizeShift;
- static constexpr uptr kNextMask = (1ULL << kSizeShift) - 1;
- uptr GetStorageSize() const { return (long_ >> kSizeShift) << kPageSizeBits; }
- static uptr SignExtend(uptr x) { return ((sptr)x) << kSizeBits >> kSizeBits; }
- void Init(void *storage, uptr size) {
- CHECK_EQ(sizeof(CompactRingBuffer<T>), sizeof(void *));
- CHECK(IsPowerOfTwo(size));
- CHECK_GE(size, 1 << kPageSizeBits);
- CHECK_LE(size, 128 << kPageSizeBits);
- CHECK_EQ(size % 4096, 0);
- CHECK_EQ(size % sizeof(T), 0);
- uptr st = (uptr)storage;
- CHECK_EQ(st % (size * 2), 0);
- CHECK_EQ(st, SignExtend(st & kNextMask));
- long_ = (st & kNextMask) | ((size >> kPageSizeBits) << kSizeShift);
- }
- void SetNext(const T *next) {
- long_ = (long_ & ~kNextMask) | ((uptr)next & kNextMask);
- }
- public:
- CompactRingBuffer(void *storage, uptr size) {
- Init(storage, size);
- }
- // A copy constructor of sorts.
- CompactRingBuffer(const CompactRingBuffer &other, void *storage) {
- uptr size = other.GetStorageSize();
- internal_memcpy(storage, other.StartOfStorage(), size);
- Init(storage, size);
- uptr Idx = other.Next() - (const T *)other.StartOfStorage();
- SetNext((const T *)storage + Idx);
- }
- T *Next() const { return (T *)(SignExtend(long_ & kNextMask)); }
- void *StartOfStorage() const {
- return (void *)((uptr)Next() & ~(GetStorageSize() - 1));
- }
- void *EndOfStorage() const {
- return (void *)((uptr)StartOfStorage() + GetStorageSize());
- }
- uptr size() const { return GetStorageSize() / sizeof(T); }
- void push(T t) {
- T *next = Next();
- *next = t;
- next++;
- next = (T *)((uptr)next & ~GetStorageSize());
- SetNext(next);
- }
- const T &operator[](uptr Idx) const {
- CHECK_LT(Idx, size());
- const T *Begin = (const T *)StartOfStorage();
- sptr StorageIdx = Next() - Begin;
- StorageIdx -= (sptr)(Idx + 1);
- if (StorageIdx < 0)
- StorageIdx += size();
- return Begin[StorageIdx];
- }
- public:
- ~CompactRingBuffer() {}
- CompactRingBuffer(const CompactRingBuffer &) = delete;
- uptr long_;
- };
- #endif
- } // namespace __sanitizer
- #endif // SANITIZER_RING_BUFFER_H
|