server: Use ringbuffer for socket backlog

Currently, the socket handler uses a linear buffer for the backlog data;
this means we need to shift up to 128kB of data after each socket
write().

This change introduces a single-producer-multiple-consumer ringbuffer,
to avoid the need for memmove()ing data around; we can simply update
pointers instead of shifting data.

We add this as a new file (ringbuffer.c), to make it a little more
modular. To mitigate the risk of subtle pointer arithmetic issues, we
add a set of tests too.

Change-Id: Ib7c5151d3cf1f588436f5461000b6fed22d0681c
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
diff --git a/test/test-ringbuffer-boundary-read.c b/test/test-ringbuffer-boundary-read.c
new file mode 100644
index 0000000..2b982e1
--- /dev/null
+++ b/test/test-ringbuffer-boundary-read.c
@@ -0,0 +1,51 @@
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include "ringbuffer.c"
+#include "ringbuffer-test-utils.c"
+
+void test_boundary_read(void)
+{
+	uint8_t *out_buf, in_buf[] = { 'a', 'b', 'c', 'd', 'e', 'f' };
+	struct ringbuffer_consumer *rbc;
+	struct ringbuffer *rb;
+	size_t len, pos;
+	int rc;
+
+	assert(sizeof(in_buf) * 2 > 10);
+
+	rb = ringbuffer_init(10);
+	rbc = ringbuffer_consumer_register(rb, ringbuffer_poll_nop, NULL);
+
+	/* queue and dequeue, so our tail is non-zero */
+	ringbuffer_queue(rb, in_buf, sizeof(in_buf));
+	ringbuffer_dequeue_commit(rbc, sizeof(in_buf));
+
+	/* ensure we're getting the second batch of data back */
+	in_buf[0] = 'A';
+
+	/* the next queue should cross the end of the buffer */
+	rc = ringbuffer_queue(rb, in_buf, sizeof(in_buf));
+	assert(!rc);
+
+	/* dequeue everything we can */
+	pos = 0;
+	for (;;) {
+		len = ringbuffer_dequeue_peek(rbc, pos, &out_buf);
+		if (len == 0)
+			break;
+		assert(!memcmp(in_buf+pos, out_buf, len));
+		pos += len;
+	}
+	assert(pos == sizeof(in_buf));
+
+	ringbuffer_fini(rb);
+}
+
+int main(void)
+{
+	test_boundary_read();
+	return EXIT_SUCCESS;
+}