From 546f4e5e0500593b0c7cd0afa12e5e62d2b14707 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 11 Mar 2010 17:12:21 +0000 Subject: [PATCH] * Added create_ring_buffer_etc() which allows to re-create a ring buffer from a given flat buffer. * Added ring_buffer_peek() for random position reading from the ring buffer without changing its state. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@35813 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/kernel/util/ring_buffer.h | 9 +++ src/system/kernel/util/ring_buffer.cpp | 72 +++++++++++++++++++++-- 2 files changed, 76 insertions(+), 5 deletions(-) diff --git a/headers/private/kernel/util/ring_buffer.h b/headers/private/kernel/util/ring_buffer.h index 973d4c7519..e1f6e1cc04 100644 --- a/headers/private/kernel/util/ring_buffer.h +++ b/headers/private/kernel/util/ring_buffer.h @@ -17,11 +17,17 @@ struct ring_buffer { }; +// flags for create_ring_buffer_etc() +#define RING_BUFFER_INIT_FROM_BUFFER 0x01 + + #ifdef __cplusplus extern "C" { #endif struct ring_buffer *create_ring_buffer(size_t size); +struct ring_buffer *create_ring_buffer_etc(void *memory, size_t size, + uint32 flags); void delete_ring_buffer(struct ring_buffer *buffer); void ring_buffer_clear(struct ring_buffer *buffer); @@ -32,9 +38,12 @@ size_t ring_buffer_read(struct ring_buffer *buffer, uint8 *data, ssize_t length) size_t ring_buffer_write(struct ring_buffer *buffer, const uint8 *data, ssize_t length); ssize_t ring_buffer_user_read(struct ring_buffer *buffer, uint8 *data, ssize_t length); ssize_t ring_buffer_user_write(struct ring_buffer *buffer, const uint8 *data, ssize_t length); +size_t ring_buffer_peek(struct ring_buffer *buffer, size_t offset, void *data, + size_t length); #ifdef __cplusplus } #endif + #endif /* RING_BUFFER_H */ diff --git a/src/system/kernel/util/ring_buffer.cpp b/src/system/kernel/util/ring_buffer.cpp index 2e216047ab..3bd5a5f7ba 100644 --- a/src/system/kernel/util/ring_buffer.cpp +++ b/src/system/kernel/util/ring_buffer.cpp @@ -122,15 +122,38 @@ write_to_buffer(struct ring_buffer *buffer, const uint8 *data, ssize_t length, // #pragma mark - -struct ring_buffer * +struct ring_buffer* create_ring_buffer(size_t size) { - struct ring_buffer *buffer = (ring_buffer *)malloc(sizeof(ring_buffer) + size); - if (buffer == NULL) - return NULL; + return create_ring_buffer_etc(NULL, size, 0); +} + + +struct ring_buffer* +create_ring_buffer_etc(void* memory, size_t size, uint32 flags) +{ + if (memory == NULL) { + ring_buffer* buffer = (ring_buffer*)malloc(sizeof(ring_buffer) + size); + if (buffer == NULL) + return NULL; + + buffer->size = size; + ring_buffer_clear(buffer); + + return buffer; + } + + size -= sizeof(ring_buffer); + ring_buffer* buffer = (ring_buffer*)memory; buffer->size = size; - ring_buffer_clear(buffer); + if ((flags & RING_BUFFER_INIT_FROM_BUFFER) != 0 + && (size_t)buffer->size == size + && buffer->in >= 0 && (size_t)buffer->in <= size + && buffer->first >= 0 && (size_t)buffer->first < size) { + // structure looks valid + } else + ring_buffer_clear(buffer); return buffer; } @@ -205,6 +228,45 @@ ring_buffer_user_write(struct ring_buffer *buffer, const uint8 *data, ssize_t le } +/*! Reads data from the ring buffer, but doesn't remove the data from it. + \param buffer The ring buffer. + \param offset The offset relative to the beginning of the data in the ring + buffer at which to start reading. + \param data The buffer to which to copy the data. + \param length The number of bytes to read at maximum. + \return The number of bytes actually read from the buffer. +*/ +size_t +ring_buffer_peek(struct ring_buffer* buffer, size_t offset, void* data, + size_t length) +{ + size_t available = buffer->in; + + if (offset >= available || length == 0) + return 0; + + if (offset + length > available) + length = available - offset; + + if ((offset += buffer->first) >= (size_t)buffer->size) + offset -= buffer->size; + + if (offset + length <= (size_t)buffer->size) { + // simple copy + memcpy(data, buffer->buffer + offset, length); + } else { + // need to copy both ends + size_t upper = buffer->size - offset; + size_t lower = length - upper; + + memcpy(data, buffer->buffer + offset, upper); + memcpy((uint8*)data + upper, buffer->buffer, lower); + } + + return length; +} + + #if 0 /** Sends the contents of the ring buffer to a port. * The buffer will be empty afterwards only if sending the data actually works.