DPDK  26.07.0
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 
48 static __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 
111 static __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 __rte_always_inline
Definition: rte_common.h:506
rte_ring_queue_behavior
Definition: rte_ring_core.h:40
#define unlikely(x)
uint32_t capacity