FD.io VPP  v16.06
Vector Packet Processing
smp_fifo.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /*
16  Copyright (c) 2012 Eliot Dresselhaus
17 
18  Permission is hereby granted, free of charge, to any person obtaining
19  a copy of this software and associated documentation files (the
20  "Software"), to deal in the Software without restriction, including
21  without limitation the rights to use, copy, modify, merge, publish,
22  distribute, sublicense, and/or sell copies of the Software, and to
23  permit persons to whom the Software is furnished to do so, subject to
24  the following conditions:
25 
26  The above copyright notice and this permission notice shall be
27  included in all copies or substantial portions of the Software.
28 
29  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 */
37 
38 #ifndef included_clib_smp_vec_h
39 #define included_clib_smp_vec_h
40 
41 #include <vppinfra/smp.h>
42 
43 #define foreach_clib_smp_fifo_data_state \
44  _ (free) \
45  _ (write_alloc) \
46  _ (write_done) \
47  _ (read_fetch)
48 
49 typedef enum {
50 #define _(f) CLIB_SMP_FIFO_DATA_STATE_##f,
52 #undef _
55 
56 /* Footer at end of each data element. */
57 typedef struct {
58  /* Magic number marking valid footer plus state encoded in low bits. */
61 
62 #define CLIB_SMP_DATA_FOOTER_MAGIC 0xfafbfcf0
63 
66 {
68 
69  /* Check that magic number plus state is still valid. */
71  os_panic ();
72 
73  return s;
74 }
75 
76 always_inline void
80 
81 typedef struct {
82  /* Read/write indices each on their own cache line.
83  Atomic incremented for each read/write. */
84  u32 read_index, write_index;
85 
86  /* Power of 2 number of elements in fifo less one. */
88 
89  /* Log2 of above. */
91 
92  /* Cache aligned data. */
93  void * data;
95 
96 /* External functions. */
97 clib_smp_fifo_t * clib_smp_fifo_init (uword max_n_elts, uword n_bytes_per_elt);
98 
99 /* Elements are always cache-line sized; this is to avoid smp cache thrashing. */
102 { return round_pow2 (n_bytes_per_elt, CLIB_CACHE_LINE_BYTES); }
103 
106 {
107  uword n = f->write_index - f->read_index;
108  ASSERT (n <= f->max_n_elts_less_one + 1);
109  return n;
110 }
111 
113 clib_smp_fifo_get_data_footer (void * d, uword n_bytes_per_elt)
114 {
116  f = d + clib_smp_fifo_round_elt_bytes (n_bytes_per_elt) - sizeof (f[0]);
117  return f;
118 }
119 
120 always_inline void *
122 {
123  uword n_bytes_per_elt_cache_aligned;
124 
125  ASSERT (i <= f->max_n_elts_less_one);
126 
127  n_bytes_per_elt_cache_aligned = clib_smp_fifo_round_elt_bytes (n_bytes_per_elt);
128 
129  return f->data + i * n_bytes_per_elt_cache_aligned;
130 }
131 
132 always_inline void *
134 {
135  void * d;
138  u32 wi0, wi1;
139 
140  wi0 = f->write_index;
141 
142  /* Fifo full? */
143  if (wi0 - f->read_index > f->max_n_elts_less_one)
144  return 0;
145 
146  while (1)
147  {
148  wi1 = wi0 + 1;
149 
150  d = clib_smp_fifo_elt_at_index (f, n_bytes_per_elt, wi0 & f->max_n_elts_less_one);
151  t = clib_smp_fifo_get_data_footer (d, n_bytes_per_elt);
152 
154  if (s != CLIB_SMP_FIFO_DATA_STATE_free)
155  {
156  d = 0;
157  break;
158  }
159 
160  wi1 = clib_smp_compare_and_swap (&f->write_index, wi1, wi0);
161 
162  if (wi1 == wi0)
163  {
164  clib_smp_fifo_data_footer_set_state (t, CLIB_SMP_FIFO_DATA_STATE_write_alloc);
165  break;
166  }
167 
168  /* Other cpu wrote write index first: try again. */
169  wi0 = wi1;
170  }
171 
172  return d;
173 }
174 
175 always_inline void
176 clib_smp_fifo_write_done (clib_smp_fifo_t * f, void * d, uword n_bytes_per_elt)
177 {
179 
180  /* Flush out pending writes before we change state to write_done.
181  This will hold off readers until data is flushed. */
183 
184  t = clib_smp_fifo_get_data_footer (d, n_bytes_per_elt);
185 
186  ASSERT (clib_smp_fifo_data_footer_get_state (t) == CLIB_SMP_FIFO_DATA_STATE_write_alloc);
187  clib_smp_fifo_data_footer_set_state (t, CLIB_SMP_FIFO_DATA_STATE_write_done);
188 }
189 
190 always_inline void *
192 {
193  void * d;
196  u32 ri0, ri1;
197 
198  ri0 = f->read_index;
199 
200  /* Fifo empty? */
201  if (f->write_index - ri0 == 0)
202  return 0;
203 
204  while (1)
205  {
206  ri1 = ri0 + 1;
207 
208  d = clib_smp_fifo_elt_at_index (f, n_bytes_per_elt, ri0 & f->max_n_elts_less_one);
209  t = clib_smp_fifo_get_data_footer (d, n_bytes_per_elt);
210 
212  if (s != CLIB_SMP_FIFO_DATA_STATE_write_done)
213  {
214  d = 0;
215  break;
216  }
217 
218  ri1 = clib_smp_compare_and_swap (&f->read_index, ri1, ri0);
219  if (ri1 == ri0)
220  {
221  clib_smp_fifo_data_footer_set_state (t, CLIB_SMP_FIFO_DATA_STATE_read_fetch);
222  break;
223  }
224 
225  ri0 = ri1;
226  }
227 
228  return d;
229 }
230 
231 always_inline void
232 clib_smp_fifo_read_done (clib_smp_fifo_t * f, void * d, uword n_bytes_per_elt)
233 {
235 
236  t = clib_smp_fifo_get_data_footer (d, n_bytes_per_elt);
237 
238  ASSERT (clib_smp_fifo_data_footer_get_state (t) == CLIB_SMP_FIFO_DATA_STATE_read_fetch);
239  clib_smp_fifo_data_footer_set_state (t, CLIB_SMP_FIFO_DATA_STATE_free);
240 }
241 
242 always_inline void
243 clib_smp_fifo_memcpy (uword * dst, uword * src, uword n_bytes)
244 {
245  word n_bytes_left = n_bytes;
246 
247  while (n_bytes_left >= 4 * sizeof (uword))
248  {
249  dst[0] = src[0];
250  dst[1] = src[1];
251  dst[2] = src[2];
252  dst[3] = src[3];
253  dst += 4;
254  src += 4;
255  n_bytes_left -= 4 * sizeof (dst[0]);
256  }
257 
258  while (n_bytes_left > 0)
259  {
260  dst[0] = src[0];
261  dst += 1;
262  src += 1;
263  n_bytes_left -= 1 * sizeof (dst[0]);
264  }
265 }
266 
267 always_inline void
268 clib_smp_fifo_write_inline (clib_smp_fifo_t * f, void * elt_to_write, uword n_bytes_per_elt)
269 {
270  uword * dst;
271  dst = clib_smp_fifo_write_alloc (f, n_bytes_per_elt);
272  clib_smp_fifo_memcpy (dst, elt_to_write, n_bytes_per_elt);
273  clib_smp_fifo_write_done (f, dst, n_bytes_per_elt);
274 }
275 
276 always_inline void
277 clib_smp_fifo_read_inline (clib_smp_fifo_t * f, void * elt_to_read, uword n_bytes_per_elt)
278 {
279  uword * src;
280  src = clib_smp_fifo_read_fetch (f, n_bytes_per_elt);
281  clib_smp_fifo_memcpy (elt_to_read, src, n_bytes_per_elt);
282  clib_smp_fifo_read_done (f, src, n_bytes_per_elt);
283 }
284 
285 #endif /* included_clib_smp_vec_h */
always_inline uword round_pow2(uword x, uword pow2)
Definition: clib.h:255
#define clib_smp_compare_and_swap(addr, new, old)
Definition: smp.h:108
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:267
always_inline void clib_smp_fifo_write_inline(clib_smp_fifo_t *f, void *elt_to_write, uword n_bytes_per_elt)
Definition: smp_fifo.h:268
always_inline void clib_smp_fifo_read_inline(clib_smp_fifo_t *f, void *elt_to_read, uword n_bytes_per_elt)
Definition: smp_fifo.h:277
clib_smp_fifo_t * clib_smp_fifo_init(uword max_n_elts, uword n_bytes_per_elt)
Definition: smp_fifo.c:41
always_inline void * clib_smp_fifo_elt_at_index(clib_smp_fifo_t *f, uword n_bytes_per_elt, uword i)
Definition: smp_fifo.h:121
void os_panic(void)
Definition: unix-misc.c:165
always_inline void clib_smp_fifo_read_done(clib_smp_fifo_t *f, void *d, uword n_bytes_per_elt)
Definition: smp_fifo.h:232
always_inline void clib_smp_fifo_memcpy(uword *dst, uword *src, uword n_bytes)
Definition: smp_fifo.h:243
always_inline void clib_smp_fifo_write_done(clib_smp_fifo_t *f, void *d, uword n_bytes_per_elt)
Definition: smp_fifo.h:176
#define always_inline
Definition: clib.h:84
always_inline uword clib_smp_fifo_n_elts(clib_smp_fifo_t *f)
Definition: smp_fifo.h:105
always_inline void * clib_smp_fifo_read_fetch(clib_smp_fifo_t *f, uword n_bytes_per_elt)
Definition: smp_fifo.h:191
#define foreach_clib_smp_fifo_data_state
Definition: smp_fifo.h:43
always_inline void clib_smp_fifo_data_footer_set_state(clib_smp_fifo_data_footer_t *f, clib_smp_fifo_data_state_t s)
Definition: smp_fifo.h:77
clib_smp_fifo_data_state_t
Definition: smp_fifo.h:49
always_inline clib_smp_fifo_data_state_t clib_smp_fifo_data_footer_get_state(clib_smp_fifo_data_footer_t *f)
Definition: smp_fifo.h:65
void * data
Definition: smp_fifo.h:93
#define CLIB_SMP_DATA_FOOTER_MAGIC
Definition: smp_fifo.h:62
#define ASSERT(truth)
always_inline void * clib_smp_fifo_write_alloc(clib_smp_fifo_t *f, uword n_bytes_per_elt)
Definition: smp_fifo.h:133
unsigned int u32
Definition: types.h:88
u32 log2_max_n_elts
Definition: smp_fifo.h:90
always_inline uword clib_smp_fifo_round_elt_bytes(uword n_bytes_per_elt)
Definition: smp_fifo.h:101
u64 uword
Definition: types.h:112
i64 word
Definition: types.h:111
always_inline clib_smp_fifo_data_footer_t * clib_smp_fifo_get_data_footer(void *d, uword n_bytes_per_elt)
Definition: smp_fifo.h:113
#define CLIB_MEMORY_BARRIER()
Definition: clib.h:101
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
u32 max_n_elts_less_one
Definition: smp_fifo.h:87