DPDK 26.07.0-rc1
rte_ring_c11_pvt.h
Go to the documentation of this file.
1/* SPDX-License-Identifier: BSD-3-Clause
2 *
3 * Copyright (c) 2017,2018 HXT-semitech Corporation.
4 * Copyright (c) 2007-2009 Kip Macy kmacy@freebsd.org
5 * Copyright (c) 2021 Arm Limited
6 * All rights reserved.
7 * Derived from FreeBSD's bufring.h
8 * Used as BSD-3 Licensed with permission from Kip Macy.
9 */
10
11#ifndef _RTE_RING_C11_PVT_H_
12#define _RTE_RING_C11_PVT_H_
13
48static __rte_always_inline unsigned int
49__rte_ring_headtail_move_head_st(struct rte_ring_headtail *d,
50 const struct rte_ring_headtail *s, uint32_t capacity,
51 unsigned int n,
52 enum rte_ring_queue_behavior behavior,
53 uint32_t *old_head, uint32_t *new_head, uint32_t *entries)
54{
55 uint32_t stail;
56
57 /* Single producer: only this thread writes d->head,
58 * so a relaxed load is sufficient.
59 */
60 *old_head = rte_atomic_load_explicit(&d->head, rte_memory_order_relaxed);
61
62 /* Acquire pairs with the consumer's release-store of tail in __rte_ring_update_tail,
63 * ensuring the consumer's ring-element reads are complete before
64 * we observe the updated tail.
65 */
66 stail = rte_atomic_load_explicit(&s->tail, rte_memory_order_acquire);
67
68 /* Unsigned subtraction is modulo 2^32, so entries is always in
69 * [0, capacity) even if old_head > stail.
70 */
71 *entries = capacity + stail - *old_head;
72
73 /* check that we have enough room in ring */
74 if (unlikely(n > *entries))
75 n = (behavior == RTE_RING_QUEUE_FIXED) ? 0 : *entries;
76
77 if (n > 0) {
78 *new_head = *old_head + n;
79 rte_atomic_store_explicit(&d->head, *new_head, rte_memory_order_relaxed);
80 }
81
82 return n;
83}
84
111static __rte_always_inline unsigned int
112__rte_ring_headtail_move_head_mt(struct rte_ring_headtail *d,
113 const struct rte_ring_headtail *s, uint32_t capacity,
114 unsigned int n,
115 enum rte_ring_queue_behavior behavior,
116 uint32_t *old_head, uint32_t *new_head, uint32_t *entries)
117{
118 uint32_t stail;
119 bool success;
120 unsigned int max = n;
121
122 /*
123 * A0: Establishes a synchronizing edge with R1.
124 * Ensure that this thread observes same values
125 * to stail observed by the thread that updated
126 * d->head.
127 * If not, an unsafe partial order may ensue.
128 */
129 *old_head = rte_atomic_load_explicit(&d->head,
130 rte_memory_order_acquire);
131 do {
132 /* Reset n to the initial burst count */
133 n = max;
134
135 /*
136 * A1: Establishes a synchronizing edge with R0.
137 * Ensures that other thread's memory effects on
138 * ring elements array is observed by the time
139 * this thread observes its tail update.
140 */
141 stail = rte_atomic_load_explicit(&s->tail,
142 rte_memory_order_acquire);
143
144 /* The subtraction is done between two unsigned 32bits value
145 * (the result is always modulo 32 bits even if we have
146 * *old_head > s->tail). So 'entries' is always between 0
147 * and capacity (which is < size).
148 */
149 *entries = (capacity + stail - *old_head);
150
151 /* check that we have enough room in ring */
152 if (unlikely(n > *entries))
153 n = (behavior == RTE_RING_QUEUE_FIXED) ?
154 0 : *entries;
155
156 if (n == 0)
157 return 0;
158
159 *new_head = *old_head + n;
160 /* on failure, *old_head is updated */
161 /*
162 * R1/A2.
163 * R1: Establishes a synchronizing edge with A0 of a
164 * different thread.
165 * A2: Establishes a synchronizing edge with R1 of a
166 * different thread to observe same value for stail
167 * observed by that thread on CAS failure (to retry
168 * with an updated *old_head).
169 */
170 success = rte_atomic_compare_exchange_strong_explicit(
171 &d->head, old_head, *new_head,
172 rte_memory_order_release,
173 rte_memory_order_acquire);
174 } while (unlikely(!success));
175 return n;
176}
177
178#endif /* _RTE_RING_C11_PVT_H_ */
#define unlikely(x)
#define __rte_always_inline
Definition: rte_common.h:490
rte_ring_queue_behavior
Definition: rte_ring_core.h:40
@ RTE_RING_QUEUE_FIXED
Definition: rte_ring_core.h:42