dev: new device driver infra
[vpp.git] / src / vppinfra / ring.h
1 /*
2  * Copyright (c) 2018 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 #ifndef included_ring_h
17 #define included_ring_h
18
19 #include <vppinfra/error.h>
20 #include <vppinfra/format.h>
21 #include <vppinfra/vec.h>
22 #include <vppinfra/vector.h>
23
24 typedef struct
25 {
26   u32 next, n_enq;
27 } clib_ring_header_t;
28
29 always_inline clib_ring_header_t *
30 clib_ring_header (void *v)
31 {
32   return vec_header (v);
33 }
34
35 always_inline void
36 clib_ring_new_inline (void **p, u32 elt_bytes, u32 size, u32 align)
37 {
38   void *v;
39   clib_ring_header_t *h;
40   vec_attr_t va = { .elt_sz = elt_bytes,
41                     .hdr_sz = sizeof (clib_ring_header_t),
42                     .align = align };
43
44   v = _vec_alloc_internal (size, &va);
45
46   h = clib_ring_header (v);
47   h->next = 0;
48   h->n_enq = 0;
49   p[0] = v;
50 }
51
52 #define clib_ring_new_aligned(ring, size, align) \
53 { clib_ring_new_inline ((void **)&(ring), sizeof(ring[0]), size, align); }
54
55 #define clib_ring_new(ring, size) \
56 { clib_ring_new_inline ((void **)&(ring), sizeof(ring[0]), size, 0);}
57
58 #define clib_ring_free(f) vec_free ((f))
59
60 always_inline u32
61 clib_ring_n_enq (void *v)
62 {
63   clib_ring_header_t *h = clib_ring_header (v);
64   return h->n_enq;
65 }
66
67 always_inline void *
68 clib_ring_get_last_inline (void *v, u32 elt_bytes, int enqueue)
69 {
70   clib_ring_header_t *h = clib_ring_header (v);
71   u32 slot;
72
73   if (enqueue)
74     {
75       if (h->n_enq == _vec_len (v))
76         return 0;
77       slot = h->next;
78       h->n_enq++;
79       h->next++;
80       if (h->next == _vec_len (v))
81         h->next = 0;
82     }
83   else
84     {
85       if (h->n_enq == 0)
86         return 0;
87       slot = h->next == 0 ? _vec_len (v) - 1 : h->next - 1;
88     }
89
90   return (void *) ((u8 *) v + elt_bytes * slot);
91 }
92
93 #define clib_ring_enq(ring) \
94 clib_ring_get_last_inline (ring, sizeof(ring[0]), 1)
95
96 #define clib_ring_get_last(ring) \
97 clib_ring_get_last_inline (ring, sizeof(ring[0]), 0)
98
99 always_inline void *
100 clib_ring_get_first_inline (void *v, u32 elt_bytes, int dequeue)
101 {
102   clib_ring_header_t *h = clib_ring_header (v);
103   u32 slot;
104
105   if (h->n_enq == 0)
106     return 0;
107
108   if (h->n_enq > h->next)
109     slot = _vec_len (v) + h->next - h->n_enq;
110   else
111     slot = h->next - h->n_enq;
112
113   if (dequeue)
114     h->n_enq--;
115
116   return (void *) ((u8 *) v + elt_bytes * slot);
117 }
118
119 #define clib_ring_deq(ring) \
120 clib_ring_get_first_inline (ring, sizeof(ring[0]), 1)
121
122 #define clib_ring_get_first(ring) \
123 clib_ring_get_first_inline (ring, sizeof(ring[0]), 0)
124
125 #endif /* included_ring_h */
126
127 /*
128  * fd.io coding-style-patch-verification: ON
129  *
130  * Local Variables:
131  * eval: (c-set-style "gnu")
132  * End:
133  */