X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=lib%2Flibrte_ring%2Frte_ring.h;h=7181c33b40181e9209a0949d440788bbecc805dd;hb=2f86fb666eb0dc15f9f8715ea12c6a5b687ed883;hp=de1a5f366b2571f15cc573b78d75a265581eb950;hpb=ea771bc2a96dd67102656ad81c68edeed5974179;p=dpdk.git diff --git a/lib/librte_ring/rte_ring.h b/lib/librte_ring/rte_ring.h index de1a5f366b..7181c33b40 100644 --- a/lib/librte_ring/rte_ring.h +++ b/lib/librte_ring/rte_ring.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: BSD-3-Clause * - * Copyright (c) 2010-2017 Intel Corporation + * Copyright (c) 2010-2020 Intel Corporation * Copyright (c) 2007-2009 Kip Macy kmacy@freebsd.org * All rights reserved. * Derived from FreeBSD's bufring.h @@ -25,9 +25,13 @@ * - Multi- or single-producer enqueue. * - Bulk dequeue. * - Bulk enqueue. + * - Ability to select different sync modes for producer/consumer. + * - Dequeue start/finish (depending on consumer sync modes). + * - Enqueue start/finish (depending on producer sync mode). * - * Note: the ring implementation is not preemptable. A lcore must not - * be interrupted by another task that uses the same ring. + * Note: the ring implementation is not preemptible. Refer to Programmer's + * guide/Environment Abstraction Layer/Multiple pthread/Known Issues/rte_ring + * for more information. * */ @@ -35,93 +39,7 @@ extern "C" { #endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define RTE_TAILQ_RING_NAME "RTE_RING" - -enum rte_ring_queue_behavior { - RTE_RING_QUEUE_FIXED = 0, /* Enq/Deq a fixed number of items from a ring */ - RTE_RING_QUEUE_VARIABLE /* Enq/Deq as many items as possible from ring */ -}; - -#define RTE_RING_MZ_PREFIX "RG_" -/**< The maximum length of a ring name. */ -#define RTE_RING_NAMESIZE (RTE_MEMZONE_NAMESIZE - \ - sizeof(RTE_RING_MZ_PREFIX) + 1) - -struct rte_memzone; /* forward declaration, so as not to require memzone.h */ - -/* structure to hold a pair of head/tail values and other metadata */ -struct rte_ring_headtail { - volatile uint32_t head; /**< Prod/consumer head. */ - volatile uint32_t tail; /**< Prod/consumer tail. */ - uint32_t single; /**< True if single prod/cons */ -}; - -/** - * 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 rte_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] __rte_cache_aligned; /**< Name of the ring. */ - int flags; /**< Flags supplied at creation. */ - const struct rte_memzone *memzone; - /**< Memzone, if any, containing the rte_ring */ - uint32_t size; /**< Size of ring. */ - uint32_t mask; /**< Mask (size-1) of ring. */ - uint32_t capacity; /**< Usable size of ring */ - - char pad0 __rte_cache_aligned; /**< empty cache line */ - - /** Ring producer status. */ - struct rte_ring_headtail prod __rte_cache_aligned; - char pad1 __rte_cache_aligned; /**< empty cache line */ - - /** Ring consumer status. */ - struct rte_ring_headtail cons __rte_cache_aligned; - char pad2 __rte_cache_aligned; /**< empty cache line */ -}; - -#define RING_F_SP_ENQ 0x0001 /**< The default enqueue is "single-producer". */ -#define RING_F_SC_DEQ 0x0002 /**< The default dequeue is "single-consumer". */ -/** - * Ring is to hold exactly requested number of entries. - * Without this flag set, the ring size requested must be a power of 2, and the - * usable space will be that size - 1. With the flag, the requested size will - * be rounded up to the next power of two, but the usable space will be exactly - * that requested. Worst case, if a power-of-2 size is requested, half the - * ring space will be wasted. - */ -#define RING_F_EXACT_SZ 0x0004 -#define RTE_RING_SZ_MASK (0x7fffffffU) /**< Ring size mask */ - -/* @internal defines for passing to the enqueue dequeue worker functions */ -#define __IS_SP 1 -#define __IS_MP 0 -#define __IS_SC 1 -#define __IS_MC 0 +#include /** * Calculate the memory size needed for a ring @@ -137,7 +55,7 @@ struct rte_ring { * - The memory size needed for the ring on success. * - -EINVAL if count is not a power of 2. */ -ssize_t rte_ring_get_memsize(unsigned count); +ssize_t rte_ring_get_memsize(unsigned int count); /** * Initialize a ring structure. @@ -164,17 +82,35 @@ ssize_t rte_ring_get_memsize(unsigned count); * The number of elements in the ring (must be a power of 2). * @param flags * An OR of the following: - * - RING_F_SP_ENQ: If this flag is set, the default behavior when - * using ``rte_ring_enqueue()`` or ``rte_ring_enqueue_bulk()`` - * is "single-producer". Otherwise, it is "multi-producers". - * - RING_F_SC_DEQ: If this flag is set, the default behavior when - * using ``rte_ring_dequeue()`` or ``rte_ring_dequeue_bulk()`` - * is "single-consumer". Otherwise, it is "multi-consumers". + * - One of mutually exclusive flags that define producer behavior: + * - RING_F_SP_ENQ: If this flag is set, the default behavior when + * using ``rte_ring_enqueue()`` or ``rte_ring_enqueue_bulk()`` + * is "single-producer". + * - RING_F_MP_RTS_ENQ: If this flag is set, the default behavior when + * using ``rte_ring_enqueue()`` or ``rte_ring_enqueue_bulk()`` + * is "multi-producer RTS mode". + * - RING_F_MP_HTS_ENQ: If this flag is set, the default behavior when + * using ``rte_ring_enqueue()`` or ``rte_ring_enqueue_bulk()`` + * is "multi-producer HTS mode". + * If none of these flags is set, then default "multi-producer" + * behavior is selected. + * - One of mutually exclusive flags that define consumer behavior: + * - RING_F_SC_DEQ: If this flag is set, the default behavior when + * using ``rte_ring_dequeue()`` or ``rte_ring_dequeue_bulk()`` + * is "single-consumer". Otherwise, it is "multi-consumers". + * - RING_F_MC_RTS_DEQ: If this flag is set, the default behavior when + * using ``rte_ring_dequeue()`` or ``rte_ring_dequeue_bulk()`` + * is "multi-consumer RTS mode". + * - RING_F_MC_HTS_DEQ: If this flag is set, the default behavior when + * using ``rte_ring_dequeue()`` or ``rte_ring_dequeue_bulk()`` + * is "multi-consumer HTS mode". + * If none of these flags is set, then default "multi-consumer" + * behavior is selected. * @return * 0 on success, or a negative value on error. */ -int rte_ring_init(struct rte_ring *r, const char *name, unsigned count, - unsigned flags); +int rte_ring_init(struct rte_ring *r, const char *name, unsigned int count, + unsigned int flags); /** * Create a new ring named *name* in memory. @@ -199,12 +135,30 @@ int rte_ring_init(struct rte_ring *r, const char *name, unsigned count, * constraint for the reserved zone. * @param flags * An OR of the following: - * - RING_F_SP_ENQ: If this flag is set, the default behavior when - * using ``rte_ring_enqueue()`` or ``rte_ring_enqueue_bulk()`` - * is "single-producer". Otherwise, it is "multi-producers". - * - RING_F_SC_DEQ: If this flag is set, the default behavior when - * using ``rte_ring_dequeue()`` or ``rte_ring_dequeue_bulk()`` - * is "single-consumer". Otherwise, it is "multi-consumers". + * - One of mutually exclusive flags that define producer behavior: + * - RING_F_SP_ENQ: If this flag is set, the default behavior when + * using ``rte_ring_enqueue()`` or ``rte_ring_enqueue_bulk()`` + * is "single-producer". + * - RING_F_MP_RTS_ENQ: If this flag is set, the default behavior when + * using ``rte_ring_enqueue()`` or ``rte_ring_enqueue_bulk()`` + * is "multi-producer RTS mode". + * - RING_F_MP_HTS_ENQ: If this flag is set, the default behavior when + * using ``rte_ring_enqueue()`` or ``rte_ring_enqueue_bulk()`` + * is "multi-producer HTS mode". + * If none of these flags is set, then default "multi-producer" + * behavior is selected. + * - One of mutually exclusive flags that define consumer behavior: + * - RING_F_SC_DEQ: If this flag is set, the default behavior when + * using ``rte_ring_dequeue()`` or ``rte_ring_dequeue_bulk()`` + * is "single-consumer". Otherwise, it is "multi-consumers". + * - RING_F_MC_RTS_DEQ: If this flag is set, the default behavior when + * using ``rte_ring_dequeue()`` or ``rte_ring_dequeue_bulk()`` + * is "multi-consumer RTS mode". + * - RING_F_MC_HTS_DEQ: If this flag is set, the default behavior when + * using ``rte_ring_dequeue()`` or ``rte_ring_dequeue_bulk()`` + * is "multi-consumer HTS mode". + * If none of these flags is set, then default "multi-consumer" + * behavior is selected. * @return * On success, the pointer to the new allocated ring. NULL on error with * rte_errno set appropriately. Possible errno values include: @@ -215,8 +169,9 @@ int rte_ring_init(struct rte_ring *r, const char *name, unsigned count, * - EEXIST - a memzone with the same name already exists * - ENOMEM - no appropriate memory area found in which to create memzone */ -struct rte_ring *rte_ring_create(const char *name, unsigned count, - int socket_id, unsigned flags); +struct rte_ring *rte_ring_create(const char *name, unsigned int count, + int socket_id, unsigned int flags); + /** * De-allocate all memory used by the ring. * @@ -244,11 +199,11 @@ void rte_ring_dump(FILE *f, const struct rte_ring *r); uint32_t idx = prod_head & (r)->mask; \ obj_type *ring = (obj_type *)ring_start; \ if (likely(idx + n < size)) { \ - for (i = 0; i < (n & ((~(unsigned)0x3))); i+=4, idx+=4) { \ + for (i = 0; i < (n & ~0x3); i += 4, idx += 4) { \ ring[idx] = obj_table[i]; \ - ring[idx+1] = obj_table[i+1]; \ - ring[idx+2] = obj_table[i+2]; \ - ring[idx+3] = obj_table[i+3]; \ + ring[idx + 1] = obj_table[i + 1]; \ + ring[idx + 2] = obj_table[i + 2]; \ + ring[idx + 3] = obj_table[i + 3]; \ } \ switch (n & 0x3) { \ case 3: \ @@ -275,11 +230,11 @@ void rte_ring_dump(FILE *f, const struct rte_ring *r); const uint32_t size = (r)->size; \ obj_type *ring = (obj_type *)ring_start; \ if (likely(idx + n < size)) { \ - for (i = 0; i < (n & (~(unsigned)0x3)); i+=4, idx+=4) {\ + for (i = 0; i < (n & ~0x3); i += 4, idx += 4) {\ obj_table[i] = ring[idx]; \ - obj_table[i+1] = ring[idx+1]; \ - obj_table[i+2] = ring[idx+2]; \ - obj_table[i+3] = ring[idx+3]; \ + obj_table[i + 1] = ring[idx + 1]; \ + obj_table[i + 2] = ring[idx + 2]; \ + obj_table[i + 3] = ring[idx + 3]; \ } \ switch (n & 0x3) { \ case 3: \ @@ -301,12 +256,12 @@ void rte_ring_dump(FILE *f, const struct rte_ring *r); * (powerpc/arm). * There are 2 choices for the users * 1.use rmb() memory barrier - * 2.use one-direcion load_acquire/store_release barrier,defined by - * CONFIG_RTE_RING_USE_C11_MEM_MODEL=y + * 2.use one-direction load_acquire/store_release barrier,defined by + * CONFIG_RTE_USE_C11_MEM_MODEL=y * It depends on performance test results. * By default, move common functions to rte_ring_generic.h */ -#ifdef RTE_RING_USE_C11_MEM_MODEL +#ifdef RTE_USE_C11_MEM_MODEL #include "rte_ring_c11_mem.h" #else #include "rte_ring_generic.h" @@ -420,7 +375,7 @@ rte_ring_mp_enqueue_bulk(struct rte_ring *r, void * const *obj_table, unsigned int n, unsigned int *free_space) { return __rte_ring_do_enqueue(r, obj_table, n, RTE_RING_QUEUE_FIXED, - __IS_MP, free_space); + RTE_RING_SYNC_MT, free_space); } /** @@ -443,9 +398,13 @@ rte_ring_sp_enqueue_bulk(struct rte_ring *r, void * const *obj_table, unsigned int n, unsigned int *free_space) { return __rte_ring_do_enqueue(r, obj_table, n, RTE_RING_QUEUE_FIXED, - __IS_SP, free_space); + RTE_RING_SYNC_ST, free_space); } +#ifdef ALLOW_EXPERIMENTAL_API +#include +#endif + /** * Enqueue several objects on a ring. * @@ -469,8 +428,24 @@ static __rte_always_inline unsigned int rte_ring_enqueue_bulk(struct rte_ring *r, void * const *obj_table, unsigned int n, unsigned int *free_space) { - return __rte_ring_do_enqueue(r, obj_table, n, RTE_RING_QUEUE_FIXED, - r->prod.single, free_space); + switch (r->prod.sync_type) { + case RTE_RING_SYNC_MT: + return rte_ring_mp_enqueue_bulk(r, obj_table, n, free_space); + case RTE_RING_SYNC_ST: + return rte_ring_sp_enqueue_bulk(r, obj_table, n, free_space); +#ifdef ALLOW_EXPERIMENTAL_API + case RTE_RING_SYNC_MT_RTS: + return rte_ring_mp_rts_enqueue_bulk(r, obj_table, n, + free_space); + case RTE_RING_SYNC_MT_HTS: + return rte_ring_mp_hts_enqueue_bulk(r, obj_table, n, + free_space); +#endif + } + + /* valid ring should never reach this point */ + RTE_ASSERT(0); + return 0; } /** @@ -554,7 +529,7 @@ rte_ring_mc_dequeue_bulk(struct rte_ring *r, void **obj_table, unsigned int n, unsigned int *available) { return __rte_ring_do_dequeue(r, obj_table, n, RTE_RING_QUEUE_FIXED, - __IS_MC, available); + RTE_RING_SYNC_MT, available); } /** @@ -578,7 +553,7 @@ rte_ring_sc_dequeue_bulk(struct rte_ring *r, void **obj_table, unsigned int n, unsigned int *available) { return __rte_ring_do_dequeue(r, obj_table, n, RTE_RING_QUEUE_FIXED, - __IS_SC, available); + RTE_RING_SYNC_ST, available); } /** @@ -604,8 +579,22 @@ static __rte_always_inline unsigned int rte_ring_dequeue_bulk(struct rte_ring *r, void **obj_table, unsigned int n, unsigned int *available) { - return __rte_ring_do_dequeue(r, obj_table, n, RTE_RING_QUEUE_FIXED, - r->cons.single, available); + switch (r->cons.sync_type) { + case RTE_RING_SYNC_MT: + return rte_ring_mc_dequeue_bulk(r, obj_table, n, available); + case RTE_RING_SYNC_ST: + return rte_ring_sc_dequeue_bulk(r, obj_table, n, available); +#ifdef ALLOW_EXPERIMENTAL_API + case RTE_RING_SYNC_MT_RTS: + return rte_ring_mc_rts_dequeue_bulk(r, obj_table, n, available); + case RTE_RING_SYNC_MT_HTS: + return rte_ring_mc_hts_dequeue_bulk(r, obj_table, n, available); +#endif + } + + /* valid ring should never reach this point */ + RTE_ASSERT(0); + return 0; } /** @@ -669,6 +658,20 @@ rte_ring_dequeue(struct rte_ring *r, void **obj_p) return rte_ring_dequeue_bulk(r, obj_p, 1, NULL) ? 0 : -ENOENT; } +/** + * Flush a ring. + * + * This function flush all the elements in a ring + * + * @warning + * Make sure the ring is not in use while calling this function. + * + * @param r + * A pointer to the ring structure. + */ +void +rte_ring_reset(struct rte_ring *r); + /** * Return the number of entries in a ring. * @@ -677,7 +680,7 @@ rte_ring_dequeue(struct rte_ring *r, void **obj_p) * @return * The number of entries in the ring. */ -static inline unsigned +static inline unsigned int rte_ring_count(const struct rte_ring *r) { uint32_t prod_tail = r->prod.tail; @@ -694,7 +697,7 @@ rte_ring_count(const struct rte_ring *r) * @return * The number of free entries in the ring. */ -static inline unsigned +static inline unsigned int rte_ring_free_count(const struct rte_ring *r) { return r->capacity - rte_ring_count(r); @@ -727,7 +730,9 @@ rte_ring_full(const struct rte_ring *r) static inline int rte_ring_empty(const struct rte_ring *r) { - return rte_ring_count(r) == 0; + uint32_t prod_tail = r->prod.tail; + uint32_t cons_tail = r->cons.tail; + return cons_tail == prod_tail; } /** @@ -760,6 +765,62 @@ rte_ring_get_capacity(const struct rte_ring *r) return r->capacity; } +/** + * Return sync type used by producer in the ring. + * + * @param r + * A pointer to the ring structure. + * @return + * Producer sync type value. + */ +static inline enum rte_ring_sync_type +rte_ring_get_prod_sync_type(const struct rte_ring *r) +{ + return r->prod.sync_type; +} + +/** + * Check is the ring for single producer. + * + * @param r + * A pointer to the ring structure. + * @return + * true if ring is SP, zero otherwise. + */ +static inline int +rte_ring_is_prod_single(const struct rte_ring *r) +{ + return (rte_ring_get_prod_sync_type(r) == RTE_RING_SYNC_ST); +} + +/** + * Return sync type used by consumer in the ring. + * + * @param r + * A pointer to the ring structure. + * @return + * Consumer sync type value. + */ +static inline enum rte_ring_sync_type +rte_ring_get_cons_sync_type(const struct rte_ring *r) +{ + return r->cons.sync_type; +} + +/** + * Check is the ring for single consumer. + * + * @param r + * A pointer to the ring structure. + * @return + * true if ring is SC, zero otherwise. + */ +static inline int +rte_ring_is_cons_single(const struct rte_ring *r) +{ + return (rte_ring_get_cons_sync_type(r) == RTE_RING_SYNC_ST); +} + /** * Dump the status of all rings on the console * @@ -798,12 +859,12 @@ struct rte_ring *rte_ring_lookup(const char *name); * @return * - n: Actual number of objects enqueued. */ -static __rte_always_inline unsigned +static __rte_always_inline unsigned int rte_ring_mp_enqueue_burst(struct rte_ring *r, void * const *obj_table, unsigned int n, unsigned int *free_space) { return __rte_ring_do_enqueue(r, obj_table, n, - RTE_RING_QUEUE_VARIABLE, __IS_MP, free_space); + RTE_RING_QUEUE_VARIABLE, RTE_RING_SYNC_MT, free_space); } /** @@ -821,12 +882,12 @@ rte_ring_mp_enqueue_burst(struct rte_ring *r, void * const *obj_table, * @return * - n: Actual number of objects enqueued. */ -static __rte_always_inline unsigned +static __rte_always_inline unsigned int rte_ring_sp_enqueue_burst(struct rte_ring *r, void * const *obj_table, unsigned int n, unsigned int *free_space) { return __rte_ring_do_enqueue(r, obj_table, n, - RTE_RING_QUEUE_VARIABLE, __IS_SP, free_space); + RTE_RING_QUEUE_VARIABLE, RTE_RING_SYNC_ST, free_space); } /** @@ -848,12 +909,28 @@ rte_ring_sp_enqueue_burst(struct rte_ring *r, void * const *obj_table, * @return * - n: Actual number of objects enqueued. */ -static __rte_always_inline unsigned +static __rte_always_inline unsigned int rte_ring_enqueue_burst(struct rte_ring *r, void * const *obj_table, unsigned int n, unsigned int *free_space) { - return __rte_ring_do_enqueue(r, obj_table, n, RTE_RING_QUEUE_VARIABLE, - r->prod.single, free_space); + switch (r->prod.sync_type) { + case RTE_RING_SYNC_MT: + return rte_ring_mp_enqueue_burst(r, obj_table, n, free_space); + case RTE_RING_SYNC_ST: + return rte_ring_sp_enqueue_burst(r, obj_table, n, free_space); +#ifdef ALLOW_EXPERIMENTAL_API + case RTE_RING_SYNC_MT_RTS: + return rte_ring_mp_rts_enqueue_burst(r, obj_table, n, + free_space); + case RTE_RING_SYNC_MT_HTS: + return rte_ring_mp_hts_enqueue_burst(r, obj_table, n, + free_space); +#endif + } + + /* valid ring should never reach this point */ + RTE_ASSERT(0); + return 0; } /** @@ -876,12 +953,12 @@ rte_ring_enqueue_burst(struct rte_ring *r, void * const *obj_table, * @return * - n: Actual number of objects dequeued, 0 if ring is empty */ -static __rte_always_inline unsigned +static __rte_always_inline unsigned int rte_ring_mc_dequeue_burst(struct rte_ring *r, void **obj_table, unsigned int n, unsigned int *available) { return __rte_ring_do_dequeue(r, obj_table, n, - RTE_RING_QUEUE_VARIABLE, __IS_MC, available); + RTE_RING_QUEUE_VARIABLE, RTE_RING_SYNC_MT, available); } /** @@ -901,12 +978,12 @@ rte_ring_mc_dequeue_burst(struct rte_ring *r, void **obj_table, * @return * - n: Actual number of objects dequeued, 0 if ring is empty */ -static __rte_always_inline unsigned +static __rte_always_inline unsigned int rte_ring_sc_dequeue_burst(struct rte_ring *r, void **obj_table, unsigned int n, unsigned int *available) { return __rte_ring_do_dequeue(r, obj_table, n, - RTE_RING_QUEUE_VARIABLE, __IS_SC, available); + RTE_RING_QUEUE_VARIABLE, RTE_RING_SYNC_ST, available); } /** @@ -928,13 +1005,28 @@ rte_ring_sc_dequeue_burst(struct rte_ring *r, void **obj_table, * @return * - Number of objects dequeued */ -static __rte_always_inline unsigned +static __rte_always_inline unsigned int rte_ring_dequeue_burst(struct rte_ring *r, void **obj_table, unsigned int n, unsigned int *available) { - return __rte_ring_do_dequeue(r, obj_table, n, - RTE_RING_QUEUE_VARIABLE, - r->cons.single, available); + switch (r->cons.sync_type) { + case RTE_RING_SYNC_MT: + return rte_ring_mc_dequeue_burst(r, obj_table, n, available); + case RTE_RING_SYNC_ST: + return rte_ring_sc_dequeue_burst(r, obj_table, n, available); +#ifdef ALLOW_EXPERIMENTAL_API + case RTE_RING_SYNC_MT_RTS: + return rte_ring_mc_rts_dequeue_burst(r, obj_table, n, + available); + case RTE_RING_SYNC_MT_HTS: + return rte_ring_mc_hts_dequeue_burst(r, obj_table, n, + available); +#endif + } + + /* valid ring should never reach this point */ + RTE_ASSERT(0); + return 0; } #ifdef __cplusplus