29 static constexpr uint32_t pending_write_flag = 1 << 31;
30 static constexpr uint32_t length_mask = ~pending_write_flag;
36 msg_max = std::numeric_limits<Message>::max() - 1,
39 msg_pad = std::numeric_limits<Message>::max()
44 return (n != 0u) && ((n & (~n + 1)) == n);
47 static bool is_aligned(uint8_t
const* data,
size_t align)
49 return reinterpret_cast<std::uintptr_t
>(data) % align == 0;
55 return sizeof(int32_t) +
sizeof(uint32_t);
73 return std::numeric_limits<int32_t>::max() -
header_size();
83 return buffer_size / 2;
88 const auto lz = __builtin_clzll(n);
89 return 1ul << (
sizeof(size_t) * 8 - 1 - lz);
94 void* data =
reinterpret_cast<void*
>(data_);
97 auto* ret = std::align(8,
sizeof(
size_t), data, size);
103 data_ =
reinterpret_cast<uint8_t*
>(data);
110 return (((uint64_t)m) << 32) |
111 ((size & length_mask) | (pending ? pending_write_flag : 0u));
124 if (index + access_size >
size)
126#ifdef RINGBUFFER_USE_ABORT
129 throw std::runtime_error(fmt::format(
130 "Ringbuffer access out of bounds - attempting to access {}, max "
143 auto* src = bd.
data + index;
144 auto* src_64 =
reinterpret_cast<uint64_t*
>(src);
146#ifdef __cpp_lib_atomic_ref
150 std::atomic_ref<uint64_t> slot(ref);
151 return slot.load(std::memory_order_acquire);
159 __atomic_load(src_64, &r, __ATOMIC_ACQUIRE);
165 return (
Message)(header >> 32);
170 return header & std::numeric_limits<uint32_t>::max();
180 virtual uint64_t read64(
size_t index)
186 virtual void clear_mem(
size_t index,
size_t advance)
188 ::memset(bd.
data + index, 0, advance);
196 throw std::logic_error(
197 fmt::format(
"Buffer size must be a power of 2, not {}", bd.
size));
202 throw std::logic_error(
"Buffer must be 8-byte aligned");
210 auto mask = bd.
size - 1;
211 auto hd = bd.
offsets->
head.load(std::memory_order_acquire);
212 auto hd_index = hd & mask;
213 auto block = bd.
size - hd_index;
217 while ((advance < block) && (count < limit))
219 auto msg_index = hd_index + advance;
220 auto header = read64(msg_index);
224 if ((size & pending_write_flag) != 0u)
261 clear_mem(hd_index, advance);
262 bd.
offsets->
head.store(hd + advance, std::memory_order_release);
299 size_t* identifier =
nullptr)
override
305 m, fmt::format(
"Cannot use a reserved message ({})", m));
314 "Message ({}) is too long for any writer: {} > {}",
326 "Message ({}) is too long for this writer: {} > {}",
332 auto r = reserve(rsize);
341 std::this_thread::yield();
343 }
while (!r.has_value());
357 if (identifier !=
nullptr)
359 *identifier = r.value().identifier;
367 if (marker.has_value())
371 const auto header = read64(index);
375 write64(index, finished_header);
386 const WriteMarker& marker,
const uint8_t* bytes,
size_t size)
override
388 if (!marker.has_value())
393 const auto index = marker.value();
400 ccf::pal::safe_memcpy(
bd.
data + index, bytes, size);
403 return {index + size};
412 static bool greater_with_wraparound(
size_t a,
size_t b)
414 static constexpr auto switch_point = UINT64_MAX / 2;
416 return (a != b) && ((a - b) < switch_point);
419 virtual uint64_t read64(
size_t index)
425 virtual void write64(
size_t index, uint64_t value)
428#ifdef __cpp_lib_atomic_ref
429 auto& ref = *(
reinterpret_cast<uint64_t*
>(
bd.
data + index));
430 std::atomic_ref<uint64_t> slot(ref);
431 slot.store(value, std::memory_order_release);
437 reinterpret_cast<uint64_t*
>(
bd.
data + index), &value, __ATOMIC_RELEASE);
441 std::optional<Reservation> reserve(
size_t size)
451 size_t tl_index = 0u;
456 auto avail =
bd.
size - gap;
460 if ((gap >
bd.
size) || (size > avail))
469 if (greater_with_wraparound(hd, tl))
474 avail =
bd.
size - (tl - hd);
488 tl_index = tl & mask;
489 auto block =
bd.
size - tl_index;
494 auto hd_index = hd & mask;
500 hd_index = hd & mask;
519 tl, tl + size + padding, std::memory_order_seq_cst));
530 return {{tl_index, tl}};
545 from_outside(from_outside_buffer),
546 from_inside(from_inside_buffer)
561 return {from_inside};
566 return {from_outside};
Definition ring_buffer_types.h:157
Definition ring_buffer_types.h:63
std::optional< size_t > WriteMarker
Definition ring_buffer_types.h:100
Definition ring_buffer.h:536
ringbuffer::Writer write_to_inside()
Definition ring_buffer.h:564
ringbuffer::Reader & read_from_inside()
Definition ring_buffer.h:554
Circuit(const BufferDef &from_outside_buffer, const BufferDef &from_inside_buffer)
Definition ring_buffer.h:542
ringbuffer::Reader & read_from_outside()
Definition ring_buffer.h:549
ringbuffer::Writer write_to_outside()
Definition ring_buffer.h:559
Definition ring_buffer.h:175
size_t read(size_t limit, Handler f)
Definition ring_buffer.h:208
virtual ~Reader()=default
Reader(const BufferDef &bd_)
Definition ring_buffer.h:192
Definition ring_buffer.h:571
WriterFactory(ringbuffer::Circuit &c)
Definition ring_buffer.h:575
std::shared_ptr< ringbuffer::AbstractWriter > create_writer_to_inside() override
Definition ring_buffer.h:583
std::shared_ptr< ringbuffer::AbstractWriter > create_writer_to_outside() override
Definition ring_buffer.h:577
Definition ring_buffer.h:270
std::optional< size_t > prepare(Message m, size_t size, bool wait=true, size_t *identifier=nullptr) override
Definition ring_buffer.h:295
~Writer() override=default
Writer(const Reader &r)
Definition ring_buffer.h:286
BufferDef bd
Definition ring_buffer.h:272
const size_t rmax
Definition ring_buffer.h:273
Writer(const Writer &that)
Definition ring_buffer.h:291
WriteMarker write_bytes(const WriteMarker &marker, const uint8_t *bytes, size_t size) override
Definition ring_buffer.h:385
void finish(const WriteMarker &marker) override
Definition ring_buffer.h:365
size_t get_max_message_size() override
Definition ring_buffer.h:379
Definition ring_buffer_types.h:51
uint32_t length(uint64_t header)
Definition ring_buffer.h:168
uint64_t read64_impl(const BufferDef &bd, size_t index)
Definition ring_buffer.h:141
Message message(uint64_t header)
Definition ring_buffer.h:163
Definition non_blocking.h:15
std::function< void(Message, const uint8_t *, size_t)> Handler
Definition ring_buffer.h:26
uint32_t Message
Definition ring_buffer_types.h:19
Definition ring_buffer.h:116
void check_access(size_t index, size_t access_size)
Definition ring_buffer.h:122
uint8_t * data
Definition ring_buffer.h:117
Offsets * offsets
Definition ring_buffer.h:120
size_t size
Definition ring_buffer.h:118
Definition ring_buffer.h:33
@ msg_pad
Definition ring_buffer.h:39
@ msg_max
Definition ring_buffer.h:36
@ msg_none
Definition ring_buffer.h:38
@ msg_min
Definition ring_buffer.h:37
static constexpr size_t max_size()
Definition ring_buffer.h:69
static constexpr bool is_power_of_2(size_t n)
Definition ring_buffer.h:42
static constexpr size_t align_size(size_t n)
Definition ring_buffer.h:58
static constexpr size_t previous_power_of_2(size_t n)
Definition ring_buffer.h:86
static bool find_acceptable_sub_buffer(uint8_t *&data_, size_t &size_)
Definition ring_buffer.h:92
static bool is_aligned(uint8_t const *data, size_t align)
Definition ring_buffer.h:47
static constexpr size_t entry_size(size_t n)
Definition ring_buffer.h:64
static constexpr size_t max_reservation_size(size_t buffer_size)
Definition ring_buffer.h:76
static constexpr size_t header_size()
Definition ring_buffer.h:52
static uint64_t make_header(Message m, size_t size, bool pending=true)
Definition ring_buffer.h:108
Definition ring_buffer_types.h:26
std::atomic< size_t > head
Definition ring_buffer_types.h:31
std::atomic< size_t > head_cache
Definition ring_buffer_types.h:38
std::atomic< size_t > tail
Definition ring_buffer_types.h:46
Definition ring_buffer.h:592
std::vector< uint8_t > storage
Definition ring_buffer.h:594
BufferDef bd
Definition ring_buffer.h:595
Offsets offsets
Definition ring_buffer.h:593
TestBuffer(size_t size)
Definition ring_buffer.h:597
Definition ring_buffer.h:276
size_t index
Definition ring_buffer.h:278
size_t identifier
Definition ring_buffer.h:282