DPDK  18.05.1
rte_ring_c11_mem.h
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  * All rights reserved.
6  * Derived from FreeBSD's bufring.h
7  * Used as BSD-3 Licensed with permission from Kip Macy.
8  */
9 
10 #ifndef _RTE_RING_C11_MEM_H_
11 #define _RTE_RING_C11_MEM_H_
12 
13 static __rte_always_inline void
14 update_tail(struct rte_ring_headtail *ht, uint32_t old_val, uint32_t new_val,
15  uint32_t single, uint32_t enqueue)
16 {
17  RTE_SET_USED(enqueue);
18 
19  /*
20  * If there are other enqueues/dequeues in progress that preceded us,
21  * we need to wait for them to complete
22  */
23  if (!single)
24  while (unlikely(ht->tail != old_val))
25  rte_pause();
26 
27  __atomic_store_n(&ht->tail, new_val, __ATOMIC_RELEASE);
28 }
29 
53 static __rte_always_inline unsigned int
54 __rte_ring_move_prod_head(struct rte_ring *r, unsigned int is_sp,
55  unsigned int n, enum rte_ring_queue_behavior behavior,
56  uint32_t *old_head, uint32_t *new_head,
57  uint32_t *free_entries)
58 {
59  const uint32_t capacity = r->capacity;
60  unsigned int max = n;
61  int success;
62 
63  do {
64  /* Reset n to the initial burst count */
65  n = max;
66 
67  *old_head = __atomic_load_n(&r->prod.head,
68  __ATOMIC_ACQUIRE);
69 
70  /*
71  * The subtraction is done between two unsigned 32bits value
72  * (the result is always modulo 32 bits even if we have
73  * *old_head > cons_tail). So 'free_entries' is always between 0
74  * and capacity (which is < size).
75  */
76  *free_entries = (capacity + r->cons.tail - *old_head);
77 
78  /* check that we have enough room in ring */
79  if (unlikely(n > *free_entries))
80  n = (behavior == RTE_RING_QUEUE_FIXED) ?
81  0 : *free_entries;
82 
83  if (n == 0)
84  return 0;
85 
86  *new_head = *old_head + n;
87  if (is_sp)
88  r->prod.head = *new_head, success = 1;
89  else
90  success = __atomic_compare_exchange_n(&r->prod.head,
91  old_head, *new_head,
92  0, __ATOMIC_ACQUIRE,
93  __ATOMIC_RELAXED);
94  } while (unlikely(success == 0));
95  return n;
96 }
97 
121 static __rte_always_inline unsigned int
122 __rte_ring_move_cons_head(struct rte_ring *r, int is_sc,
123  unsigned int n, enum rte_ring_queue_behavior behavior,
124  uint32_t *old_head, uint32_t *new_head,
125  uint32_t *entries)
126 {
127  unsigned int max = n;
128  int success;
129 
130  /* move cons.head atomically */
131  do {
132  /* Restore n as it may change every loop */
133  n = max;
134  *old_head = __atomic_load_n(&r->cons.head,
135  __ATOMIC_ACQUIRE);
136 
137  /* The subtraction is done between two unsigned 32bits value
138  * (the result is always modulo 32 bits even if we have
139  * cons_head > prod_tail). So 'entries' is always between 0
140  * and size(ring)-1.
141  */
142  *entries = (r->prod.tail - *old_head);
143 
144  /* Set the actual entries for dequeue */
145  if (n > *entries)
146  n = (behavior == RTE_RING_QUEUE_FIXED) ? 0 : *entries;
147 
148  if (unlikely(n == 0))
149  return 0;
150 
151  *new_head = *old_head + n;
152  if (is_sc)
153  r->cons.head = *new_head, success = 1;
154  else
155  success = __atomic_compare_exchange_n(&r->cons.head,
156  old_head, *new_head,
157  0, __ATOMIC_ACQUIRE,
158  __ATOMIC_RELAXED);
159  } while (unlikely(success == 0));
160  return n;
161 }
162 
163 #endif /* _RTE_RING_C11_MEM_H_ */