[dpdk-dev] [PATCH v7 3/6] ring: add a lock-free implementation

Stephen Hemminger stephen at networkplumber.org
Tue Mar 19 16:50:22 CET 2019


On Mon, 18 Mar 2019 16:35:52 -0500
Gage Eads <gage.eads at intel.com> wrote:

>  
> +/* The actual enqueue of pointers on the lock-free ring, used by the
> + * single-producer lock-free enqueue function.
> + */
> +#define ENQUEUE_PTRS_LF(r, base, prod_head, obj_table, n) do { \
> +	unsigned int i; \
> +	const uint32_t size = (r)->size; \
> +	size_t idx = prod_head & (r)->mask; \
> +	size_t new_cnt = prod_head + size; \
> +	struct rte_ring_lf_entry *ring = (struct rte_ring_lf_entry *)base; \
> +	unsigned int mask = ~0x3; \
> +	if (likely(idx + n < size)) { \
> +		for (i = 0; i < (n & mask); i += 4, idx += 4) { \
> +			ring[idx].ptr = obj_table[i]; \
> +			ring[idx].cnt = (new_cnt + i) >> r->log2_size; \
> +			ring[idx + 1].ptr = obj_table[i + 1]; \
> +			ring[idx + 1].cnt = (new_cnt + i + 1) >> r->log2_size; \
> +			ring[idx + 2].ptr = obj_table[i + 2]; \
> +			ring[idx + 2].cnt = (new_cnt + i + 2) >> r->log2_size; \
> +			ring[idx + 3].ptr = obj_table[i + 3]; \
> +			ring[idx + 3].cnt = (new_cnt + i + 3) >> r->log2_size; \
> +		} \
> +		switch (n & 0x3) { \
> +		case 3: \
> +			ring[idx].cnt = (new_cnt + i) >> r->log2_size; \
> +			ring[idx++].ptr = obj_table[i++]; /* fallthrough */ \
> +		case 2: \
> +			ring[idx].cnt = (new_cnt + i) >> r->log2_size; \
> +			ring[idx++].ptr = obj_table[i++]; /* fallthrough */ \
> +		case 1: \
> +			ring[idx].cnt = (new_cnt + i) >> r->log2_size; \
> +			ring[idx++].ptr = obj_table[i++]; \
> +		} \
> +	} else { \
> +		for (i = 0; idx < size; i++, idx++) { \
> +			ring[idx].cnt = (new_cnt + i) >> r->log2_size; \
> +			ring[idx].ptr = obj_table[i]; \
> +		} \
> +		for (idx = 0; i < n; i++, idx++) {    \
> +			ring[idx].cnt = (new_cnt + i) >> r->log2_size; \
> +			ring[idx].ptr = obj_table[i]; \
> +		} \
> +	} \
> +} while (0)
> +
>  /* the actual copy of pointers on the ring to obj_table.
>   * Placed here since identical code needed in both
>   * single and multi consumer dequeue functions */
> @@ -314,6 +384,43 @@ void rte_ring_dump(FILE *f, const struct rte_ring *r);
>  	} \
>  } while (0)
>  
> +/* The actual copy of pointers on the lock-free ring to obj_table. */
> +#define DEQUEUE_PTRS_LF(r, base, cons_head, obj_table, n) do { \
> +	unsigned int i; \
> +	size_t idx = cons_head & (r)->mask; \
> +	const uint32_t size = (r)->size; \
> +	struct rte_ring_lf_entry *ring = (struct rte_ring_lf_entry *)base; \
> +	unsigned int mask = ~0x3; \
> +	if (likely(idx + n < size)) { \
> +		for (i = 0; i < (n & mask); i += 4, idx += 4) {\
> +			obj_table[i] = ring[idx].ptr; \
> +			obj_table[i + 1] = ring[idx + 1].ptr; \
> +			obj_table[i + 2] = ring[idx + 2].ptr; \
> +			obj_table[i + 3] = ring[idx + 3].ptr; \
> +		} \
> +		switch (n & 0x3) { \
> +		case 3: \
> +			obj_table[i++] = ring[idx++].ptr; /* fallthrough */ \
> +		case 2: \
> +			obj_table[i++] = ring[idx++].ptr; /* fallthrough */ \
> +		case 1: \
> +			obj_table[i++] = ring[idx++].ptr; \
> +		} \
> +	} else { \
> +		for (i = 0; idx < size; i++, idx++) \
> +			obj_table[i] = ring[idx].ptr; \
> +		for (idx = 0; i < n; i++, idx++) \
> +			obj_table[i] = ring[idx].ptr; \
> +	} \
> +} while (0)
> +

Generic programming like this in C is hard to maintain. Please don't
use large macros. It is better to have two copies than a single large macro.
Better yet use a single inline function than can be expanded in different ways
based on the pointer size.


More information about the dev mailing list