CNDP  22.08.0
cne_ring_elem.h
Go to the documentation of this file.
1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright (c) 2019 Arm Limited
4  * Copyright (c) 2010-2022 Intel Corporation
5  * Copyright (c) 2007-2009 Kip Macy kmacy@freebsd.org
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 _CNE_RING_ELEM_H_
12 #define _CNE_RING_ELEM_H_
13 
19 #ifdef __cplusplus
20 extern "C" {
21 #endif
22 
23 #include <stdio.h>
24 #include <stdint.h>
25 #include <string.h>
26 #include <sys/queue.h>
27 #include <errno.h>
28 #include <cne_common.h>
29 #include <cne_branch_prediction.h>
30 
31 #include "ring_private.h"
32 
33 static __cne_always_inline void
34 __cne_ring_enqueue_elems_32(struct cne_ring *r, const uint32_t size, uint32_t idx,
35  const void *obj_table, uint32_t n)
36 {
37  unsigned int i;
38  uint32_t *ring = (uint32_t *)&r[1];
39  const uint32_t *obj = (const uint32_t *)obj_table;
40  if (likely(idx + n < size)) {
41  for (i = 0; i < (n & ~0x7); i += 8, idx += 8) {
42  ring[idx] = obj[i];
43  ring[idx + 1] = obj[i + 1];
44  ring[idx + 2] = obj[i + 2];
45  ring[idx + 3] = obj[i + 3];
46  ring[idx + 4] = obj[i + 4];
47  ring[idx + 5] = obj[i + 5];
48  ring[idx + 6] = obj[i + 6];
49  ring[idx + 7] = obj[i + 7];
50  }
51  switch (n & 0x7) {
52  case 7:
53  ring[idx++] = obj[i++]; /* fallthrough */
54  case 6:
55  ring[idx++] = obj[i++]; /* fallthrough */
56  case 5:
57  ring[idx++] = obj[i++]; /* fallthrough */
58  case 4:
59  ring[idx++] = obj[i++]; /* fallthrough */
60  case 3:
61  ring[idx++] = obj[i++]; /* fallthrough */
62  case 2:
63  ring[idx++] = obj[i++]; /* fallthrough */
64  case 1:
65  ring[idx++] = obj[i++]; /* fallthrough */
66  }
67  } else {
68  for (i = 0; idx < size; i++, idx++)
69  ring[idx] = obj[i];
70  /* Start at the beginning */
71  for (idx = 0; i < n; i++, idx++)
72  ring[idx] = obj[i];
73  }
74 }
75 
76 static __cne_always_inline void
77 __cne_ring_enqueue_elems_64(struct cne_ring *r, uint32_t prod_head, const void *obj_table,
78  uint32_t n)
79 {
80  unsigned int i;
81  const uint32_t size = r->size;
82  uint32_t idx = prod_head & r->mask;
83  uint64_t *ring = (uint64_t *)&r[1];
84  const unaligned_uint64_t *obj = (const unaligned_uint64_t *)obj_table;
85  if (likely(idx + n < size)) {
86  for (i = 0; i < (n & ~0x3); i += 4, idx += 4) {
87  ring[idx] = obj[i];
88  ring[idx + 1] = obj[i + 1];
89  ring[idx + 2] = obj[i + 2];
90  ring[idx + 3] = obj[i + 3];
91  }
92  switch (n & 0x3) {
93  case 3:
94  ring[idx++] = obj[i++]; /* fallthrough */
95  case 2:
96  ring[idx++] = obj[i++]; /* fallthrough */
97  case 1:
98  ring[idx++] = obj[i++];
99  }
100  } else {
101  for (i = 0; idx < size; i++, idx++)
102  ring[idx] = obj[i];
103  /* Start at the beginning */
104  for (idx = 0; i < n; i++, idx++)
105  ring[idx] = obj[i];
106  }
107 }
108 
109 /* The actual enqueue of elements on the ring.
110  * Placed here since identical code needed in both
111  * single and multi producer enqueue functions.
112  */
113 static __cne_always_inline void
114 __cne_ring_enqueue_elems(struct cne_ring *r, uint32_t prod_head, const void *obj_table,
115  uint32_t esize, uint32_t num)
116 {
117  /* 8B copies implemented individually to retain
118  * the current performance.
119  */
120  if (esize == 8)
121  __cne_ring_enqueue_elems_64(r, prod_head, obj_table, num);
122  else {
123  uint32_t idx, scale, nr_idx, nr_num, nr_size;
124 
125  /* Normalize to uint32_t */
126  scale = esize / sizeof(uint32_t);
127  nr_num = num * scale;
128  idx = prod_head & r->mask;
129  nr_idx = idx * scale;
130  nr_size = r->size * scale;
131  __cne_ring_enqueue_elems_32(r, nr_size, nr_idx, obj_table, nr_num);
132  }
133 }
134 
135 static __cne_always_inline void
136 __cne_ring_dequeue_elems_32(struct cne_ring *r, const uint32_t size, uint32_t idx, void *obj_table,
137  uint32_t n)
138 {
139  unsigned int i;
140  uint32_t *ring = (uint32_t *)&r[1];
141  uint32_t *obj = (uint32_t *)obj_table;
142  if (likely(idx + n < size)) {
143  for (i = 0; i < (n & ~0x7); i += 8, idx += 8) {
144  obj[i] = ring[idx];
145  obj[i + 1] = ring[idx + 1];
146  obj[i + 2] = ring[idx + 2];
147  obj[i + 3] = ring[idx + 3];
148  obj[i + 4] = ring[idx + 4];
149  obj[i + 5] = ring[idx + 5];
150  obj[i + 6] = ring[idx + 6];
151  obj[i + 7] = ring[idx + 7];
152  }
153  switch (n & 0x7) {
154  case 7:
155  obj[i++] = ring[idx++]; /* fallthrough */
156  case 6:
157  obj[i++] = ring[idx++]; /* fallthrough */
158  case 5:
159  obj[i++] = ring[idx++]; /* fallthrough */
160  case 4:
161  obj[i++] = ring[idx++]; /* fallthrough */
162  case 3:
163  obj[i++] = ring[idx++]; /* fallthrough */
164  case 2:
165  obj[i++] = ring[idx++]; /* fallthrough */
166  case 1:
167  obj[i++] = ring[idx++]; /* fallthrough */
168  }
169  } else {
170  for (i = 0; idx < size; i++, idx++)
171  obj[i] = ring[idx];
172  /* Start at the beginning */
173  for (idx = 0; i < n; i++, idx++)
174  obj[i] = ring[idx];
175  }
176 }
177 
178 static __cne_always_inline void
179 __cne_ring_dequeue_elems_64(struct cne_ring *r, uint32_t prod_head, void *obj_table, uint32_t n)
180 {
181  unsigned int i;
182  const uint32_t size = r->size;
183  uint32_t idx = prod_head & r->mask;
184  uint64_t *ring = (uint64_t *)&r[1];
185  unaligned_uint64_t *obj = (unaligned_uint64_t *)obj_table;
186  if (likely(idx + n < size)) {
187  for (i = 0; i < (n & ~0x3); i += 4, idx += 4) {
188  obj[i] = ring[idx];
189  obj[i + 1] = ring[idx + 1];
190  obj[i + 2] = ring[idx + 2];
191  obj[i + 3] = ring[idx + 3];
192  }
193  switch (n & 0x3) {
194  case 3:
195  obj[i++] = ring[idx++]; /* fallthrough */
196  case 2:
197  obj[i++] = ring[idx++]; /* fallthrough */
198  case 1:
199  obj[i++] = ring[idx++]; /* fallthrough */
200  }
201  } else {
202  for (i = 0; idx < size; i++, idx++)
203  obj[i] = ring[idx];
204  /* Start at the beginning */
205  for (idx = 0; i < n; i++, idx++)
206  obj[i] = ring[idx];
207  }
208 }
209 
210 /* The actual dequeue of elements from the ring.
211  * Placed here since identical code needed in both
212  * single and multi producer enqueue functions.
213  */
214 static __cne_always_inline void
215 __cne_ring_dequeue_elems(struct cne_ring *r, uint32_t cons_head, void *obj_table, uint32_t esize,
216  uint32_t num)
217 {
218  /* 8B copies implemented individually to retain
219  * the current performance.
220  */
221  if (esize == 8)
222  __cne_ring_dequeue_elems_64(r, cons_head, obj_table, num);
223  else {
224  uint32_t idx, scale, nr_idx, nr_num, nr_size;
225 
226  /* Normalize to uint32_t */
227  scale = esize / sizeof(uint32_t);
228  nr_num = num * scale;
229  idx = cons_head & r->mask;
230  nr_idx = idx * scale;
231  nr_size = r->size * scale;
232  __cne_ring_dequeue_elems_32(r, nr_size, nr_idx, obj_table, nr_num);
233  }
234 }
235 
236 #include "cne_ring_generic.h"
237 
262 static __cne_always_inline unsigned int
263 __cne_ring_do_enqueue_elem(struct cne_ring *r, const void *obj_table, unsigned int esize,
264  unsigned int n, enum cne_ring_queue_behavior behavior,
265  unsigned int is_sp, unsigned int *free_space)
266 {
267  uint32_t prod_head, prod_next;
268  uint32_t free_entries;
269 
270  n = __cne_ring_move_prod_head(r, is_sp, n, behavior, &prod_head, &prod_next, &free_entries);
271  if (n == 0)
272  goto end;
273 
274  __cne_ring_enqueue_elems(r, prod_head, obj_table, esize, n);
275 
276  update_tail(&r->prod, prod_head, prod_next, is_sp);
277 end:
278  if (free_space != NULL)
279  *free_space = free_entries - n;
280  return n;
281 }
282 
307 static __cne_always_inline unsigned int
308 __cne_ring_do_dequeue_elem(struct cne_ring *r, void *obj_table, unsigned int esize, unsigned int n,
309  enum cne_ring_queue_behavior behavior, unsigned int is_sc,
310  unsigned int *available)
311 {
312  uint32_t cons_head, cons_next;
313  uint32_t entries;
314 
315  n = __cne_ring_move_cons_head(r, (int)is_sc, n, behavior, &cons_head, &cons_next, &entries);
316  if (n == 0)
317  goto end;
318 
319  __cne_ring_dequeue_elems(r, cons_head, obj_table, esize, n);
320 
321  update_tail(&r->cons, cons_head, cons_next, is_sc);
322 
323 end:
324  if (available != NULL)
325  *available = entries - n;
326  return n;
327 }
328 
329 #ifdef __cplusplus
330 }
331 #endif
332 
333 #endif /* _CNE_RING_ELEM_H_ */
#define likely(x)
#define __cne_always_inline
Definition: cne_common.h:218