xref: /dpdk/lib/ring/rte_ring_rts.h (revision 719834a6849e1daf4a70ff7742bbcc3ae7e25607)
199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson  *
399a2dd95SBruce Richardson  * Copyright (c) 2010-2020 Intel Corporation
499a2dd95SBruce Richardson  * Copyright (c) 2007-2009 Kip Macy kmacy@freebsd.org
599a2dd95SBruce Richardson  * All rights reserved.
699a2dd95SBruce Richardson  * Derived from FreeBSD's bufring.h
799a2dd95SBruce Richardson  * Used as BSD-3 Licensed with permission from Kip Macy.
899a2dd95SBruce Richardson  */
999a2dd95SBruce Richardson 
1099a2dd95SBruce Richardson #ifndef _RTE_RING_RTS_H_
1199a2dd95SBruce Richardson #define _RTE_RING_RTS_H_
1299a2dd95SBruce Richardson 
1399a2dd95SBruce Richardson /**
1499a2dd95SBruce Richardson  * @file rte_ring_rts.h
1599a2dd95SBruce Richardson  * It is not recommended to include this file directly.
1699a2dd95SBruce Richardson  * Please include <rte_ring.h> instead.
1799a2dd95SBruce Richardson  *
1899a2dd95SBruce Richardson  * Contains functions for Relaxed Tail Sync (RTS) ring mode.
1999a2dd95SBruce Richardson  * The main idea remains the same as for our original MP/MC synchronization
2099a2dd95SBruce Richardson  * mechanism.
2199a2dd95SBruce Richardson  * The main difference is that tail value is increased not
2299a2dd95SBruce Richardson  * by every thread that finished enqueue/dequeue,
2399a2dd95SBruce Richardson  * but only by the current last one doing enqueue/dequeue.
2499a2dd95SBruce Richardson  * That allows threads to skip spinning on tail value,
2599a2dd95SBruce Richardson  * leaving actual tail value change to last thread at a given instance.
2699a2dd95SBruce Richardson  * RTS requires 2 64-bit CAS for each enqueue(/dequeue) operation:
2799a2dd95SBruce Richardson  * one for head update, second for tail update.
2899a2dd95SBruce Richardson  * As a gain it allows thread to avoid spinning/waiting on tail value.
2999a2dd95SBruce Richardson  * In comparison original MP/MC algorithm requires one 32-bit CAS
3099a2dd95SBruce Richardson  * for head update and waiting/spinning on tail value.
3199a2dd95SBruce Richardson  *
3299a2dd95SBruce Richardson  * Brief outline:
3399a2dd95SBruce Richardson  *  - introduce update counter (cnt) for both head and tail.
3499a2dd95SBruce Richardson  *  - increment head.cnt for each head.value update
3599a2dd95SBruce Richardson  *  - write head.value and head.cnt atomically (64-bit CAS)
3699a2dd95SBruce Richardson  *  - move tail.value ahead only when tail.cnt + 1 == head.cnt
3799a2dd95SBruce Richardson  *    (indicating that this is the last thread updating the tail)
3899a2dd95SBruce Richardson  *  - increment tail.cnt when each enqueue/dequeue op finishes
3999a2dd95SBruce Richardson  *    (no matter if tail.value going to change or not)
4099a2dd95SBruce Richardson  *  - write tail.value and tail.cnt atomically (64-bit CAS)
4199a2dd95SBruce Richardson  *
4299a2dd95SBruce Richardson  * To avoid producer/consumer starvation:
4399a2dd95SBruce Richardson  *  - limit max allowed distance between head and tail value (HTD_MAX).
4499a2dd95SBruce Richardson  *    I.E. thread is allowed to proceed with changing head.value,
4599a2dd95SBruce Richardson  *    only when:  head.value - tail.value <= HTD_MAX
4699a2dd95SBruce Richardson  * HTD_MAX is an optional parameter.
4799a2dd95SBruce Richardson  * With HTD_MAX == 0 we'll have fully serialized ring -
4899a2dd95SBruce Richardson  * i.e. only one thread at a time will be able to enqueue/dequeue
4999a2dd95SBruce Richardson  * to/from the ring.
5099a2dd95SBruce Richardson  * With HTD_MAX >= ring.capacity - no limitation.
5199a2dd95SBruce Richardson  * By default HTD_MAX == ring.capacity / 8.
5299a2dd95SBruce Richardson  */
5399a2dd95SBruce Richardson 
54*719834a6SMattias Rönnblom #include <rte_ring_rts_elem_pvt.h>
55*719834a6SMattias Rönnblom 
5699a2dd95SBruce Richardson #ifdef __cplusplus
5799a2dd95SBruce Richardson extern "C" {
5899a2dd95SBruce Richardson #endif
5999a2dd95SBruce Richardson 
6099a2dd95SBruce Richardson /**
6199a2dd95SBruce Richardson  * Enqueue several objects on the RTS ring (multi-producers safe).
6299a2dd95SBruce Richardson  *
6399a2dd95SBruce Richardson  * @param r
6499a2dd95SBruce Richardson  *   A pointer to the ring structure.
6599a2dd95SBruce Richardson  * @param obj_table
6699a2dd95SBruce Richardson  *   A pointer to a table of objects.
6799a2dd95SBruce Richardson  * @param esize
6899a2dd95SBruce Richardson  *   The size of ring element, in bytes. It must be a multiple of 4.
6999a2dd95SBruce Richardson  *   This must be the same value used while creating the ring. Otherwise
7099a2dd95SBruce Richardson  *   the results are undefined.
7199a2dd95SBruce Richardson  * @param n
7299a2dd95SBruce Richardson  *   The number of objects to add in the ring from the obj_table.
7399a2dd95SBruce Richardson  * @param free_space
7499a2dd95SBruce Richardson  *   if non-NULL, returns the amount of space in the ring after the
7599a2dd95SBruce Richardson  *   enqueue operation has finished.
7699a2dd95SBruce Richardson  * @return
7799a2dd95SBruce Richardson  *   The number of objects enqueued, either 0 or n
7899a2dd95SBruce Richardson  */
7999a2dd95SBruce Richardson static __rte_always_inline unsigned int
8099a2dd95SBruce Richardson rte_ring_mp_rts_enqueue_bulk_elem(struct rte_ring *r, const void *obj_table,
8199a2dd95SBruce Richardson 	unsigned int esize, unsigned int n, unsigned int *free_space)
8299a2dd95SBruce Richardson {
8399a2dd95SBruce Richardson 	return __rte_ring_do_rts_enqueue_elem(r, obj_table, esize, n,
8499a2dd95SBruce Richardson 			RTE_RING_QUEUE_FIXED, free_space);
8599a2dd95SBruce Richardson }
8699a2dd95SBruce Richardson 
8799a2dd95SBruce Richardson /**
8899a2dd95SBruce Richardson  * Dequeue several objects from an RTS ring (multi-consumers safe).
8999a2dd95SBruce Richardson  *
9099a2dd95SBruce Richardson  * @param r
9199a2dd95SBruce Richardson  *   A pointer to the ring structure.
9299a2dd95SBruce Richardson  * @param obj_table
9399a2dd95SBruce Richardson  *   A pointer to a table of objects that will be filled.
9499a2dd95SBruce Richardson  * @param esize
9599a2dd95SBruce Richardson  *   The size of ring element, in bytes. It must be a multiple of 4.
9699a2dd95SBruce Richardson  *   This must be the same value used while creating the ring. Otherwise
9799a2dd95SBruce Richardson  *   the results are undefined.
9899a2dd95SBruce Richardson  * @param n
9999a2dd95SBruce Richardson  *   The number of objects to dequeue from the ring to the obj_table.
10099a2dd95SBruce Richardson  * @param available
10199a2dd95SBruce Richardson  *   If non-NULL, returns the number of remaining ring entries after the
10299a2dd95SBruce Richardson  *   dequeue has finished.
10399a2dd95SBruce Richardson  * @return
10499a2dd95SBruce Richardson  *   The number of objects dequeued, either 0 or n
10599a2dd95SBruce Richardson  */
10699a2dd95SBruce Richardson static __rte_always_inline unsigned int
10799a2dd95SBruce Richardson rte_ring_mc_rts_dequeue_bulk_elem(struct rte_ring *r, void *obj_table,
10899a2dd95SBruce Richardson 	unsigned int esize, unsigned int n, unsigned int *available)
10999a2dd95SBruce Richardson {
11099a2dd95SBruce Richardson 	return __rte_ring_do_rts_dequeue_elem(r, obj_table, esize, n,
11199a2dd95SBruce Richardson 			RTE_RING_QUEUE_FIXED, available);
11299a2dd95SBruce Richardson }
11399a2dd95SBruce Richardson 
11499a2dd95SBruce Richardson /**
11599a2dd95SBruce Richardson  * Enqueue several objects on the RTS ring (multi-producers safe).
11699a2dd95SBruce Richardson  *
11799a2dd95SBruce Richardson  * @param r
11899a2dd95SBruce Richardson  *   A pointer to the ring structure.
11999a2dd95SBruce Richardson  * @param obj_table
12099a2dd95SBruce Richardson  *   A pointer to a table of objects.
12199a2dd95SBruce Richardson  * @param esize
12299a2dd95SBruce Richardson  *   The size of ring element, in bytes. It must be a multiple of 4.
12399a2dd95SBruce Richardson  *   This must be the same value used while creating the ring. Otherwise
12499a2dd95SBruce Richardson  *   the results are undefined.
12599a2dd95SBruce Richardson  * @param n
12699a2dd95SBruce Richardson  *   The number of objects to add in the ring from the obj_table.
12799a2dd95SBruce Richardson  * @param free_space
12899a2dd95SBruce Richardson  *   if non-NULL, returns the amount of space in the ring after the
12999a2dd95SBruce Richardson  *   enqueue operation has finished.
13099a2dd95SBruce Richardson  * @return
13199a2dd95SBruce Richardson  *   - n: Actual number of objects enqueued.
13299a2dd95SBruce Richardson  */
13399a2dd95SBruce Richardson static __rte_always_inline unsigned int
13499a2dd95SBruce Richardson rte_ring_mp_rts_enqueue_burst_elem(struct rte_ring *r, const void *obj_table,
13599a2dd95SBruce Richardson 	unsigned int esize, unsigned int n, unsigned int *free_space)
13699a2dd95SBruce Richardson {
13799a2dd95SBruce Richardson 	return __rte_ring_do_rts_enqueue_elem(r, obj_table, esize, n,
13899a2dd95SBruce Richardson 			RTE_RING_QUEUE_VARIABLE, free_space);
13999a2dd95SBruce Richardson }
14099a2dd95SBruce Richardson 
14199a2dd95SBruce Richardson /**
14299a2dd95SBruce Richardson  * Dequeue several objects from an RTS  ring (multi-consumers safe).
14399a2dd95SBruce Richardson  * When the requested objects are more than the available objects,
14499a2dd95SBruce Richardson  * only dequeue the actual number of objects.
14599a2dd95SBruce Richardson  *
14699a2dd95SBruce Richardson  * @param r
14799a2dd95SBruce Richardson  *   A pointer to the ring structure.
14899a2dd95SBruce Richardson  * @param obj_table
14999a2dd95SBruce Richardson  *   A pointer to a table of objects that will be filled.
15099a2dd95SBruce Richardson  * @param esize
15199a2dd95SBruce Richardson  *   The size of ring element, in bytes. It must be a multiple of 4.
15299a2dd95SBruce Richardson  *   This must be the same value used while creating the ring. Otherwise
15399a2dd95SBruce Richardson  *   the results are undefined.
15499a2dd95SBruce Richardson  * @param n
15599a2dd95SBruce Richardson  *   The number of objects to dequeue from the ring to the obj_table.
15699a2dd95SBruce Richardson  * @param available
15799a2dd95SBruce Richardson  *   If non-NULL, returns the number of remaining ring entries after the
15899a2dd95SBruce Richardson  *   dequeue has finished.
15999a2dd95SBruce Richardson  * @return
16099a2dd95SBruce Richardson  *   - n: Actual number of objects dequeued, 0 if ring is empty
16199a2dd95SBruce Richardson  */
16299a2dd95SBruce Richardson static __rte_always_inline unsigned int
16399a2dd95SBruce Richardson rte_ring_mc_rts_dequeue_burst_elem(struct rte_ring *r, void *obj_table,
16499a2dd95SBruce Richardson 	unsigned int esize, unsigned int n, unsigned int *available)
16599a2dd95SBruce Richardson {
16699a2dd95SBruce Richardson 	return __rte_ring_do_rts_dequeue_elem(r, obj_table, esize, n,
16799a2dd95SBruce Richardson 			RTE_RING_QUEUE_VARIABLE, available);
16899a2dd95SBruce Richardson }
16999a2dd95SBruce Richardson 
17099a2dd95SBruce Richardson /**
17199a2dd95SBruce Richardson  * Enqueue several objects on the RTS ring (multi-producers safe).
17299a2dd95SBruce Richardson  *
17399a2dd95SBruce Richardson  * @param r
17499a2dd95SBruce Richardson  *   A pointer to the ring structure.
17599a2dd95SBruce Richardson  * @param obj_table
17699a2dd95SBruce Richardson  *   A pointer to a table of void * pointers (objects).
17799a2dd95SBruce Richardson  * @param n
17899a2dd95SBruce Richardson  *   The number of objects to add in the ring from the obj_table.
17999a2dd95SBruce Richardson  * @param free_space
18099a2dd95SBruce Richardson  *   if non-NULL, returns the amount of space in the ring after the
18199a2dd95SBruce Richardson  *   enqueue operation has finished.
18299a2dd95SBruce Richardson  * @return
18399a2dd95SBruce Richardson  *   The number of objects enqueued, either 0 or n
18499a2dd95SBruce Richardson  */
18599a2dd95SBruce Richardson static __rte_always_inline unsigned int
18699a2dd95SBruce Richardson rte_ring_mp_rts_enqueue_bulk(struct rte_ring *r, void * const *obj_table,
18799a2dd95SBruce Richardson 			 unsigned int n, unsigned int *free_space)
18899a2dd95SBruce Richardson {
18999a2dd95SBruce Richardson 	return rte_ring_mp_rts_enqueue_bulk_elem(r, obj_table,
19099a2dd95SBruce Richardson 			sizeof(uintptr_t), n, free_space);
19199a2dd95SBruce Richardson }
19299a2dd95SBruce Richardson 
19399a2dd95SBruce Richardson /**
19499a2dd95SBruce Richardson  * Dequeue several objects from an RTS ring (multi-consumers safe).
19599a2dd95SBruce Richardson  *
19699a2dd95SBruce Richardson  * @param r
19799a2dd95SBruce Richardson  *   A pointer to the ring structure.
19899a2dd95SBruce Richardson  * @param obj_table
19999a2dd95SBruce Richardson  *   A pointer to a table of void * pointers (objects) that will be filled.
20099a2dd95SBruce Richardson  * @param n
20199a2dd95SBruce Richardson  *   The number of objects to dequeue from the ring to the obj_table.
20299a2dd95SBruce Richardson  * @param available
20399a2dd95SBruce Richardson  *   If non-NULL, returns the number of remaining ring entries after the
20499a2dd95SBruce Richardson  *   dequeue has finished.
20599a2dd95SBruce Richardson  * @return
20699a2dd95SBruce Richardson  *   The number of objects dequeued, either 0 or n
20799a2dd95SBruce Richardson  */
20899a2dd95SBruce Richardson static __rte_always_inline unsigned int
20999a2dd95SBruce Richardson rte_ring_mc_rts_dequeue_bulk(struct rte_ring *r, void **obj_table,
21099a2dd95SBruce Richardson 		unsigned int n, unsigned int *available)
21199a2dd95SBruce Richardson {
21299a2dd95SBruce Richardson 	return rte_ring_mc_rts_dequeue_bulk_elem(r, obj_table,
21399a2dd95SBruce Richardson 			sizeof(uintptr_t), n, available);
21499a2dd95SBruce Richardson }
21599a2dd95SBruce Richardson 
21699a2dd95SBruce Richardson /**
21799a2dd95SBruce Richardson  * Enqueue several objects on the RTS ring (multi-producers safe).
21899a2dd95SBruce Richardson  *
21999a2dd95SBruce Richardson  * @param r
22099a2dd95SBruce Richardson  *   A pointer to the ring structure.
22199a2dd95SBruce Richardson  * @param obj_table
22299a2dd95SBruce Richardson  *   A pointer to a table of void * pointers (objects).
22399a2dd95SBruce Richardson  * @param n
22499a2dd95SBruce Richardson  *   The number of objects to add in the ring from the obj_table.
22599a2dd95SBruce Richardson  * @param free_space
22699a2dd95SBruce Richardson  *   if non-NULL, returns the amount of space in the ring after the
22799a2dd95SBruce Richardson  *   enqueue operation has finished.
22899a2dd95SBruce Richardson  * @return
22999a2dd95SBruce Richardson  *   - n: Actual number of objects enqueued.
23099a2dd95SBruce Richardson  */
23199a2dd95SBruce Richardson static __rte_always_inline unsigned int
23299a2dd95SBruce Richardson rte_ring_mp_rts_enqueue_burst(struct rte_ring *r, void * const *obj_table,
23399a2dd95SBruce Richardson 			 unsigned int n, unsigned int *free_space)
23499a2dd95SBruce Richardson {
23599a2dd95SBruce Richardson 	return rte_ring_mp_rts_enqueue_burst_elem(r, obj_table,
23699a2dd95SBruce Richardson 			sizeof(uintptr_t), n, free_space);
23799a2dd95SBruce Richardson }
23899a2dd95SBruce Richardson 
23999a2dd95SBruce Richardson /**
24099a2dd95SBruce Richardson  * Dequeue several objects from an RTS  ring (multi-consumers safe).
24199a2dd95SBruce Richardson  * When the requested objects are more than the available objects,
24299a2dd95SBruce Richardson  * only dequeue the actual number of objects.
24399a2dd95SBruce Richardson  *
24499a2dd95SBruce Richardson  * @param r
24599a2dd95SBruce Richardson  *   A pointer to the ring structure.
24699a2dd95SBruce Richardson  * @param obj_table
24799a2dd95SBruce Richardson  *   A pointer to a table of void * pointers (objects) that will be filled.
24899a2dd95SBruce Richardson  * @param n
24999a2dd95SBruce Richardson  *   The number of objects to dequeue from the ring to the obj_table.
25099a2dd95SBruce Richardson  * @param available
25199a2dd95SBruce Richardson  *   If non-NULL, returns the number of remaining ring entries after the
25299a2dd95SBruce Richardson  *   dequeue has finished.
25399a2dd95SBruce Richardson  * @return
25499a2dd95SBruce Richardson  *   - n: Actual number of objects dequeued, 0 if ring is empty
25599a2dd95SBruce Richardson  */
25699a2dd95SBruce Richardson static __rte_always_inline unsigned int
25799a2dd95SBruce Richardson rte_ring_mc_rts_dequeue_burst(struct rte_ring *r, void **obj_table,
25899a2dd95SBruce Richardson 		unsigned int n, unsigned int *available)
25999a2dd95SBruce Richardson {
26099a2dd95SBruce Richardson 	return rte_ring_mc_rts_dequeue_burst_elem(r, obj_table,
26199a2dd95SBruce Richardson 			sizeof(uintptr_t), n, available);
26299a2dd95SBruce Richardson }
26399a2dd95SBruce Richardson 
26499a2dd95SBruce Richardson /**
26599a2dd95SBruce Richardson  * Return producer max Head-Tail-Distance (HTD).
26699a2dd95SBruce Richardson  *
26799a2dd95SBruce Richardson  * @param r
26899a2dd95SBruce Richardson  *   A pointer to the ring structure.
26999a2dd95SBruce Richardson  * @return
27099a2dd95SBruce Richardson  *   Producer HTD value, if producer is set in appropriate sync mode,
27199a2dd95SBruce Richardson  *   or UINT32_MAX otherwise.
27299a2dd95SBruce Richardson  */
27399a2dd95SBruce Richardson static inline uint32_t
27499a2dd95SBruce Richardson rte_ring_get_prod_htd_max(const struct rte_ring *r)
27599a2dd95SBruce Richardson {
27699a2dd95SBruce Richardson 	if (r->prod.sync_type == RTE_RING_SYNC_MT_RTS)
27799a2dd95SBruce Richardson 		return r->rts_prod.htd_max;
27899a2dd95SBruce Richardson 	return UINT32_MAX;
27999a2dd95SBruce Richardson }
28099a2dd95SBruce Richardson 
28199a2dd95SBruce Richardson /**
28299a2dd95SBruce Richardson  * Set producer max Head-Tail-Distance (HTD).
28399a2dd95SBruce Richardson  * Note that producer has to use appropriate sync mode (RTS).
28499a2dd95SBruce Richardson  *
28599a2dd95SBruce Richardson  * @param r
28699a2dd95SBruce Richardson  *   A pointer to the ring structure.
28799a2dd95SBruce Richardson  * @param v
28899a2dd95SBruce Richardson  *   new HTD value to setup.
28999a2dd95SBruce Richardson  * @return
29099a2dd95SBruce Richardson  *   Zero on success, or negative error code otherwise.
29199a2dd95SBruce Richardson  */
29299a2dd95SBruce Richardson static inline int
29399a2dd95SBruce Richardson rte_ring_set_prod_htd_max(struct rte_ring *r, uint32_t v)
29499a2dd95SBruce Richardson {
29599a2dd95SBruce Richardson 	if (r->prod.sync_type != RTE_RING_SYNC_MT_RTS)
29699a2dd95SBruce Richardson 		return -ENOTSUP;
29799a2dd95SBruce Richardson 
29899a2dd95SBruce Richardson 	r->rts_prod.htd_max = v;
29999a2dd95SBruce Richardson 	return 0;
30099a2dd95SBruce Richardson }
30199a2dd95SBruce Richardson 
30299a2dd95SBruce Richardson /**
30399a2dd95SBruce Richardson  * Return consumer max Head-Tail-Distance (HTD).
30499a2dd95SBruce Richardson  *
30599a2dd95SBruce Richardson  * @param r
30699a2dd95SBruce Richardson  *   A pointer to the ring structure.
30799a2dd95SBruce Richardson  * @return
30899a2dd95SBruce Richardson  *   Consumer HTD value, if consumer is set in appropriate sync mode,
30999a2dd95SBruce Richardson  *   or UINT32_MAX otherwise.
31099a2dd95SBruce Richardson  */
31199a2dd95SBruce Richardson static inline uint32_t
31299a2dd95SBruce Richardson rte_ring_get_cons_htd_max(const struct rte_ring *r)
31399a2dd95SBruce Richardson {
31499a2dd95SBruce Richardson 	if (r->cons.sync_type == RTE_RING_SYNC_MT_RTS)
31599a2dd95SBruce Richardson 		return r->rts_cons.htd_max;
31699a2dd95SBruce Richardson 	return UINT32_MAX;
31799a2dd95SBruce Richardson }
31899a2dd95SBruce Richardson 
31999a2dd95SBruce Richardson /**
32099a2dd95SBruce Richardson  * Set consumer max Head-Tail-Distance (HTD).
32199a2dd95SBruce Richardson  * Note that consumer has to use appropriate sync mode (RTS).
32299a2dd95SBruce Richardson  *
32399a2dd95SBruce Richardson  * @param r
32499a2dd95SBruce Richardson  *   A pointer to the ring structure.
32599a2dd95SBruce Richardson  * @param v
32699a2dd95SBruce Richardson  *   new HTD value to setup.
32799a2dd95SBruce Richardson  * @return
32899a2dd95SBruce Richardson  *   Zero on success, or negative error code otherwise.
32999a2dd95SBruce Richardson  */
33099a2dd95SBruce Richardson static inline int
33199a2dd95SBruce Richardson rte_ring_set_cons_htd_max(struct rte_ring *r, uint32_t v)
33299a2dd95SBruce Richardson {
33399a2dd95SBruce Richardson 	if (r->cons.sync_type != RTE_RING_SYNC_MT_RTS)
33499a2dd95SBruce Richardson 		return -ENOTSUP;
33599a2dd95SBruce Richardson 
33699a2dd95SBruce Richardson 	r->rts_cons.htd_max = v;
33799a2dd95SBruce Richardson 	return 0;
33899a2dd95SBruce Richardson }
33999a2dd95SBruce Richardson 
34099a2dd95SBruce Richardson #ifdef __cplusplus
34199a2dd95SBruce Richardson }
34299a2dd95SBruce Richardson #endif
34399a2dd95SBruce Richardson 
34499a2dd95SBruce Richardson #endif /* _RTE_RING_RTS_H_ */
345