Mesa (master): util: add generic ringbuffer utitilty
Keith Whitwell
keithw at kemper.freedesktop.org
Sat Jan 16 21:16:12 UTC 2010
Module: Mesa
Branch: master
Commit: 164fd16cfbc09970676c2e6866e062a5c9b410db
URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=164fd16cfbc09970676c2e6866e062a5c9b410db
Author: Keith Whitwell <keithw at vmware.com>
Date: Sat Jan 16 21:11:01 2010 +0000
util: add generic ringbuffer utitilty
---
src/gallium/auxiliary/Makefile | 1 +
src/gallium/auxiliary/SConscript | 1 +
src/gallium/auxiliary/util/u_ringbuffer.c | 145 +++++++++++++++++++++++++++++
src/gallium/auxiliary/util/u_ringbuffer.h | 29 ++++++
4 files changed, 176 insertions(+), 0 deletions(-)
diff --git a/src/gallium/auxiliary/Makefile b/src/gallium/auxiliary/Makefile
index e3af41c..8f937e3 100644
--- a/src/gallium/auxiliary/Makefile
+++ b/src/gallium/auxiliary/Makefile
@@ -111,6 +111,7 @@ C_SOURCES = \
util/u_math.c \
util/u_mm.c \
util/u_rect.c \
+ util/u_ringbuffer.c \
util/u_simple_shaders.c \
util/u_snprintf.c \
util/u_stream_stdc.c \
diff --git a/src/gallium/auxiliary/SConscript b/src/gallium/auxiliary/SConscript
index 782eb53..f957090 100644
--- a/src/gallium/auxiliary/SConscript
+++ b/src/gallium/auxiliary/SConscript
@@ -147,6 +147,7 @@ source = [
'util/u_math.c',
'util/u_mm.c',
'util/u_rect.c',
+ 'util/u_ringbuffer.c',
'util/u_simple_shaders.c',
'util/u_snprintf.c',
'util/u_stream_stdc.c',
diff --git a/src/gallium/auxiliary/util/u_ringbuffer.c b/src/gallium/auxiliary/util/u_ringbuffer.c
new file mode 100644
index 0000000..3f43a19
--- /dev/null
+++ b/src/gallium/auxiliary/util/u_ringbuffer.c
@@ -0,0 +1,145 @@
+
+#include "pipe/p_thread.h"
+#include "pipe/p_defines.h"
+#include "util/u_ringbuffer.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+
+/* Generic ringbuffer:
+ */
+struct util_ringbuffer
+{
+ struct util_packet *buf;
+ unsigned mask;
+
+ /* Can this be done with atomic variables??
+ */
+ unsigned head;
+ unsigned tail;
+ pipe_condvar change;
+ pipe_mutex mutex;
+};
+
+
+struct util_ringbuffer *util_ringbuffer_create( unsigned dwords )
+{
+ struct util_ringbuffer *ring = CALLOC_STRUCT(util_ringbuffer);
+ if (ring == NULL)
+ return NULL;
+
+ assert(util_is_power_of_two(dwords));
+
+ ring->buf = MALLOC( dwords * sizeof(unsigned) );
+ if (ring->buf == NULL)
+ goto fail;
+
+ ring->mask = dwords - 1;
+
+ pipe_condvar_init(ring->change);
+ pipe_mutex_init(ring->mutex);
+ return ring;
+
+fail:
+ FREE(ring->buf);
+ FREE(ring);
+ return NULL;
+}
+
+void util_ringbuffer_destroy( struct util_ringbuffer *ring )
+{
+ pipe_condvar_destroy(ring->change);
+ pipe_mutex_destroy(ring->mutex);
+ FREE(ring->buf);
+ FREE(ring);
+}
+
+static INLINE unsigned util_ringbuffer_space( const struct util_ringbuffer *ring )
+{
+ return (ring->tail - (ring->head + 1)) & ring->mask;
+}
+
+void util_ringbuffer_enqueue( struct util_ringbuffer *ring,
+ const struct util_packet *packet )
+{
+ unsigned i;
+
+ /* XXX: over-reliance on mutexes, etc:
+ */
+ pipe_mutex_lock(ring->mutex);
+
+ /* Wait for free space:
+ */
+ while (util_ringbuffer_space(ring) < packet->dwords)
+ pipe_condvar_wait(ring->change, ring->mutex);
+
+ /* Copy data to ring:
+ */
+ for (i = 0; i < packet->dwords; i++) {
+
+ /* Copy all dwords of the packet. Note we're abusing the
+ * typesystem a little - we're being passed a pointer to
+ * something, but probably not an array of packet structs:
+ */
+ ring->buf[ring->head] = packet[i];
+ ring->head++;
+ ring->head &= ring->mask;
+ }
+
+ /* Signal change:
+ */
+ pipe_condvar_signal(ring->change);
+ pipe_mutex_unlock(ring->mutex);
+}
+
+enum pipe_error util_ringbuffer_dequeue( struct util_ringbuffer *ring,
+ struct util_packet *packet,
+ unsigned max_dwords,
+ boolean wait )
+{
+ const struct util_packet *ring_packet;
+ unsigned i;
+ int ret = PIPE_OK;
+
+ /* XXX: over-reliance on mutexes, etc:
+ */
+ pipe_mutex_lock(ring->mutex);
+
+ /* Wait for free space:
+ */
+ if (wait) {
+ while (util_ringbuffer_space(ring) == 0)
+ pipe_condvar_wait(ring->change, ring->mutex);
+ }
+ else {
+ if (util_ringbuffer_space(ring) == 0) {
+ ret = PIPE_ERROR_OUT_OF_MEMORY;
+ goto out;
+ }
+ }
+
+ ring_packet = &ring->buf[ring->tail];
+
+ /* Both of these are considered bugs. Raise an assert on debug builds.
+ */
+ if (ring_packet->dwords > ring->mask + 1 - util_ringbuffer_space(ring) ||
+ ring_packet->dwords > max_dwords) {
+ assert(0);
+ ret = PIPE_ERROR_BAD_INPUT;
+ goto out;
+ }
+
+ /* Copy data from ring:
+ */
+ for (i = 0; i < ring_packet->dwords; i++) {
+ packet[i] = ring->buf[ring->tail];
+ ring->tail++;
+ ring->tail &= ring->mask;
+ }
+
+out:
+ /* Signal change:
+ */
+ pipe_condvar_signal(ring->change);
+ pipe_mutex_unlock(ring->mutex);
+ return ret;
+}
diff --git a/src/gallium/auxiliary/util/u_ringbuffer.h b/src/gallium/auxiliary/util/u_ringbuffer.h
new file mode 100644
index 0000000..85f0ad6
--- /dev/null
+++ b/src/gallium/auxiliary/util/u_ringbuffer.h
@@ -0,0 +1,29 @@
+
+#ifndef UTIL_RINGBUFFER_H
+#define UTIL_RINGBUFFER_H
+
+#include "pipe/p_compiler.h"
+#include "pipe/p_defines.h" /* only for pipe_error! */
+
+/* Generic header
+ */
+struct util_packet {
+ unsigned dwords:8;
+ unsigned data24:24;
+};
+
+struct util_ringbuffer;
+
+struct util_ringbuffer *util_ringbuffer_create( unsigned dwords );
+
+void util_ringbuffer_destroy( struct util_ringbuffer *ring );
+
+void util_ringbuffer_enqueue( struct util_ringbuffer *ring,
+ const struct util_packet *packet );
+
+enum pipe_error util_ringbuffer_dequeue( struct util_ringbuffer *ring,
+ struct util_packet *packet,
+ unsigned max_dwords,
+ boolean wait );
+
+#endif
More information about the mesa-commit
mailing list