Add a ringbuffer implementation targetting byte sending
This adds a ringbuffer implementation that targets bytes sending. The ringbuffer can grow when there's not enough room, that's why it's not thread-safe (locking must be done externally). It will be shrinked to its initial size as soon as the used bytes are the half of the initial size.
This commit is contained in:
parent
94a836078f
commit
0ea1dc43ec
122
include/freerdp/utils/ringbuffer.h
Normal file
122
include/freerdp/utils/ringbuffer.h
Normal file
@ -0,0 +1,122 @@
|
||||
/**
|
||||
* Copyright © 2014 Thincast Technologies GmbH
|
||||
* Copyright © 2014 Hardening <contact@hardening-consulting.com>
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and
|
||||
* its documentation for any purpose is hereby granted without fee, provided
|
||||
* that the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation, and that the name of the copyright holders not be used in
|
||||
* advertising or publicity pertaining to distribution of the software
|
||||
* without specific, written prior permission. The copyright holders make
|
||||
* no representations about the suitability of this software for any
|
||||
* purpose. It is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __RINGBUFFER_H___
|
||||
#define __RINGBUFFER_H___
|
||||
|
||||
#include <winpr/wtypes.h>
|
||||
|
||||
/** @brief ring buffer meta data */
|
||||
struct _RingBuffer {
|
||||
size_t initialSize;
|
||||
size_t freeSize;
|
||||
size_t size;
|
||||
size_t readPtr;
|
||||
size_t writePtr;
|
||||
BYTE *buffer;
|
||||
};
|
||||
typedef struct _RingBuffer RingBuffer;
|
||||
|
||||
|
||||
/** @brief a piece of data in the ring buffer, exactly like a glibc iovec */
|
||||
struct _DataChunk {
|
||||
size_t size;
|
||||
const BYTE *data;
|
||||
};
|
||||
typedef struct _DataChunk DataChunk;
|
||||
|
||||
/** initialise a ringbuffer
|
||||
* @param initialSize the initial capacity of the ringBuffer
|
||||
* @return if the initialisation was successful
|
||||
*/
|
||||
BOOL ringbuffer_init(RingBuffer *rb, size_t initialSize);
|
||||
|
||||
/** destroys internal data used by this ringbuffer
|
||||
* @param ringbuffer
|
||||
*/
|
||||
void ringbuffer_destroy(RingBuffer *ringbuffer);
|
||||
|
||||
/** computes the space used in this ringbuffer
|
||||
* @param ringbuffer
|
||||
* @return the number of bytes stored in that ringbuffer
|
||||
*/
|
||||
size_t ringbuffer_used(const RingBuffer *ringbuffer);
|
||||
|
||||
/** returns the capacity of the ring buffer
|
||||
* @param ringbuffer
|
||||
* @return the capacity of this ring buffer
|
||||
*/
|
||||
size_t ringbuffer_capacity(const RingBuffer *ringbuffer);
|
||||
|
||||
/** writes some bytes in the ringbuffer, if the data doesn't fit, the ringbuffer
|
||||
* is resized automatically
|
||||
*
|
||||
* @param rb the ringbuffer
|
||||
* @param ptr a pointer on the data to add
|
||||
* @param sz the size of the data to add
|
||||
* @return if the operation was successful, it could fail in case of OOM during realloc()
|
||||
*/
|
||||
BOOL ringbuffer_write(RingBuffer *rb, const void *ptr, size_t sz);
|
||||
|
||||
|
||||
/** ensures that we have sz bytes available at the write head, and return a pointer
|
||||
* on the write head
|
||||
*
|
||||
* @param rb the ring buffer
|
||||
* @param sz the size to ensure
|
||||
* @return a pointer on the write head, or NULL in case of OOM
|
||||
*/
|
||||
BYTE *ringbuffer_ensure_linear_write(RingBuffer *rb, size_t sz);
|
||||
|
||||
/** move ahead the write head in case some byte were written directly by using
|
||||
* a pointer retrieved via ringbuffer_ensure_linear_write(). This function is
|
||||
* used to commit the written bytes. The provided size should not exceed the
|
||||
* size ensured by ringbuffer_ensure_linear_write()
|
||||
*
|
||||
* @param rb the ring buffer
|
||||
* @param sz the number of bytes that have been written
|
||||
* @return if the operation was successful, FALSE is sz is too big
|
||||
*/
|
||||
BOOL ringbuffer_commit_written_bytes(RingBuffer *rb, size_t sz);
|
||||
|
||||
|
||||
/** peeks the buffer chunks for sz bytes and returns how many chunks are filled.
|
||||
* Note that the sum of the resulting chunks may be smaller than sz.
|
||||
*
|
||||
* @param rb the ringbuffer
|
||||
* @param chunks an array of data chunks that will contain data / size of chunks
|
||||
* @param sz the requested size
|
||||
* @return the number of chunks used for reading sz bytes
|
||||
*/
|
||||
int ringbuffer_peek(const RingBuffer *rb, DataChunk chunks[2], size_t sz);
|
||||
|
||||
/** move ahead the read head in case some byte were read using ringbuffer_peek()
|
||||
* This function is used to commit the bytes that were effectively consumed.
|
||||
*
|
||||
* @param rb the ring buffer
|
||||
* @param sz the
|
||||
*/
|
||||
void ringbuffer_commit_read_bytes(RingBuffer *rb, size_t sz);
|
||||
|
||||
|
||||
#endif /* __RINGBUFFER_H___ */
|
@ -25,6 +25,7 @@ set(${MODULE_PREFIX}_SRCS
|
||||
pcap.c
|
||||
profiler.c
|
||||
rail.c
|
||||
ringbuffer.c
|
||||
signal.c
|
||||
stopwatch.c
|
||||
svc_plugin.c
|
||||
@ -68,3 +69,9 @@ else()
|
||||
endif()
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/libfreerdp")
|
||||
|
||||
|
||||
if(BUILD_TESTING)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
|
250
libfreerdp/utils/ringbuffer.c
Normal file
250
libfreerdp/utils/ringbuffer.c
Normal file
@ -0,0 +1,250 @@
|
||||
/**
|
||||
* Copyright © 2014 Thincast Technologies GmbH
|
||||
* Copyright © 2014 Hardening <contact@hardening-consulting.com>
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and
|
||||
* its documentation for any purpose is hereby granted without fee, provided
|
||||
* that the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation, and that the name of the copyright holders not be used in
|
||||
* advertising or publicity pertaining to distribution of the software
|
||||
* without specific, written prior permission. The copyright holders make
|
||||
* no representations about the suitability of this software for any
|
||||
* purpose. It is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <freerdp/utils/ringbuffer.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
BOOL ringbuffer_init(RingBuffer *rb, size_t initialSize)
|
||||
{
|
||||
rb->buffer = malloc(initialSize);
|
||||
if (!rb->buffer)
|
||||
return FALSE;
|
||||
|
||||
rb->readPtr = rb->writePtr = 0;
|
||||
rb->initialSize = rb->size = rb->freeSize = initialSize;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
size_t ringbuffer_used(const RingBuffer *ringbuffer)
|
||||
{
|
||||
return ringbuffer->size - ringbuffer->freeSize;
|
||||
}
|
||||
|
||||
size_t ringbuffer_capacity(const RingBuffer *ringbuffer)
|
||||
{
|
||||
return ringbuffer->size;
|
||||
}
|
||||
|
||||
void ringbuffer_destroy(RingBuffer *ringbuffer)
|
||||
{
|
||||
free(ringbuffer->buffer);
|
||||
ringbuffer->buffer = 0;
|
||||
}
|
||||
|
||||
static BOOL ringbuffer_realloc(RingBuffer *rb, size_t targetSize)
|
||||
{
|
||||
BYTE *newData;
|
||||
|
||||
if (rb->writePtr == rb->readPtr)
|
||||
{
|
||||
/* when no size is used we can realloc() and set the heads at the
|
||||
* beginning of the buffer
|
||||
*/
|
||||
newData = (BYTE *)realloc(rb->buffer, targetSize);
|
||||
if (!newData)
|
||||
return FALSE;
|
||||
rb->readPtr = rb->writePtr = 0;
|
||||
}
|
||||
else if ((rb->writePtr >= rb->readPtr) && (rb->writePtr < targetSize))
|
||||
{
|
||||
/* we reallocate only if we're in that case, realloc don't touch read
|
||||
* and write heads
|
||||
*
|
||||
* readPtr writePtr
|
||||
* | |
|
||||
* v v
|
||||
* [............|XXXXXXXXXXXXXX|..........]
|
||||
*/
|
||||
newData = (BYTE *)realloc(rb->buffer, targetSize);
|
||||
if (!newData)
|
||||
return FALSE;
|
||||
|
||||
rb->buffer = newData;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* in case of malloc the read head is moved at the beginning of the new buffer
|
||||
* and the write head is set accordingly
|
||||
*/
|
||||
newData = (BYTE *)malloc(targetSize);
|
||||
if (!newData)
|
||||
return FALSE;
|
||||
if (rb->readPtr < rb->writePtr)
|
||||
{
|
||||
/* readPtr writePtr
|
||||
* | |
|
||||
* v v
|
||||
* [............|XXXXXXXXXXXXXX|..........]
|
||||
*/
|
||||
memcpy(newData, rb->buffer + rb->readPtr, ringbuffer_used(rb));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* writePtr readPtr
|
||||
* | |
|
||||
* v v
|
||||
* [XXXXXXXXXXXX|..............|XXXXXXXXXX]
|
||||
*/
|
||||
BYTE *dst = newData;
|
||||
memcpy(dst, rb->buffer + rb->readPtr, rb->size - rb->readPtr);
|
||||
dst += (rb->size - rb->readPtr);
|
||||
if (rb->writePtr)
|
||||
memcpy(dst, rb->buffer, rb->writePtr);
|
||||
}
|
||||
rb->writePtr = rb->size - rb->freeSize;
|
||||
rb->readPtr = 0;
|
||||
rb->buffer = newData;
|
||||
}
|
||||
|
||||
rb->freeSize += (targetSize - rb->size);
|
||||
rb->size = targetSize;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param rb
|
||||
* @param ptr
|
||||
* @param sz
|
||||
* @return
|
||||
*/
|
||||
BOOL ringbuffer_write(RingBuffer *rb, const void *ptr, size_t sz)
|
||||
{
|
||||
if ((rb->freeSize <= sz) && !ringbuffer_realloc(rb, rb->size + sz))
|
||||
return FALSE;
|
||||
|
||||
/* the write could be split in two
|
||||
* readHead writeHead
|
||||
* | |
|
||||
* v v
|
||||
* [ ################ ]
|
||||
*/
|
||||
size_t toWrite = sz;
|
||||
size_t remaining = sz;
|
||||
if (rb->size - rb->writePtr < sz)
|
||||
toWrite = rb->size - rb->writePtr;
|
||||
|
||||
if (toWrite)
|
||||
{
|
||||
memcpy(rb->buffer + rb->writePtr, ptr, toWrite);
|
||||
remaining -= toWrite;
|
||||
ptr += toWrite;
|
||||
}
|
||||
|
||||
if (remaining)
|
||||
memcpy(rb->buffer, ptr, remaining);
|
||||
|
||||
rb->writePtr = (rb->writePtr + sz) % rb->size;
|
||||
|
||||
rb->freeSize -= sz;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
BYTE *ringbuffer_ensure_linear_write(RingBuffer *rb, size_t sz)
|
||||
{
|
||||
if (rb->freeSize < sz)
|
||||
{
|
||||
if (!ringbuffer_realloc(rb, rb->size + sz - rb->freeSize + 32))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (rb->writePtr == rb->readPtr)
|
||||
{
|
||||
rb->writePtr = rb->readPtr = 0;
|
||||
}
|
||||
|
||||
if (rb->writePtr + sz < rb->size)
|
||||
return rb->buffer + rb->writePtr;
|
||||
|
||||
/*
|
||||
* to add: .......
|
||||
* [ XXXXXXXXX ]
|
||||
*
|
||||
* result:
|
||||
* [XXXXXXXXX....... ]
|
||||
*/
|
||||
memmove(rb->buffer, rb->buffer + rb->readPtr, rb->writePtr - rb->readPtr);
|
||||
rb->readPtr = 0;
|
||||
rb->writePtr = rb->size - rb->freeSize;
|
||||
return rb->buffer + rb->writePtr;
|
||||
}
|
||||
|
||||
BOOL ringbuffer_commit_written_bytes(RingBuffer *rb, size_t sz)
|
||||
{
|
||||
if (rb->writePtr + sz > rb->size)
|
||||
return FALSE;
|
||||
rb->writePtr = (rb->writePtr + sz) % rb->size;
|
||||
rb->freeSize -= sz;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int ringbuffer_peek(const RingBuffer *rb, DataChunk chunks[2], size_t sz)
|
||||
{
|
||||
size_t remaining = sz;
|
||||
size_t toRead;
|
||||
int chunkIndex = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (rb->size - rb->freeSize < sz)
|
||||
remaining = rb->size - rb->freeSize;
|
||||
|
||||
toRead = remaining;
|
||||
|
||||
if (rb->readPtr + remaining > rb->size)
|
||||
toRead = rb->size - rb->readPtr;
|
||||
|
||||
if (toRead)
|
||||
{
|
||||
chunks[0].data = rb->buffer + rb->readPtr;
|
||||
chunks[0].size = toRead;
|
||||
remaining -= toRead;
|
||||
chunkIndex++;
|
||||
ret++;
|
||||
}
|
||||
|
||||
if (remaining)
|
||||
{
|
||||
chunks[chunkIndex].data = rb->buffer;
|
||||
chunks[chunkIndex].size = remaining;
|
||||
ret++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ringbuffer_commit_read_bytes(RingBuffer *rb, size_t sz)
|
||||
{
|
||||
assert(rb->size - rb->freeSize >= sz);
|
||||
|
||||
rb->readPtr = (rb->readPtr + sz) % rb->size;
|
||||
rb->freeSize += sz;
|
||||
|
||||
/* when we reach a reasonable free size, we can go back to the original size */
|
||||
if ((rb->size != rb->initialSize) && (ringbuffer_used(rb) < rb->initialSize / 2))
|
||||
ringbuffer_realloc(rb, rb->initialSize);
|
||||
}
|
34
libfreerdp/utils/test/CMakeLists.txt
Normal file
34
libfreerdp/utils/test/CMakeLists.txt
Normal file
@ -0,0 +1,34 @@
|
||||
|
||||
set(MODULE_NAME "TestFreeRDPutils")
|
||||
set(MODULE_PREFIX "TEST_FREERDP_UTILS")
|
||||
|
||||
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
|
||||
|
||||
set(${MODULE_PREFIX}_TESTS
|
||||
TestRingBuffer.c
|
||||
)
|
||||
|
||||
create_test_sourcelist(${MODULE_PREFIX}_SRCS
|
||||
${${MODULE_PREFIX}_DRIVER}
|
||||
${${MODULE_PREFIX}_TESTS}
|
||||
)
|
||||
|
||||
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
|
||||
|
||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
||||
MODULE winpr
|
||||
MODULES winpr-thread winpr-synch winpr-file winpr-utils winpr-crt freerdp-utils
|
||||
)
|
||||
|
||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||
|
||||
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
|
||||
|
||||
foreach(test ${${MODULE_PREFIX}_TESTS})
|
||||
get_filename_component(TestName ${test} NAME_WE)
|
||||
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
|
||||
endforeach()
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/Test")
|
||||
|
228
libfreerdp/utils/test/TestRingBuffer.c
Normal file
228
libfreerdp/utils/test/TestRingBuffer.c
Normal file
@ -0,0 +1,228 @@
|
||||
/**
|
||||
* Copyright © 2014 Thincast Technologies GmbH
|
||||
* Copyright © 2014 Hardening <contact@hardening-consulting.com>
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and
|
||||
* its documentation for any purpose is hereby granted without fee, provided
|
||||
* that the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation, and that the name of the copyright holders not be used in
|
||||
* advertising or publicity pertaining to distribution of the software
|
||||
* without specific, written prior permission. The copyright holders make
|
||||
* no representations about the suitability of this software for any
|
||||
* purpose. It is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <freerdp/utils/ringbuffer.h>
|
||||
|
||||
BOOL test_overlaps(void)
|
||||
{
|
||||
RingBuffer rb;
|
||||
DataChunk chunks[2];
|
||||
BYTE bytes[200];
|
||||
int nchunks, i, j, k, counter = 0;
|
||||
|
||||
for (i = 0; i < sizeof(bytes); i++)
|
||||
bytes[i] = (BYTE)i;
|
||||
|
||||
ringbuffer_init(&rb, 5);
|
||||
if (!ringbuffer_write(&rb, bytes, 4)) /* [0123.] */
|
||||
goto error;
|
||||
counter += 4;
|
||||
ringbuffer_commit_read_bytes(&rb, 2); /* [..23.] */
|
||||
|
||||
if (!ringbuffer_write(&rb, &bytes[counter], 2)) /* [5.234] */
|
||||
goto error;
|
||||
counter += 2;
|
||||
|
||||
nchunks = ringbuffer_peek(&rb, chunks, 4);
|
||||
if (nchunks != 2 || chunks[0].size != 3 || chunks[1].size != 1)
|
||||
goto error;
|
||||
|
||||
for (i = 0, j = 2; i < nchunks; i++)
|
||||
{
|
||||
for (k = 0; k < chunks[i].size; k++, j++)
|
||||
{
|
||||
if (chunks[i].data[k] != (BYTE)j)
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
ringbuffer_commit_read_bytes(&rb, 3); /* [5....] */
|
||||
if (ringbuffer_used(&rb) != 1)
|
||||
goto error;
|
||||
|
||||
if (!ringbuffer_write(&rb, &bytes[counter], 6)) /* [56789ab....] */
|
||||
goto error;
|
||||
counter += 6;
|
||||
|
||||
ringbuffer_commit_read_bytes(&rb, 6); /* [......b....] */
|
||||
nchunks = ringbuffer_peek(&rb, chunks, 10);
|
||||
if (nchunks != 1 || chunks[0].size != 1 || (*chunks[0].data != 0xb))
|
||||
goto error;
|
||||
|
||||
if (ringbuffer_capacity(&rb) != 5)
|
||||
goto error;
|
||||
|
||||
return TRUE;
|
||||
error:
|
||||
ringbuffer_destroy(&rb);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
int TestRingBuffer(int argc, char* argv[])
|
||||
{
|
||||
RingBuffer ringBuffer;
|
||||
int testNo = 0;
|
||||
BYTE *tmpBuf;
|
||||
BYTE *rb_ptr;
|
||||
int i/*, chunkNb, counter*/;
|
||||
DataChunk chunks[2];
|
||||
|
||||
if (!ringbuffer_init(&ringBuffer, 10))
|
||||
{
|
||||
fprintf(stderr, "unable to initialize ringbuffer\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
tmpBuf = (BYTE *)malloc(50);
|
||||
if (!tmpBuf)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < 50; i++)
|
||||
tmpBuf[i] = (char)i;
|
||||
|
||||
fprintf(stderr, "%d: basic tests...", ++testNo);
|
||||
if (!ringbuffer_write(&ringBuffer, tmpBuf, 5) || !ringbuffer_write(&ringBuffer, tmpBuf, 5) ||
|
||||
!ringbuffer_write(&ringBuffer, tmpBuf, 5))
|
||||
{
|
||||
fprintf(stderr, "error when writing bytes\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ringbuffer_used(&ringBuffer) != 15)
|
||||
{
|
||||
fprintf(stderr, "invalid used size got %d when i would expect 15\n", ringbuffer_used(&ringBuffer));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ringbuffer_peek(&ringBuffer, chunks, 10) != 1 || chunks[0].size != 10)
|
||||
{
|
||||
fprintf(stderr, "error when reading bytes\n");
|
||||
return -1;
|
||||
}
|
||||
ringbuffer_commit_read_bytes(&ringBuffer, chunks[0].size);
|
||||
|
||||
/* check retrieved bytes */
|
||||
for (i = 0; i < chunks[0].size; i++)
|
||||
{
|
||||
if (chunks[0].data[i] != i % 5)
|
||||
{
|
||||
fprintf(stderr, "invalid byte at %d, got %d instead of %d\n", i, chunks[0].data[i], i % 5);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (ringbuffer_used(&ringBuffer) != 5)
|
||||
{
|
||||
fprintf(stderr, "invalid used size after read got %d when i would expect 5\n", ringbuffer_used(&ringBuffer));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* write some more bytes to have writePtr < readPtr and data splitted in 2 chunks */
|
||||
if (!ringbuffer_write(&ringBuffer, tmpBuf, 6) ||
|
||||
ringbuffer_peek(&ringBuffer, chunks, 11) != 2 ||
|
||||
chunks[0].size != 10 ||
|
||||
chunks[1].size != 1)
|
||||
{
|
||||
fprintf(stderr, "invalid read of splitted data\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ringbuffer_commit_read_bytes(&ringBuffer, 11);
|
||||
fprintf(stderr, "ok\n");
|
||||
|
||||
fprintf(stderr, "%d: peek with nothing to read...", ++testNo);
|
||||
if (ringbuffer_peek(&ringBuffer, chunks, 10))
|
||||
{
|
||||
fprintf(stderr, "peek returns some chunks\n");
|
||||
return -1;
|
||||
}
|
||||
fprintf(stderr, "ok\n");
|
||||
|
||||
fprintf(stderr, "%d: ensure_linear_write / read() shouldn't grow...", ++testNo);
|
||||
for (i = 0; i < 1000; i++)
|
||||
{
|
||||
rb_ptr = ringbuffer_ensure_linear_write(&ringBuffer, 50);
|
||||
if (!rb_ptr)
|
||||
{
|
||||
fprintf(stderr, "ringbuffer_ensure_linear_write() error\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(rb_ptr, tmpBuf, 50);
|
||||
|
||||
if (!ringbuffer_commit_written_bytes(&ringBuffer, 50))
|
||||
{
|
||||
fprintf(stderr, "ringbuffer_commit_written_bytes() error, i=%d\n", i);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//ringbuffer_commit_read_bytes(&ringBuffer, 25);
|
||||
}
|
||||
|
||||
for (i = 0; i < 1000; i++)
|
||||
ringbuffer_commit_read_bytes(&ringBuffer, 25);
|
||||
|
||||
for (i = 0; i < 1000; i++)
|
||||
ringbuffer_commit_read_bytes(&ringBuffer, 25);
|
||||
|
||||
|
||||
if (ringbuffer_capacity(&ringBuffer) != 10)
|
||||
{
|
||||
fprintf(stderr, "not the expected capacity, have %d and expects 10\n", ringbuffer_capacity(&ringBuffer));
|
||||
return -1;
|
||||
}
|
||||
fprintf(stderr, "ok\n");
|
||||
|
||||
|
||||
fprintf(stderr, "%d: free size is correctly computed...", ++testNo);
|
||||
for (i = 0; i < 1000; i++)
|
||||
{
|
||||
ringbuffer_ensure_linear_write(&ringBuffer, 50);
|
||||
if (!ringbuffer_commit_written_bytes(&ringBuffer, 50))
|
||||
{
|
||||
fprintf(stderr, "ringbuffer_commit_written_bytes() error, i=%d\n", i);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
ringbuffer_commit_read_bytes(&ringBuffer, 50 * 1000);
|
||||
fprintf(stderr, "ok\n");
|
||||
|
||||
ringbuffer_destroy(&ringBuffer);
|
||||
|
||||
fprintf(stderr, "%d: specific overlaps test...", ++testNo);
|
||||
if (!test_overlaps())
|
||||
{
|
||||
fprintf(stderr, "ko\n", i);
|
||||
return -1;
|
||||
}
|
||||
fprintf(stderr, "ok\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user