blob: 5dc1b4512cfd4901d91346c8ccd868bb1d2a1f21 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
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) 2005 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_fifo_h
39#define included_fifo_h
40
41#include <vppinfra/cache.h>
Dave Barachc3799992016-08-15 11:12:27 -040042#include <vppinfra/error.h> /* for ASSERT */
Ed Warnickecb9cada2015-12-08 15:45:58 -070043#include <vppinfra/vec.h>
44
Dave Barachc3799992016-08-15 11:12:27 -040045typedef struct
46{
Ed Warnickecb9cada2015-12-08 15:45:58 -070047 /* First index of valid data in fifo. */
48 u32 head_index;
49
50 /* One beyond last index in fifo. */
51 u32 tail_index;
52} clib_fifo_header_t;
53
54always_inline clib_fifo_header_t *
Dave Barachc3799992016-08-15 11:12:27 -040055clib_fifo_header (void *f)
56{
57 return vec_header (f, sizeof (clib_fifo_header_t));
58}
Ed Warnickecb9cada2015-12-08 15:45:58 -070059
60/* Aliases. */
61#define clib_fifo_len(v) vec_len(v)
62#define _clib_fifo_len(v) _vec_len(v)
63#define clib_fifo_end(v) vec_end(v)
64
65always_inline uword
Dave Barachc3799992016-08-15 11:12:27 -040066clib_fifo_elts (void *v)
Ed Warnickecb9cada2015-12-08 15:45:58 -070067{
68 word l, r;
Dave Barachc3799992016-08-15 11:12:27 -040069 clib_fifo_header_t *f = clib_fifo_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -070070
Dave Barachc3799992016-08-15 11:12:27 -040071 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -070072 return 0;
73
74 l = _clib_fifo_len (v);
75 r = (word) f->tail_index - (word) f->head_index;
76 r = r < 0 ? r + l : r;
77 ASSERT (r >= 0 && r <= l);
78 return r;
79}
80
81always_inline uword
Dave Barachc3799992016-08-15 11:12:27 -040082clib_fifo_free_elts (void *v)
83{
84 return clib_fifo_len (v) - clib_fifo_elts (v);
85}
Ed Warnickecb9cada2015-12-08 15:45:58 -070086
87always_inline void
Dave Barachc3799992016-08-15 11:12:27 -040088clib_fifo_reset (void *v)
Ed Warnickecb9cada2015-12-08 15:45:58 -070089{
Dave Barachc3799992016-08-15 11:12:27 -040090 clib_fifo_header_t *f = clib_fifo_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -070091 if (v)
92 {
93 f->head_index = f->tail_index = 0;
94 _vec_len (v) = 0;
95 }
96}
97
98/* External resize function. */
Dave Barachc3799992016-08-15 11:12:27 -040099void *_clib_fifo_resize (void *v, uword n_elts, uword elt_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700100
101#define clib_fifo_resize(f,n_elts) \
102 f = _clib_fifo_resize ((f), (n_elts), sizeof ((f)[0]))
103
104always_inline void *
Dave Barachc3799992016-08-15 11:12:27 -0400105_clib_fifo_validate (void *v, uword n_elts, uword elt_bytes)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700106{
107 if (clib_fifo_free_elts (v) < n_elts)
108 v = _clib_fifo_resize (v, n_elts, elt_bytes);
109 return v;
110}
111
112#define clib_fifo_validate(f,n_elts) \
113 f = _clib_fifo_validate ((f), (n_elts), sizeof (f[0]))
Dave Barachc3799992016-08-15 11:12:27 -0400114
Ed Warnickecb9cada2015-12-08 15:45:58 -0700115/* Advance tail pointer by N_ELTS which can be either positive or negative. */
116always_inline void *
Dave Barachc3799992016-08-15 11:12:27 -0400117_clib_fifo_advance_tail (void *v, word n_elts, uword elt_bytes,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700118 uword * tail_return)
119{
120 word i, l, n_free;
Dave Barachc3799992016-08-15 11:12:27 -0400121 clib_fifo_header_t *f;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700122
123 n_free = clib_fifo_free_elts (v);
124 if (n_free < n_elts)
125 {
126 v = _clib_fifo_resize (v, n_elts, elt_bytes);
127 n_free = clib_fifo_free_elts (v);
128 }
129
130 ASSERT (n_free >= n_elts);
131 n_free -= n_elts;
132
133 f = clib_fifo_header (v);
134 l = _clib_fifo_len (v);
135 i = f->tail_index;
136
137 if (n_free == 0)
138 {
139 /* Mark fifo full. */
140 f->tail_index = f->head_index + l;
141 }
142 else
143 {
144 word n = f->tail_index + n_elts;
145 if (n >= l)
146 n -= l;
147 else if (n < 0)
148 n += l;
149 ASSERT (n >= 0 && n < l);
150 f->tail_index = n;
151 }
152
153 ASSERT (clib_fifo_free_elts (v) == n_free);
154
155 if (tail_return)
156 *tail_return = n_elts > 0 ? i : f->tail_index;
157
158 return v;
159}
160
161#define clib_fifo_advance_tail(f,n_elts) \
162({ \
163 uword _i; \
164 (f) = _clib_fifo_advance_tail ((f), (n_elts), sizeof ((f)[0]), &_i); \
165 (f) + _i; \
166})
167
168always_inline uword
Dave Barachc3799992016-08-15 11:12:27 -0400169clib_fifo_advance_head (void *v, uword n_elts)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700170{
Dave Barachc3799992016-08-15 11:12:27 -0400171 clib_fifo_header_t *f;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700172 uword l, i, n;
173
174 ASSERT (clib_fifo_elts (v) >= n_elts);
175 f = clib_fifo_header (v);
176 l = _clib_fifo_len (v);
177
178 /* If fifo was full, restore tail pointer. */
179 if (f->tail_index == f->head_index + l)
180 f->tail_index = f->head_index;
181
182 n = i = f->head_index;
183 n += n_elts;
184 n = n >= l ? n - l : n;
185 ASSERT (n < l);
186 f->head_index = n;
187
188 return i;
189}
190
191/* Add given element to fifo. */
192#define clib_fifo_add1(f,e) \
193do { \
194 uword _i; \
195 (f) = _clib_fifo_advance_tail ((f), 1, sizeof ((f)[0]), &_i); \
196 (f)[_i] = (e); \
197} while (0)
198
199/* Add element to fifo; return pointer to new element. */
200#define clib_fifo_add2(f,p) \
201do { \
202 uword _i; \
203 (f) = _clib_fifo_advance_tail ((f), 1, sizeof ((f)[0]), &_i); \
204 (p) = (f) + _i; \
205} while (0)
206
207/* Add several elements to fifo. */
208#define clib_fifo_add(f,e,n) \
209do { \
210 uword _i, _l; word _n0, _n1; \
211 \
212 _n0 = (n); \
213 (f) = _clib_fifo_advance_tail ((f), _n0, sizeof ((f)[0]), &_i); \
214 _l = clib_fifo_len (f); \
215 _n1 = _i + _n0 - _l; \
216 _n1 = _n1 < 0 ? 0 : _n1; \
217 _n0 -= _n1; \
Dave Barach178cf492018-11-13 16:34:13 -0500218 clib_memcpy_fast ((f) + _i, (e), _n0 * sizeof ((f)[0])); \
Ed Warnickecb9cada2015-12-08 15:45:58 -0700219 if (_n1) \
Dave Barach178cf492018-11-13 16:34:13 -0500220 clib_memcpy_fast ((f) + 0, (e) + _n0, _n1 * sizeof ((f)[0])); \
Ed Warnickecb9cada2015-12-08 15:45:58 -0700221} while (0)
222
223/* Subtract element from fifo. */
224#define clib_fifo_sub1(f,e) \
225do { \
226 uword _i; \
227 ASSERT (clib_fifo_elts (f) >= 1); \
228 _i = clib_fifo_advance_head ((f), 1); \
229 (e) = (f)[_i]; \
230} while (0)
231
232#define clib_fifo_sub2(f,p) \
233do { \
234 uword _i; \
235 ASSERT (clib_fifo_elts (f) >= 1); \
236 _i = clib_fifo_advance_head ((f), 1); \
237 (p) = (f) + _i; \
238} while (0)
239
240always_inline uword
Dave Barachc3799992016-08-15 11:12:27 -0400241clib_fifo_head_index (void *v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700242{
Dave Barachc3799992016-08-15 11:12:27 -0400243 clib_fifo_header_t *f = clib_fifo_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700244 return v ? f->head_index : 0;
245}
246
247always_inline uword
Dave Barachc3799992016-08-15 11:12:27 -0400248clib_fifo_tail_index (void *v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700249{
Dave Barachc3799992016-08-15 11:12:27 -0400250 clib_fifo_header_t *f = clib_fifo_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700251 return v ? f->tail_index : 0;
252}
253
254#define clib_fifo_head(v) ((v) + clib_fifo_head_index (v))
255#define clib_fifo_tail(v) ((v) + clib_fifo_tail_index (v))
256
257#define clib_fifo_free(f) vec_free_h((f),sizeof(clib_fifo_header_t))
258
259always_inline uword
Dave Barachc3799992016-08-15 11:12:27 -0400260clib_fifo_elt_index (void *v, uword i)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700261{
Dave Barachc3799992016-08-15 11:12:27 -0400262 clib_fifo_header_t *f = clib_fifo_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700263 uword result = 0;
264
265 ASSERT (i < clib_fifo_elts (v));
266
267 if (v)
268 {
269 result = f->head_index + i;
270 if (result >= _vec_len (v))
271 result -= _vec_len (v);
272 }
273
274 return result;
275}
276
277#define clib_fifo_elt_at_index(v,i) ((v) + clib_fifo_elt_index (v, (i)))
278
279#define clib_fifo_foreach(v,f,body) \
280do { \
281 uword _i, _l, _n; \
282 \
283 _i = clib_fifo_head_index (f); \
284 _l = clib_fifo_len (f); \
285 _n = clib_fifo_elts (f); \
286 while (_n > 0) \
287 { \
288 (v) = (f) + _i; \
289 do { body; } while (0); \
290 _n--; \
291 _i++; \
292 _i = _i >= _l ? 0 : _i; \
293 } \
294} while (0)
295
296#endif /* included_fifo_h */
Dave Barachc3799992016-08-15 11:12:27 -0400297
298/*
299 * fd.io coding-style-patch-verification: ON
300 *
301 * Local Variables:
302 * eval: (c-set-style "gnu")
303 * End:
304 */