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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 Copyright (c) 2012 Eliot Dresselhaus
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:
26 The above copyright notice and this permission notice shall be
27 included in all copies or substantial portions of the Software.
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.
38 #ifndef included_clib_smp_vec_h
39 #define included_clib_smp_vec_h
41 #include <vppinfra/smp.h>
43 #define foreach_clib_smp_fifo_data_state \
50 #define _(f) CLIB_SMP_FIFO_DATA_STATE_##f,
51 foreach_clib_smp_fifo_data_state
53 CLIB_SMP_FIFO_N_DATA_STATE,
54 } clib_smp_fifo_data_state_t;
56 /* Footer at end of each data element. */
58 /* Magic number marking valid footer plus state encoded in low bits. */
60 } clib_smp_fifo_data_footer_t;
62 #define CLIB_SMP_DATA_FOOTER_MAGIC 0xfafbfcf0
64 always_inline clib_smp_fifo_data_state_t
65 clib_smp_fifo_data_footer_get_state (clib_smp_fifo_data_footer_t * f)
67 u32 s = f->magic_state - CLIB_SMP_DATA_FOOTER_MAGIC;
69 /* Check that magic number plus state is still valid. */
70 if (s >= CLIB_SMP_FIFO_N_DATA_STATE)
77 clib_smp_fifo_data_footer_set_state (clib_smp_fifo_data_footer_t * f,
78 clib_smp_fifo_data_state_t s)
79 { f->magic_state = CLIB_SMP_DATA_FOOTER_MAGIC + s; }
82 /* Read/write indices each on their own cache line.
83 Atomic incremented for each read/write. */
84 u32 read_index, write_index;
86 /* Power of 2 number of elements in fifo less one. */
87 u32 max_n_elts_less_one;
92 /* Cache aligned data. */
96 /* External functions. */
97 clib_smp_fifo_t * clib_smp_fifo_init (uword max_n_elts, uword n_bytes_per_elt);
99 /* Elements are always cache-line sized; this is to avoid smp cache thrashing. */
101 clib_smp_fifo_round_elt_bytes (uword n_bytes_per_elt)
102 { return round_pow2 (n_bytes_per_elt, CLIB_CACHE_LINE_BYTES); }
105 clib_smp_fifo_n_elts (clib_smp_fifo_t * f)
107 uword n = f->write_index - f->read_index;
108 ASSERT (n <= f->max_n_elts_less_one + 1);
112 always_inline clib_smp_fifo_data_footer_t *
113 clib_smp_fifo_get_data_footer (void * d, uword n_bytes_per_elt)
115 clib_smp_fifo_data_footer_t * f;
116 f = d + clib_smp_fifo_round_elt_bytes (n_bytes_per_elt) - sizeof (f[0]);
121 clib_smp_fifo_elt_at_index (clib_smp_fifo_t * f, uword n_bytes_per_elt, uword i)
123 uword n_bytes_per_elt_cache_aligned;
125 ASSERT (i <= f->max_n_elts_less_one);
127 n_bytes_per_elt_cache_aligned = clib_smp_fifo_round_elt_bytes (n_bytes_per_elt);
129 return f->data + i * n_bytes_per_elt_cache_aligned;
133 clib_smp_fifo_write_alloc (clib_smp_fifo_t * f, uword n_bytes_per_elt)
136 clib_smp_fifo_data_footer_t * t;
137 clib_smp_fifo_data_state_t s;
140 wi0 = f->write_index;
143 if (wi0 - f->read_index > f->max_n_elts_less_one)
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);
153 s = clib_smp_fifo_data_footer_get_state (t);
154 if (s != CLIB_SMP_FIFO_DATA_STATE_free)
160 wi1 = clib_smp_compare_and_swap (&f->write_index, wi1, wi0);
164 clib_smp_fifo_data_footer_set_state (t, CLIB_SMP_FIFO_DATA_STATE_write_alloc);
168 /* Other cpu wrote write index first: try again. */
176 clib_smp_fifo_write_done (clib_smp_fifo_t * f, void * d, uword n_bytes_per_elt)
178 clib_smp_fifo_data_footer_t * t;
180 /* Flush out pending writes before we change state to write_done.
181 This will hold off readers until data is flushed. */
182 CLIB_MEMORY_BARRIER ();
184 t = clib_smp_fifo_get_data_footer (d, n_bytes_per_elt);
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);
191 clib_smp_fifo_read_fetch (clib_smp_fifo_t * f, uword n_bytes_per_elt)
194 clib_smp_fifo_data_footer_t * t;
195 clib_smp_fifo_data_state_t s;
201 if (f->write_index - ri0 == 0)
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);
211 s = clib_smp_fifo_data_footer_get_state (t);
212 if (s != CLIB_SMP_FIFO_DATA_STATE_write_done)
218 ri1 = clib_smp_compare_and_swap (&f->read_index, ri1, ri0);
221 clib_smp_fifo_data_footer_set_state (t, CLIB_SMP_FIFO_DATA_STATE_read_fetch);
232 clib_smp_fifo_read_done (clib_smp_fifo_t * f, void * d, uword n_bytes_per_elt)
234 clib_smp_fifo_data_footer_t * t;
236 t = clib_smp_fifo_get_data_footer (d, n_bytes_per_elt);
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);
243 clib_smp_fifo_memcpy (uword * dst, uword * src, uword n_bytes)
245 word n_bytes_left = n_bytes;
247 while (n_bytes_left >= 4 * sizeof (uword))
255 n_bytes_left -= 4 * sizeof (dst[0]);
258 while (n_bytes_left > 0)
263 n_bytes_left -= 1 * sizeof (dst[0]);
268 clib_smp_fifo_write_inline (clib_smp_fifo_t * f, void * elt_to_write, uword n_bytes_per_elt)
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);
277 clib_smp_fifo_read_inline (clib_smp_fifo_t * f, void * elt_to_read, uword n_bytes_per_elt)
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);
285 #endif /* included_clib_smp_vec_h */