blob: b6a8b8f5c3bb14ebeee7916e9527cec9f3632bc2 [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{
Damjan Mariona4a28f02022-03-17 15:46:25 +010057 return vec_header (f);
Dave Barachc3799992016-08-15 11:12:27 -040058}
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;
Damjan Marion8bea5892022-04-04 22:40:45 +020094 vec_set_len (v, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -070095 }
96}
97
98/* External resize function. */
Damjan Marion8b231fb2022-04-04 16:49:16 +020099void *_clib_fifo_resize (void *v, uword n_elts, uword align, uword elt_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700100
Damjan Marion8b231fb2022-04-04 16:49:16 +0200101#define clib_fifo_resize(f, n_elts) \
102 f = _clib_fifo_resize ((f), (n_elts), _vec_align (f, 0), _vec_elt_sz (f))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700103
104always_inline void *
Damjan Marion8b231fb2022-04-04 16:49:16 +0200105_clib_fifo_validate (void *v, uword n_elts, uword align, uword elt_bytes)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700106{
107 if (clib_fifo_free_elts (v) < n_elts)
Damjan Marion8b231fb2022-04-04 16:49:16 +0200108 v = _clib_fifo_resize (v, n_elts, align, elt_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700109 return v;
110}
111
Damjan Marion8b231fb2022-04-04 16:49:16 +0200112#define clib_fifo_validate(f, n_elts) \
113 f = _clib_fifo_validate ((f), (n_elts), _vec_align (f, 0), _vec_elt_sz (f))
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 *
Damjan Marion8b231fb2022-04-04 16:49:16 +0200117_clib_fifo_advance_tail (void *v, word n_elts, uword align, uword elt_bytes,
118 uword *tail_return)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700119{
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 {
Damjan Marion8b231fb2022-04-04 16:49:16 +0200126 v = _clib_fifo_resize (v, n_elts, align, elt_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700127 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
Damjan Marion8b231fb2022-04-04 16:49:16 +0200161#define clib_fifo_advance_tail(f, n_elts) \
162 ({ \
163 uword _i; \
164 (f) = _clib_fifo_advance_tail ((f), (n_elts), _vec_align (f, 0), \
165 _vec_elt_sz (f), &_i); \
166 (f) + _i; \
167 })
Ed Warnickecb9cada2015-12-08 15:45:58 -0700168
169always_inline uword
Dave Barachc3799992016-08-15 11:12:27 -0400170clib_fifo_advance_head (void *v, uword n_elts)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700171{
Dave Barachc3799992016-08-15 11:12:27 -0400172 clib_fifo_header_t *f;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700173 uword l, i, n;
174
175 ASSERT (clib_fifo_elts (v) >= n_elts);
176 f = clib_fifo_header (v);
177 l = _clib_fifo_len (v);
178
179 /* If fifo was full, restore tail pointer. */
180 if (f->tail_index == f->head_index + l)
181 f->tail_index = f->head_index;
182
183 n = i = f->head_index;
184 n += n_elts;
185 n = n >= l ? n - l : n;
186 ASSERT (n < l);
187 f->head_index = n;
188
189 return i;
190}
191
192/* Add given element to fifo. */
Damjan Marion8b231fb2022-04-04 16:49:16 +0200193#define clib_fifo_add1(f, e) \
194 do \
195 { \
196 uword _i; \
197 (f) = _clib_fifo_advance_tail ((f), 1, _vec_align (f, 0), \
198 _vec_elt_sz (f), &_i); \
199 (f)[_i] = (e); \
200 } \
201 while (0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700202
203/* Add element to fifo; return pointer to new element. */
Damjan Marion8b231fb2022-04-04 16:49:16 +0200204#define clib_fifo_add2(f, p) \
205 do \
206 { \
207 uword _i; \
208 (f) = _clib_fifo_advance_tail ((f), 1, _vec_align (f, 0), \
209 _vec_elt_sz (f), &_i); \
210 (p) = (f) + _i; \
211 } \
212 while (0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700213
214/* Add several elements to fifo. */
Damjan Marion8b231fb2022-04-04 16:49:16 +0200215#define clib_fifo_add(f, e, n) \
216 do \
217 { \
218 uword _i, _l; \
219 word _n0, _n1; \
220 \
221 _n0 = (n); \
222 (f) = _clib_fifo_advance_tail ((f), _n0, _vec_align (f, 0), \
223 _vec_elt_sz (f), &_i); \
224 _l = clib_fifo_len (f); \
225 _n1 = _i + _n0 - _l; \
226 _n1 = _n1 < 0 ? 0 : _n1; \
227 _n0 -= _n1; \
228 clib_memcpy_fast ((f) + _i, (e), _n0 * sizeof ((f)[0])); \
229 if (_n1) \
230 clib_memcpy_fast ((f) + 0, (e) + _n0, _n1 * sizeof ((f)[0])); \
231 } \
232 while (0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700233
234/* Subtract element from fifo. */
235#define clib_fifo_sub1(f,e) \
236do { \
237 uword _i; \
238 ASSERT (clib_fifo_elts (f) >= 1); \
239 _i = clib_fifo_advance_head ((f), 1); \
240 (e) = (f)[_i]; \
241} while (0)
242
243#define clib_fifo_sub2(f,p) \
244do { \
245 uword _i; \
246 ASSERT (clib_fifo_elts (f) >= 1); \
247 _i = clib_fifo_advance_head ((f), 1); \
248 (p) = (f) + _i; \
249} while (0)
250
251always_inline uword
Dave Barachc3799992016-08-15 11:12:27 -0400252clib_fifo_head_index (void *v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700253{
Dave Barachc3799992016-08-15 11:12:27 -0400254 clib_fifo_header_t *f = clib_fifo_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700255 return v ? f->head_index : 0;
256}
257
258always_inline uword
Dave Barachc3799992016-08-15 11:12:27 -0400259clib_fifo_tail_index (void *v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700260{
Dave Barachc3799992016-08-15 11:12:27 -0400261 clib_fifo_header_t *f = clib_fifo_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700262 return v ? f->tail_index : 0;
263}
264
265#define clib_fifo_head(v) ((v) + clib_fifo_head_index (v))
266#define clib_fifo_tail(v) ((v) + clib_fifo_tail_index (v))
267
Damjan Marion05563c92022-03-17 18:29:32 +0100268#define clib_fifo_free(f) vec_free ((f))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700269
270always_inline uword
Dave Barachc3799992016-08-15 11:12:27 -0400271clib_fifo_elt_index (void *v, uword i)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700272{
Dave Barachc3799992016-08-15 11:12:27 -0400273 clib_fifo_header_t *f = clib_fifo_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700274 uword result = 0;
275
276 ASSERT (i < clib_fifo_elts (v));
277
278 if (v)
279 {
280 result = f->head_index + i;
281 if (result >= _vec_len (v))
282 result -= _vec_len (v);
283 }
284
285 return result;
286}
287
Florin Coras1413a382021-12-14 19:30:04 -0800288#define clib_fifo_elt_at_index(v, i) ((v) + (i))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700289
290#define clib_fifo_foreach(v,f,body) \
291do { \
292 uword _i, _l, _n; \
293 \
294 _i = clib_fifo_head_index (f); \
295 _l = clib_fifo_len (f); \
296 _n = clib_fifo_elts (f); \
297 while (_n > 0) \
298 { \
299 (v) = (f) + _i; \
300 do { body; } while (0); \
301 _n--; \
302 _i++; \
303 _i = _i >= _l ? 0 : _i; \
304 } \
305} while (0)
306
307#endif /* included_fifo_h */
Dave Barachc3799992016-08-15 11:12:27 -0400308
309/*
310 * fd.io coding-style-patch-verification: ON
311 *
312 * Local Variables:
313 * eval: (c-set-style "gnu")
314 * End:
315 */