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 && ((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 "
141 static inline uint64_t read64_impl(
const BufferDef& bd,
size_t index)
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);
163 static inline Message message(uint64_t header)
165 return (
Message)(header >> 32);
168 static inline uint32_t length(uint64_t header)
170 return header & std::numeric_limits<uint32_t>::max();
180 virtual uint64_t read64(
size_t index)
183 return read64_impl(bd, 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");
208 auto mask = bd.
size - 1;
209 auto hd = bd.
offsets->
head.load(std::memory_order_acquire);
210 auto hd_index = hd & mask;
211 auto block = bd.
size - hd_index;
215 while ((advance < block) && (count < limit))
217 auto msg_index = hd_index + advance;
218 auto header = read64(msg_index);
219 auto size = length(header);
222 if ((size & pending_write_flag) != 0u)
225 auto m = message(header);
256 clear_mem(hd_index, advance);
257 bd.
offsets->
head.store(hd + advance, std::memory_order_release);
294 size_t* identifier =
nullptr)
override
300 m, fmt::format(
"Cannot use a reserved message ({})", m));
309 "Message ({}) is too long for any writer: {} > {}",
321 "Message ({}) is too long for this writer: {} > {}",
327 auto r = reserve(rsize);
336 std::this_thread::yield();
338 }
while (!r.has_value());
352 if (identifier !=
nullptr)
353 *identifier = r.value().identifier;
360 if (marker.has_value())
364 const auto header = read64(index);
365 const auto size = length(header);
366 const auto m = message(header);
368 write64(index, finished_header);
379 const WriteMarker& marker,
const uint8_t* bytes,
size_t size)
override
381 if (!marker.has_value())
386 const auto index = marker.value();
393 ccf::pal::safe_memcpy(
bd.
data + index, bytes, size);
396 return {index + size};
405 static bool greater_with_wraparound(
size_t a,
size_t b)
407 static constexpr auto switch_point = UINT64_MAX / 2;
409 return (a != b) && ((a - b) < switch_point);
412 virtual uint64_t read64(
size_t index)
415 return read64_impl(
bd, index);
418 virtual void write64(
size_t index, uint64_t value)
421#ifdef __cpp_lib_atomic_ref
422 auto& ref = *(
reinterpret_cast<uint64_t*
>(
bd.
data + index));
423 std::atomic_ref<uint64_t> slot(ref);
424 slot.store(value, std::memory_order_release);
430 reinterpret_cast<uint64_t*
>(
bd.
data + index), &value, __ATOMIC_RELEASE);
434 std::optional<Reservation> reserve(
size_t size)
444 size_t tl_index = 0u;
449 auto avail =
bd.
size - gap;
453 if ((gap >
bd.
size) || (size > avail))
462 if (greater_with_wraparound(hd, tl))
467 avail =
bd.
size - (tl - hd);
479 tl_index = tl & mask;
480 auto block =
bd.
size - tl_index;
485 auto hd_index = hd & mask;
491 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)
Definition ring_buffer_types.h:153
Definition ring_buffer_types.h:61
std::optional< size_t > WriteMarker
Definition ring_buffer_types.h:98
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:175
size_t read(size_t limit, Handler f)
Definition ring_buffer.h:206
Reader(const BufferDef &bd_)
Definition ring_buffer.h:192
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:265
virtual std::optional< size_t > prepare(Message m, size_t size, bool wait=true, size_t *identifier=nullptr) override
Definition ring_buffer.h:290
Writer(const Reader &r)
Definition ring_buffer.h:281
virtual void finish(const WriteMarker &marker) override
Definition ring_buffer.h:358
BufferDef bd
Definition ring_buffer.h:267
virtual size_t get_max_message_size() override
Definition ring_buffer.h:372
const size_t rmax
Definition ring_buffer.h:268
Writer(const Writer &that)
Definition ring_buffer.h:286
virtual ~Writer()
Definition ring_buffer.h:288
virtual WriteMarker write_bytes(const WriteMarker &marker, const uint8_t *bytes, size_t size) override
Definition ring_buffer.h:378
Definition ring_buffer_types.h:49
Definition non_blocking.h:14
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
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
@ 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 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:25
std::atomic< size_t > head
Definition ring_buffer_types.h:45
std::atomic< size_t > head_cache
Definition ring_buffer_types.h:31
std::atomic< size_t > tail
Definition ring_buffer_types.h:39
Definition ring_buffer.h:581
std::vector< uint8_t > storage
Definition ring_buffer.h:582
BufferDef bd
Definition ring_buffer.h:585
Offsets offsets
Definition ring_buffer.h:583
TestBuffer(size_t size)
Definition ring_buffer.h:587
Definition ring_buffer.h:271
size_t index
Definition ring_buffer.h:273
size_t identifier
Definition ring_buffer.h:277