16#define CCF_PAUSE() asm volatile("pause")
34 static constexpr uint32_t pending_write_flag = 1 << 31;
35 static constexpr uint32_t length_mask = ~pending_write_flag;
41 msg_max = std::numeric_limits<Message>::max() - 1,
44 msg_pad = std::numeric_limits<Message>::max()
49 return n && ((n & (~n + 1)) == n);
52 static bool is_aligned(uint8_t
const* data,
size_t align)
54 return reinterpret_cast<std::uintptr_t
>(data) % align == 0;
60 return sizeof(int32_t) +
sizeof(uint32_t);
78 return std::numeric_limits<int32_t>::max() -
header_size();
88 return buffer_size / 2;
93 const auto lz = __builtin_clzll(n);
94 return 1ul << (
sizeof(size_t) * 8 - 1 - lz);
99 void* data =
reinterpret_cast<void*
>(data_);
102 auto ret = std::align(8,
sizeof(
size_t), data, size);
108 data_ =
reinterpret_cast<uint8_t*
>(data);
115 return (((uint64_t)m) << 32) |
116 ((size & length_mask) | (pending ? pending_write_flag : 0u));
129 if (index + access_size >
size)
131#ifdef RINGBUFFER_USE_ABORT
134 throw std::runtime_error(fmt::format(
135 "Ringbuffer access out of bounds - attempting to access {}, max "
146 static inline uint64_t read64_impl(
const BufferDef& bd,
size_t index)
148#ifdef __cpp_lib_atomic_ref
149 auto& ref = *(
reinterpret_cast<uint64_t*
>(bd.data + index));
150 std::atomic_ref<uint64_t> slot(ref);
151 return slot.load(std::memory_order_acquire);
158 reinterpret_cast<uint64_t*
>(bd.data + index), &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 std::vector<uint8_t> local_copy;
182 virtual uint64_t read64(
size_t index)
185 return read64_impl(bd, index);
188 virtual void clear_mem(
size_t index,
size_t advance)
190 ::memset(bd.
data + index, 0, advance);
198 throw std::logic_error(
199 fmt::format(
"Buffer size must be a power of 2, not {}", bd.
size));
204 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);
221 auto size = length(header);
224 if ((size & pending_write_flag) != 0u)
227 auto m = message(header);
251 if (ccf::pal::require_alignment_for_untrusted_reads() && size > 0)
256 if (local_copy.size() < copy_size)
258 local_copy.resize(copy_size);
260 ccf::pal::safe_memcpy(
264 f(m, local_copy.data(), (
size_t)size);
276 clear_mem(hd_index, advance);
277 bd.
offsets->
head.store(hd + advance, std::memory_order_release);
314 size_t* identifier =
nullptr)
override
320 m, fmt::format(
"Cannot use a reserved message ({})", m));
329 "Message ({}) is too long for any writer: {} > {}",
341 "Message ({}) is too long for this writer: {} > {}",
347 auto r = reserve(rsize);
358 }
while (!r.has_value());
372 if (identifier !=
nullptr)
373 *identifier = r.value().identifier;
380 if (marker.has_value())
384 const auto header = read64(index);
385 const auto size = length(header);
386 const auto m = message(header);
388 write64(index, finished_header);
399 const WriteMarker& marker,
const uint8_t* bytes,
size_t size)
override
401 if (!marker.has_value())
406 const auto index = marker.value();
413 ccf::pal::safe_memcpy(
bd.
data + index, bytes, size);
416 return {index + size};
425 static bool greater_with_wraparound(
size_t a,
size_t b)
427 static constexpr auto switch_point = UINT64_MAX / 2;
429 return (a != b) && ((a - b) < switch_point);
432 virtual uint64_t read64(
size_t index)
435 return read64_impl(
bd, index);
438 virtual void write64(
size_t index, uint64_t value)
441#ifdef __cpp_lib_atomic_ref
442 auto& ref = *(
reinterpret_cast<uint64_t*
>(
bd.
data + index));
443 std::atomic_ref<uint64_t> slot(ref);
444 slot.store(value, std::memory_order_release);
450 reinterpret_cast<uint64_t*
>(
bd.
data + index), &value, __ATOMIC_RELEASE);
454 std::optional<Reservation> reserve(
size_t size)
464 size_t tl_index = 0u;
469 auto avail =
bd.
size - gap;
473 if ((gap >
bd.
size) || (size > avail))
482 if (greater_with_wraparound(hd, tl))
487 avail =
bd.
size - (tl - hd);
499 tl_index = tl & mask;
500 auto block =
bd.
size - tl_index;
505 auto hd_index = hd & mask;
511 hd_index = hd & mask;
528 tl, tl + size + padding, std::memory_order_seq_cst));
539 return {{tl_index, tl}};
554 from_outside(from_outside_buffer),
555 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:545
ringbuffer::Writer write_to_inside()
Definition ring_buffer.h:573
ringbuffer::Reader & read_from_inside()
Definition ring_buffer.h:563
Circuit(const BufferDef &from_outside_buffer, const BufferDef &from_inside_buffer)
Definition ring_buffer.h:551
ringbuffer::Reader & read_from_outside()
Definition ring_buffer.h:558
ringbuffer::Writer write_to_outside()
Definition ring_buffer.h:568
Definition ring_buffer.h:175
size_t read(size_t limit, Handler f)
Definition ring_buffer.h:208
Reader(const BufferDef &bd_)
Definition ring_buffer.h:194
Definition ring_buffer.h:580
WriterFactory(ringbuffer::Circuit &c)
Definition ring_buffer.h:584
std::shared_ptr< ringbuffer::AbstractWriter > create_writer_to_inside() override
Definition ring_buffer.h:592
std::shared_ptr< ringbuffer::AbstractWriter > create_writer_to_outside() override
Definition ring_buffer.h:586
Definition ring_buffer.h:285
virtual std::optional< size_t > prepare(Message m, size_t size, bool wait=true, size_t *identifier=nullptr) override
Definition ring_buffer.h:310
Writer(const Reader &r)
Definition ring_buffer.h:301
virtual void finish(const WriteMarker &marker) override
Definition ring_buffer.h:378
BufferDef bd
Definition ring_buffer.h:287
virtual size_t get_max_message_size() override
Definition ring_buffer.h:392
const size_t rmax
Definition ring_buffer.h:288
Writer(const Writer &that)
Definition ring_buffer.h:306
virtual ~Writer()
Definition ring_buffer.h:308
virtual WriteMarker write_bytes(const WriteMarker &marker, const uint8_t *bytes, size_t size) override
Definition ring_buffer.h:398
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:31
uint32_t Message
Definition ring_buffer_types.h:19
#define CCF_PAUSE()
Definition ring_buffer.h:16
Definition ring_buffer.h:121
void check_access(size_t index, size_t access_size)
Definition ring_buffer.h:127
uint8_t * data
Definition ring_buffer.h:122
Offsets * offsets
Definition ring_buffer.h:125
size_t size
Definition ring_buffer.h:123
Definition ring_buffer.h:38
@ msg_pad
Definition ring_buffer.h:44
@ msg_max
Definition ring_buffer.h:41
@ msg_none
Definition ring_buffer.h:43
@ msg_min
Definition ring_buffer.h:42
static constexpr size_t max_size()
Definition ring_buffer.h:74
static constexpr bool is_power_of_2(size_t n)
Definition ring_buffer.h:47
static constexpr size_t align_size(size_t n)
Definition ring_buffer.h:63
static constexpr size_t previous_power_of_2(size_t n)
Definition ring_buffer.h:91
static bool find_acceptable_sub_buffer(uint8_t *&data_, size_t &size_)
Definition ring_buffer.h:97
static bool is_aligned(uint8_t const *data, size_t align)
Definition ring_buffer.h:52
static constexpr size_t entry_size(size_t n)
Definition ring_buffer.h:69
static constexpr size_t max_reservation_size(size_t buffer_size)
Definition ring_buffer.h:81
static constexpr size_t header_size()
Definition ring_buffer.h:57
static uint64_t make_header(Message m, size_t size, bool pending=true)
Definition ring_buffer.h:113
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:601
std::vector< uint8_t > storage
Definition ring_buffer.h:602
BufferDef bd
Definition ring_buffer.h:605
Offsets offsets
Definition ring_buffer.h:603
TestBuffer(size_t size)
Definition ring_buffer.h:607
Definition ring_buffer.h:291
size_t index
Definition ring_buffer.h:293
size_t identifier
Definition ring_buffer.h:297