summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2011-10-09 22:56:37 +0000
committerDavid Robillard <d@drobilla.net>2011-10-09 22:56:37 +0000
commit3a38a92326c983ba33807d956a4bbfb4b05da971 (patch)
treeef67288b0b40a6ccf47fe7df0ff9c917ed1f3751
parentdced6dde703f2cf7fc2980507139d67f6d5dcc9c (diff)
downloadraul-3a38a92326c983ba33807d956a4bbfb4b05da971.tar.gz
raul-3a38a92326c983ba33807d956a4bbfb4b05da971.tar.bz2
raul-3a38a92326c983ba33807d956a4bbfb4b05da971.zip
Fix RingBuffer error when reading split/wrapped messages.
More rigorous, multithreaded RingBuffer test. git-svn-id: http://svn.drobilla.net/lad/trunk/raul@3540 a436a847-0d15-0410-975c-d299462d15a1
-rw-r--r--raul/RingBuffer.hpp2
-rw-r--r--test/ringbuffer_test.cpp172
2 files changed, 120 insertions, 54 deletions
diff --git a/raul/RingBuffer.hpp b/raul/RingBuffer.hpp
index 8642514..faf1142 100644
--- a/raul/RingBuffer.hpp
+++ b/raul/RingBuffer.hpp
@@ -199,7 +199,7 @@ private:
} else {
const uint32_t first_size = _size - r;
memcpy(dst, &_buf[r], first_size);
- memcpy(dst, &_buf[0], size - first_size);
+ memcpy((char*)dst + first_size, &_buf[0], size - first_size);
}
return size;
diff --git a/test/ringbuffer_test.cpp b/test/ringbuffer_test.cpp
index ea1088c..c843ed2 100644
--- a/test/ringbuffer_test.cpp
+++ b/test/ringbuffer_test.cpp
@@ -1,6 +1,7 @@
-#include <iostream>
-#include <cstring>
+#include <cstdio>
#include <cstdlib>
+#include <cstring>
+#include <iostream>
#include "raul/log.hpp"
#include "raul/RingBuffer.hpp"
@@ -8,67 +9,132 @@
using namespace std;
using namespace Raul;
-int
-main()
+#define MSG_SIZE 20
+
+Raul::RingBuffer* ring = 0;
+size_t n_writes = 0;
+bool ring_error = false;
+
+static int
+gen_msg(int* msg, int start)
{
- static const int n_tests = 32;
- for (int i = 0; i < n_tests; ++i) {
- const int size = (rand() % 2000) + 8;
- RingBuffer rb(size);
-
- for (int j = 0; j < size * 32; ++j) {
- char ev1[] = { 'a', 'b', 'c' };
- rb.write(3, ev1);
-
- char buf[3];
- uint32_t read = rb.read(3, buf);
- if (read != 3 || strncmp(buf, "abc", 3)) {
- error << "Corrupt event " << i << ".1: "
- << buf[0] << buf[1] << buf[2] << endl;
- return 1;
- }
-
- char ev2[] = { 'd', 'e', 'f' };
- if (!rb.write(3, ev2)) {
- error << "Failed write " << i << ".2" << endl;
- return 1;
- }
+ for (int i = 0; i < MSG_SIZE; ++i) {
+ msg[i] = start;
+ start = (start + 1) % INT_MAX;
+ }
+ return start;
+}
- char ev3[] = { 'g', 'h' };
- if (!rb.write(2, ev3)) {
- error << "Failed write " << i << ".3" << endl;
- return 1;
- }
+static int
+cmp_msg(int* msg1, int* msg2)
+{
+ for (int i = 0; i < MSG_SIZE; ++i) {
+ if (msg1[i] != msg2[i]) {
+ fprintf(stderr, "ERROR: %d != %d @ %d\n", msg1[i], msg2[i], i);
+ return 0;
+ }
+ }
- if (rb.skip(1) != 1) {
- error << "Failed skip " << i << endl;
- return 1;
- }
+ return 1;
+}
- uint32_t n_read = rb.read(2, buf);
- if (n_read != 2 || strncmp(buf, "ef", 2)) {
- error << "Corrupt event " << i << ".4: "
- << buf[0] << buf[1] << buf[2] << endl;
- return 1;
- }
+static void*
+reader(void* arg)
+{
+ printf("Reader starting\n");
- n_read = rb.peek(2, buf);
- if (n_read != 2 || strncmp(buf, "gh", 2)) {
- error << "Corrupt peek event " << i << ".5: "
- << buf[0] << buf[1] << endl;
- return 1;
+ int ref_msg[MSG_SIZE]; // Reference generated for comparison
+ int read_msg[MSG_SIZE]; // Read from ring
+ size_t count = 0;
+ int start = gen_msg(ref_msg, 0);
+ for (size_t i = 0; i < n_writes; ++i) {
+ if (ring->read_space() >= MSG_SIZE * sizeof(int)) {
+ const uint32_t n_read = ring->read(MSG_SIZE * sizeof(int), read_msg);
+ if (n_read != MSG_SIZE * sizeof(int)) {
+ fprintf(stderr, "FAIL: Read size incorrect\n");
+ ring_error = true;
+ return NULL;
+ }
+ if (!cmp_msg(ref_msg, read_msg)) {
+ fprintf(stderr, "FAIL: Message %zu is corrupt\n", count);
+ ring_error = true;
+ return NULL;
}
+ start = gen_msg(ref_msg, start);
+ ++count;
+ }
+ }
+
+ printf("Reader finished\n");
+ return NULL;
+}
+
+static void*
+writer(void* arg)
+{
+ printf("Writer starting\n");
- n_read = rb.read(2, buf);
- if (n_read != 2 || strncmp(buf, "gh", 2)) {
- error << "Corrupt event " << i << ".6: "
- << buf[0] << buf[1] << endl;
- return 1;
+ int write_msg[MSG_SIZE]; // Written to ring
+ int start = gen_msg(write_msg, 0);
+ for (size_t i = 0; i < n_writes; ++i) {
+ if (ring->write_space() >= MSG_SIZE * sizeof(int)) {
+ const uint32_t n_write = ring->write(MSG_SIZE * sizeof(int), write_msg);
+ if (n_write != MSG_SIZE * sizeof(int)) {
+ fprintf(stderr, "FAIL: Write size incorrect\n");
+ ring_error = true;
+ return NULL;
}
+ start = gen_msg(write_msg, start);
}
}
- info << "Successfully ran " << n_tests << " tests." << endl;
- return 0;
+ printf("Writer finished\n");
+ return NULL;
}
+int
+main(int argc, char** argv)
+{
+ if (argc > 1 && argv[1][0] == '-') {
+ printf("Usage: %s SIZE N_WRITES\n", argv[0]);
+ return 1;
+ }
+
+ int size = 1024;
+ if (argc > 1) {
+ size = atoi(argv[1]);
+ }
+
+ n_writes = size * 1024;
+ if (argc > 2) {
+ n_writes = atoi(argv[2]);
+ }
+
+ printf("Testing %zu writes of %d ints to a %d int ring...\n",
+ n_writes, MSG_SIZE, size);
+
+ ring = new Raul::RingBuffer(size);
+
+ pthread_t reader_thread;
+ if (pthread_create(&reader_thread, NULL, reader, NULL)) {
+ fprintf(stderr, "Failed to create reader thread\n");
+ return 1;
+ }
+
+ pthread_t writer_thread;
+ if (pthread_create(&writer_thread, NULL, writer, NULL)) {
+ fprintf(stderr, "Failed to create writer thread\n");
+ return 1;
+ }
+
+ pthread_join(reader_thread, NULL);
+ pthread_join(writer_thread, NULL);
+
+ if (ring_error) {
+ fprintf(stderr, "FAIL: Error occurred\n");
+ return 1;
+ }
+
+ delete ring;
+ return 0;
+}