allow the typed ring header file to be included multiple times inside a
C file so that we can have multiple different ring types in use. This
is tested by having a second ring type in the unit tests, which works
with small (16 byte) structures, rather than just pointers.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
app/test/test_typed_ring.c | 60 +++++++++++++++-
lib/librte_ring/rte_typed_ring.h | 144 ++++++++++++++++++++-------------------
2 files changed, 132 insertions(+), 72 deletions(-)
@@ -37,6 +37,19 @@
#define RING_TYPE struct rte_mbuf *
#define RING_TYPE_NAME rte_mbuf
#include <rte_typed_ring.h>
+#undef RING_TYPE_NAME
+#undef RING_TYPE
+
+struct xyval {
+ uint64_t x;
+ void *y;
+};
+
+#define RING_TYPE struct xyval /* structure not pointer */
+#define RING_TYPE_NAME rte_xyval
+#include <rte_typed_ring.h>
+#undef RING_TYPE_NAME
+#undef RING_TYPE
#define RING_SIZE 256
#define BURST_SZ 32
@@ -73,6 +86,38 @@ test_mbuf_enqueue_dequeue(struct rte_mbuf_ring *r)
return 0;
}
+static int
+test_xyval_enqueue_dequeue(struct rte_xyval_ring *r)
+{
+ struct xyval inbufs[BURST_SZ];
+ struct xyval outbufs[BURST_SZ];
+ unsigned int i, j;
+
+ for (i = 0; i < BURST_SZ; i++)
+ inbufs[i].x = rte_rand();
+
+ for (i = 0; i < ITERATIONS; i++) {
+ uint16_t in = rte_xyval_ring_enqueue_burst(r, inbufs, BURST_SZ);
+ if (in != BURST_SZ) {
+ printf("Error enqueuing xyvals\n");
+ return -1;
+ }
+ uint16_t out = rte_xyval_ring_dequeue_burst(r, outbufs, BURST_SZ);
+ if (out != BURST_SZ) {
+ printf("Error dequeuing xyvals\n");
+ return -1;
+ }
+
+ for (j = 0; j < BURST_SZ; j++)
+ if (outbufs[j].x != inbufs[j].x ||
+ outbufs[j].y != inbufs[j].y) {
+ printf("Error: dequeued val != enqueued val\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
/**
* test entry point
*/
@@ -87,13 +132,24 @@ test_typed_ring(void)
return -1;
}
rte_mbuf_ring_list_dump(stdout);
-
+ printf("mbuf ring has memory size %u\n",
+ (unsigned int)rte_mbuf_ring_get_memsize(RING_SIZE));
if (test_mbuf_enqueue_dequeue(r) != 0) {
rte_mbuf_ring_free(r);
return -1;
}
-
rte_mbuf_ring_free(r);
+
+ struct rte_xyval_ring *r2;
+ r2 = rte_xyval_ring_create("xyval_ring", RING_SIZE, rte_socket_id(),
+ RING_F_SP_ENQ | RING_F_SC_DEQ);
+ if (test_xyval_enqueue_dequeue(r2) != 0) {
+ rte_xyval_ring_free(r2);
+ return -1;
+ }
+ printf("xyval ring has memory size %u\n",
+ (unsigned int)rte_xyval_ring_get_memsize(RING_SIZE));
+ rte_xyval_ring_free(r2);
return 0;
}
@@ -114,14 +114,6 @@ extern "C" {
#define _CAT(a, b) a ## _ ## b
#define CAT(a, b) _CAT(a, b)
-#ifndef RING_TYPE_NAME
-#error "Need RING_TYPE_NAME defined before including"
-#endif
-#ifndef RING_TYPE
-#error "Need RING_TYPE defined before including"
-#endif
-#define TYPE(x) CAT(RING_TYPE_NAME, x)
-
#define RTE_TAILQ_RING_NAME "RTE_RING"
enum rte_ring_queue_behavior {
@@ -160,63 +152,7 @@ struct rte_ring_debug_stats {
#define RTE_RING_PAUSE_REP_COUNT 0
#endif
-struct rte_memzone; /* forward declaration, so as not to require memzone.h */
-
-/**
- * An RTE ring structure.
- *
- * The producer and the consumer have a head and a tail index. The particularity
- * of these index is that they are not between 0 and size(ring). These indexes
- * are between 0 and 2^32, and we mask their value when we access the ring[]
- * field. Thanks to this assumption, we can do subtractions between 2 index
- * values in a modulo-32bit base: that's why the overflow of the indexes is not
- * a problem.
- */
-struct TYPE(ring) {
- /*
- * Note: this field kept the RTE_MEMZONE_NAMESIZE size due to ABI
- * compatibility requirements, it could be changed to RTE_RING_NAMESIZE
- * next time the ABI changes
- */
- char name[RTE_MEMZONE_NAMESIZE]; /**< Name of the ring. */
- int flags; /**< Flags supplied at creation. */
- const struct rte_memzone *memzone;
- /**< Memzone, if any, containing the ring */
-
- /** Ring producer status. */
- struct prod {
- uint32_t watermark; /**< Maximum items before EDQUOT. */
- uint32_t sp_enqueue; /**< True, if single producer. */
- uint32_t size; /**< Size of ring. */
- uint32_t mask; /**< Mask (size-1) of ring. */
- volatile uint32_t head; /**< Producer head. */
- volatile uint32_t tail; /**< Producer tail. */
- } prod __rte_cache_aligned;
-
- /** Ring consumer status. */
- struct cons {
- uint32_t sc_dequeue; /**< True, if single consumer. */
- uint32_t size; /**< Size of the ring. */
- uint32_t mask; /**< Mask (size-1) of ring. */
- volatile uint32_t head; /**< Consumer head. */
- volatile uint32_t tail; /**< Consumer tail. */
-#ifdef RTE_RING_SPLIT_PROD_CONS
- } cons __rte_cache_aligned;
-#else
- } cons;
-#endif
-
-#ifdef RTE_LIBRTE_RING_DEBUG
- struct rte_ring_debug_stats stats[RTE_MAX_LCORE];
-#endif
-
- /**
- * Memory space of ring starts here.
- * not volatile so need to be careful
- * about compiler re-ordering
- */
- RING_TYPE ring[] __rte_cache_aligned;
-};
+TAILQ_HEAD(rte_ring_list, rte_tailq_entry);
#define RING_F_SP_ENQ 0x0001 /**< The default enqueue is "single-producer". */
#define RING_F_SC_DEQ 0x0002 /**< The default dequeue is "single-consumer". */
@@ -304,6 +240,77 @@ struct TYPE(ring) {
} \
} while (0)
+extern struct rte_tailq_elem rte_ring_tailq;
+
+#endif /* _RTE_RING_H_ */
+
+#ifndef RING_TYPE_NAME
+#error "Need RING_TYPE_NAME defined before including"
+#endif
+#ifndef RING_TYPE
+#error "Need RING_TYPE defined before including"
+#endif
+#define TYPE(x) CAT(RING_TYPE_NAME, x)
+
+struct rte_memzone; /* forward declaration, so as not to require memzone.h */
+
+/**
+ * An RTE ring structure.
+ *
+ * The producer and the consumer have a head and a tail index. The particularity
+ * of these index is that they are not between 0 and size(ring). These indexes
+ * are between 0 and 2^32, and we mask their value when we access the ring[]
+ * field. Thanks to this assumption, we can do subtractions between 2 index
+ * values in a modulo-32bit base: that's why the overflow of the indexes is not
+ * a problem.
+ */
+struct TYPE(ring) {
+ /*
+ * Note: this field kept the RTE_MEMZONE_NAMESIZE size due to ABI
+ * compatibility requirements, it could be changed to RTE_RING_NAMESIZE
+ * next time the ABI changes
+ */
+ char name[RTE_MEMZONE_NAMESIZE]; /**< Name of the ring. */
+ int flags; /**< Flags supplied at creation. */
+ const struct rte_memzone *memzone;
+ /**< Memzone, if any, containing the ring */
+
+ /** Ring producer status. */
+ struct {
+ uint32_t watermark; /**< Maximum items before EDQUOT. */
+ uint32_t sp_enqueue; /**< True, if single producer. */
+ uint32_t size; /**< Size of ring. */
+ uint32_t mask; /**< Mask (size-1) of ring. */
+ volatile uint32_t head; /**< Producer head. */
+ volatile uint32_t tail; /**< Producer tail. */
+ } prod __rte_cache_aligned;
+
+ /** Ring consumer status. */
+ struct {
+ uint32_t sc_dequeue; /**< True, if single consumer. */
+ uint32_t size; /**< Size of the ring. */
+ uint32_t mask; /**< Mask (size-1) of ring. */
+ volatile uint32_t head; /**< Consumer head. */
+ volatile uint32_t tail; /**< Consumer tail. */
+#ifdef RTE_RING_SPLIT_PROD_CONS
+ } cons __rte_cache_aligned;
+#else
+ } cons;
+#endif
+
+#ifdef RTE_LIBRTE_RING_DEBUG
+ struct rte_ring_debug_stats stats[RTE_MAX_LCORE];
+#endif
+
+ /**
+ * Memory space of ring starts here.
+ * not volatile so need to be careful
+ * about compiler re-ordering
+ */
+ RING_TYPE ring[] __rte_cache_aligned;
+};
+
+
/**
* @internal Enqueue several objects on the ring (multi-producers safe).
*
@@ -1146,10 +1153,6 @@ TYPE(ring_dequeue_burst)(struct TYPE(ring) *r, RING_TYPE *obj_table, unsigned in
return TYPE(ring_mc_dequeue_burst)(r, obj_table, n);
}
-TAILQ_HEAD(rte_ring_list, rte_tailq_entry);
-
-extern struct rte_tailq_elem rte_ring_tailq;
-
/**
* Calculate the memory size needed for a ring
*
@@ -1559,8 +1562,9 @@ TYPE(ring_lookup)(const char *name)
return r;
}
+#undef TYPE
+
#ifdef __cplusplus
}
#endif
-#endif /* _RTE_RING_H_ */