Viewing file: sanitizer_ring_buffer.h (4.7 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
//===-- 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 uptr kNextMask = (1ULL << kSizeShift) - 1;
uptr GetStorageSize() const { return (long_ >> kSizeShift) << kPageSizeBits; }
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); CHECK_EQ((uptr)storage % (size * 2), 0); long_ = (uptr)storage | ((size >> kPageSizeBits) << kSizeShift); }
void SetNext(const T *next) { long_ = (long_ & ~kNextMask) | (uptr)next; }
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 *)(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
|