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);
149 std::atomic_ref<uint64_t> slot(ref);
150 return slot.load(std::memory_order_acquire);
156 __atomic_load(src_64, &r, __ATOMIC_ACQUIRE);
162 return (
Message)(header >> 32);
167 return header & std::numeric_limits<uint32_t>::max();
177 virtual uint64_t read64(
size_t index)
183 virtual void clear_mem(
size_t index,
size_t advance)
185 ::memset(bd.
data + index, 0, advance);
193 throw std::logic_error(
194 fmt::format(
"Buffer size must be a power of 2, not {}", bd.
size));
199 throw std::logic_error(
"Buffer must be 8-byte aligned");
207 auto mask = bd.
size - 1;
208 auto hd = bd.
offsets->
head.load(std::memory_order_acquire);
209 auto hd_index = hd & mask;
210 auto block = bd.
size - hd_index;
214 while ((advance < block) && (count < limit))
216 auto msg_index = hd_index + advance;
217 auto header = read64(msg_index);
221 if ((size & pending_write_flag) != 0u)
258 clear_mem(hd_index, advance);
259 bd.
offsets->
head.store(hd + advance, std::memory_order_release);
296 size_t* identifier =
nullptr)
override
302 m, fmt::format(
"Cannot use a reserved message ({})", m));
311 "Message ({}) is too long for any writer: {} > {}",
323 "Message ({}) is too long for this writer: {} > {}",
329 auto r = reserve(rsize);
338 std::this_thread::yield();
340 }
while (!r.has_value());
354 if (identifier !=
nullptr)
356 *identifier = r.value().identifier;
364 if (marker.has_value())
368 const auto header = read64(index);
372 write64(index, finished_header);
383 const WriteMarker& marker,
const uint8_t* bytes,
size_t size)
override
385 if (!marker.has_value())
390 const auto index = marker.value();
397 ccf::pal::safe_memcpy(
bd.
data + index, bytes, size);
400 return {index + size};
409 static bool greater_with_wraparound(
size_t a,
size_t b)
411 static constexpr auto switch_point = UINT64_MAX / 2;
413 return (a != b) && ((a - b) < switch_point);
416 virtual uint64_t read64(
size_t index)
422 virtual void write64(
size_t index, uint64_t value)
425 auto& ref = *(
reinterpret_cast<uint64_t*
>(
bd.
data + index));
426 std::atomic_ref<uint64_t> slot(ref);
427 slot.store(value, std::memory_order_release);
430 std::optional<Reservation> reserve(
size_t size)
440 size_t tl_index = 0u;
445 auto avail =
bd.
size - gap;
449 if ((gap >
bd.
size) || (size > avail))
458 if (greater_with_wraparound(hd, tl))
463 avail =
bd.
size - (tl - hd);
477 tl_index = tl & mask;
478 auto block =
bd.
size - tl_index;
483 auto hd_index = hd & mask;
489 hd_index = hd & mask;
508 tl, tl + size + padding, std::memory_order_seq_cst));
519 return {{tl_index, tl}};
534 from_outside(from_outside_buffer),
535 from_inside(from_inside_buffer)
550 return {from_inside};
555 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:525
ringbuffer::Writer write_to_inside()
Definition ring_buffer.h:553
ringbuffer::Reader & read_from_inside()
Definition ring_buffer.h:543
Circuit(const BufferDef &from_outside_buffer, const BufferDef &from_inside_buffer)
Definition ring_buffer.h:531
ringbuffer::Reader & read_from_outside()
Definition ring_buffer.h:538
ringbuffer::Writer write_to_outside()
Definition ring_buffer.h:548
Definition ring_buffer.h:172
size_t read(size_t limit, Handler f)
Definition ring_buffer.h:205
virtual ~Reader()=default
Reader(const BufferDef &bd_)
Definition ring_buffer.h:189
Definition ring_buffer.h:560
WriterFactory(ringbuffer::Circuit &c)
Definition ring_buffer.h:564
std::shared_ptr< ringbuffer::AbstractWriter > create_writer_to_inside() override
Definition ring_buffer.h:572
std::shared_ptr< ringbuffer::AbstractWriter > create_writer_to_outside() override
Definition ring_buffer.h:566
Definition ring_buffer.h:267
std::optional< size_t > prepare(Message m, size_t size, bool wait=true, size_t *identifier=nullptr) override
Definition ring_buffer.h:292
~Writer() override=default
Writer(const Reader &r)
Definition ring_buffer.h:283
BufferDef bd
Definition ring_buffer.h:269
const size_t rmax
Definition ring_buffer.h:270
Writer(const Writer &that)
Definition ring_buffer.h:288
WriteMarker write_bytes(const WriteMarker &marker, const uint8_t *bytes, size_t size) override
Definition ring_buffer.h:382
void finish(const WriteMarker &marker) override
Definition ring_buffer.h:362
size_t get_max_message_size() override
Definition ring_buffer.h:376
Definition ring_buffer_types.h:51
uint32_t length(uint64_t header)
Definition ring_buffer.h:165
uint64_t read64_impl(const BufferDef &bd, size_t index)
Definition ring_buffer.h:141
Message message(uint64_t header)
Definition ring_buffer.h:160
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:581
std::vector< uint8_t > storage
Definition ring_buffer.h:583
BufferDef bd
Definition ring_buffer.h:584
Offsets offsets
Definition ring_buffer.h:582
TestBuffer(size_t size)
Definition ring_buffer.h:586
Definition ring_buffer.h:273
size_t index
Definition ring_buffer.h:275
size_t identifier
Definition ring_buffer.h:279