36#if defined(TIMEMORY_LINUX)
39# include <sys/types.h>
43#if !defined(TIMEMORY_RING_BUFFER_INLINE)
44# define TIMEMORY_RING_BUFFER_INLINE
63: m_use_mmap{ rhs.m_use_mmap }
64, m_use_mmap_explicit{ rhs.m_use_mmap_explicit }
76 m_use_mmap = rhs.m_use_mmap;
77 m_use_mmap_explicit = rhs.m_use_mmap_explicit;
87 throw std::runtime_error(
88 "tim::base::ring_buffer::init(size_t) :: already initialized");
93 _size += units::get_page_size() - ((_size % units::get_page_size() > 0)
94 ? (_size % units::get_page_size())
95 : units::get_page_size());
97 if((_size % units::get_page_size()) > 0)
99 std::ostringstream _oss{};
100 _oss <<
"Error! size is not a multiple of page size: " << _size <<
" % "
101 << units::get_page_size() <<
" = " << (_size % units::get_page_size());
102 throw std::runtime_error(_oss.str());
109 if(!m_use_mmap_explicit)
110 m_use_mmap =
get_env(
"TIMEMORY_USE_MMAP", m_use_mmap);
112#if defined(TIMEMORY_LINUX)
115 m_ptr = malloc(m_size *
sizeof(
char));
120 char path[] =
"/dev/shm/rb-XXXXXX";
122 char path[] =
"/tmp/rb-XXXXXX";
126 if((m_fd = mkstemp(path)) < 0)
136 if(ftruncate(m_fd, m_size) < 0)
140 if((m_ptr = mmap(NULL, 2 * m_size, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)) ==
145 if(mmap(m_ptr, m_size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, m_fd, 0) ==
152 if(mmap(
static_cast<char*
>(m_ptr) + m_size, m_size, PROT_READ | PROT_WRITE,
153 MAP_FIXED | MAP_SHARED, m_fd, 0) == MAP_FAILED)
157 m_ptr = malloc(m_size *
sizeof(
char));
169#if defined(TIMEMORY_LINUX)
177 if(ftruncate(m_fd, 0) < 0)
181 "Ring buffer failed to truncate the file "
186 auto ret = munmap(m_ptr, m_size * 2);
208 throw std::runtime_error(
"tim::base::ring_buffer::set_use_mmap(bool) cannot be "
209 "called after initialization");
211 m_use_mmap_explicit =
true;
218 std::ostringstream ss{};
220 <<
", capacity: " <<
capacity() <<
", count: " <<
count() <<
", free: " <<
free()
222 <<
", pointer: " << m_ptr <<
", read count: " << m_read_count
223 <<
", write count: " << m_write_count;
237 throw std::runtime_error(
"heap-buffer-overflow :: ring buffer is full. read data "
238 "to avoid data corruption");
241 auto _modulo = m_size - (m_write_count % m_size);
242 if(_modulo < _length)
243 m_write_count += _modulo;
246 void* _out = write_ptr();
249 m_write_count += _length;
263 if(_length >
count())
264 throw std::runtime_error(
"ring buffer is empty");
267 auto _modulo = m_size - (m_read_count % m_size);
268 if(_modulo < _length)
269 m_read_count += _modulo;
272 void* _out = read_ptr();
275 m_read_count += _length;
Tp get_env(const std::string &env_id, Tp _default, bool _store)
tim::mpl::apply< std::string > string
#define TIMEMORY_RING_BUFFER_INLINE
Ring buffer implementation, with support for mmap as backend (Linux only).
bool is_full() const
Returns if the buffer is full.
std::string as_string() const
void destroy()
Destroy ring buffer.
void init(size_t size)
Creates new ring buffer.
Tp * retrieve()
Retrieve a pointer to the head allocation (read).
void set_use_mmap(bool)
explicitly configure to use mmap if avail
bool is_empty() const
Returns if the buffer is empty.
Tp * request()
Request a pointer to an allocation. This is similar to a "write" except the memory is uninitialized....
size_t free() const
Returns how many bytes are availiable in the buffer.
bool is_initialized() const
Returns whether the buffer has been allocated.
size_t capacity() const
Get the total number of bytes supported.
ring_buffer & operator=(const ring_buffer &)
size_t rewind(size_t n) const
Rewind the read position n bytes.
size_t count() const
Returns number of bytes currently held by the buffer.
#define CONDITIONAL_PRINT_HERE(CONDITION,...)