Introduce first version of TCP code.
[tldk.git] / lib / libtle_l4p / tle_event.h
1 /*
2  * Copyright (c) 2016  Intel Corporation.
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 _SEV_IMPL_H_
17 #define _SEV_IMPL_H_
18
19 #include <rte_common.h>
20 #include <rte_memory.h>
21 #include <rte_spinlock.h>
22 #include <rte_atomic.h>
23 #include <sys/queue.h>
24
25 #ifdef __cplusplus
26 extern "C" {
27 #endif
28
29 struct tle_evq;
30
31 /**
32  * Possible states of the event.
33  */
34 enum tle_ev_state {
35         TLE_SEV_IDLE,
36         TLE_SEV_DOWN,
37         TLE_SEV_UP,
38         TLE_SEV_NUM
39 };
40
41 struct tle_event {
42         TAILQ_ENTRY(tle_event) ql;
43         struct tle_evq *head;
44         const void *data;
45         enum tle_ev_state state;
46 } __rte_cache_aligned;
47
48 struct tle_evq {
49         rte_spinlock_t lock;
50         uint32_t nb_events;
51         uint32_t nb_armed;
52         uint32_t nb_free;
53         TAILQ_HEAD(, tle_event) armed;
54         TAILQ_HEAD(, tle_event) free;
55         struct tle_event events[0];
56 };
57
58 /**
59  * event queue creation parameters.
60  */
61 struct tle_evq_param {
62         int32_t socket_id;    /**< socket ID to allocate memory from. */
63         uint32_t max_events;  /**< max number of events in queue. */
64 };
65
66 /**
67  * create event queue.
68  * @param prm
69  *   Parameters used to create and initialise the queue.
70  * @return
71  *   Pointer to new event queue structure,
72  *   or NULL on error, with error code set in rte_errno.
73  *   Possible rte_errno errors include:
74  *   - EINVAL - invalid parameter passed to function
75  *   - ENOMEM - out of memory
76  */
77 struct tle_evq *tle_evq_create(const struct tle_evq_param *prm);
78
79 /**
80  * Destroy given event queue.
81  *
82  * @param evq
83  *   event queue to destroy
84  */
85 void tle_evq_destroy(struct tle_evq *evq);
86
87 /**
88  * allocate a new event within given event queue.
89  * @param evq
90  *    event queue to allocate a new stream within.
91  * @param data
92  *   User data to be associated with that event.
93  * @return
94  *   Pointer to event structure that can be used in future tle_event API calls,
95  *   or NULL on error, with error code set in rte_errno.
96  *   Possible rte_errno errors include:
97  *   - EINVAL - invalid parameter passed to function
98  *   - ENOMEM - max limit of allocated events reached for that context
99  */
100 struct tle_event *tle_event_alloc(struct tle_evq *evq, const void *data);
101
102 /**
103  * free an allocated event.
104  * @param ev
105  *   Pointer to the event to free.
106  */
107 void tle_event_free(struct tle_event *ev);
108
109
110 /**
111  * move event from DOWN to UP state.
112  * @param ev
113  *   Pointer to the event.
114  */
115 static inline void
116 tle_event_raise(struct tle_event *ev)
117 {
118         struct tle_evq *q;
119
120         if (ev->state != TLE_SEV_DOWN)
121                 return;
122
123         q = ev->head;
124         rte_compiler_barrier();
125
126         rte_spinlock_lock(&q->lock);
127         if (ev->state == TLE_SEV_DOWN) {
128                 ev->state = TLE_SEV_UP;
129                 TAILQ_INSERT_TAIL(&q->armed, ev, ql);
130                 q->nb_armed++;
131         }
132         rte_spinlock_unlock(&q->lock);
133 }
134
135 /**
136  * move event from UP to DOWN state.
137  * @param ev
138  *   Pointer to the event.
139  */
140 static inline void
141 tle_event_down(struct tle_event *ev)
142 {
143         struct tle_evq *q;
144
145         if (ev->state != TLE_SEV_UP)
146                 return;
147
148         q = ev->head;
149         rte_compiler_barrier();
150
151         rte_spinlock_lock(&q->lock);
152         if (ev->state == TLE_SEV_UP) {
153                 ev->state = TLE_SEV_DOWN;
154                 TAILQ_REMOVE(&q->armed, ev, ql);
155                 q->nb_armed--;
156         }
157         rte_spinlock_unlock(&q->lock);
158 }
159
160 /**
161  * move from IDLE to DOWN/UP state.
162  * @param ev
163  *   Pointer to the event.
164  * @param st
165  *   new state for the event.
166  */
167 static inline void
168 tle_event_active(struct tle_event *ev, enum tle_ev_state st)
169 {
170         struct tle_evq *q;
171
172         if (ev->state != TLE_SEV_IDLE)
173                 return;
174
175         q = ev->head;
176         rte_compiler_barrier();
177
178         rte_spinlock_lock(&q->lock);
179         if (st > ev->state) {
180                 if (st == TLE_SEV_UP) {
181                         TAILQ_INSERT_TAIL(&q->armed, ev, ql);
182                         q->nb_armed++;
183                 }
184                 ev->state = st;
185         }
186         rte_spinlock_unlock(&q->lock);
187 }
188
189 /**
190  * move event IDLE state.
191  * @param ev
192  *   Pointer to the event.
193  */
194 static inline void
195 tle_event_idle(struct tle_event *ev)
196 {
197         struct tle_evq *q;
198
199         if (ev->state == TLE_SEV_IDLE)
200                 return;
201
202         q = ev->head;
203         rte_compiler_barrier();
204
205         rte_spinlock_lock(&q->lock);
206         if (ev->state == TLE_SEV_UP) {
207                 TAILQ_REMOVE(&q->armed, ev, ql);
208                 q->nb_armed--;
209         }
210         ev->state = TLE_SEV_IDLE;
211         rte_spinlock_unlock(&q->lock);
212 }
213
214 static inline void
215 tle_evq_idle(struct tle_evq *evq, struct tle_event *ev[], uint32_t num)
216 {
217         uint32_t i, n;
218
219         rte_spinlock_lock(&evq->lock);
220
221         n = 0;
222         for (i = 0; i != num; i++) {
223                 if (ev[i]->state == TLE_SEV_UP) {
224                         TAILQ_REMOVE(&evq->armed, ev[i], ql);
225                         n++;
226                 }
227                 ev[i]->state = TLE_SEV_IDLE;
228         }
229
230         evq->nb_armed -= n;
231         rte_spinlock_unlock(&evq->lock);
232 }
233
234
235 /*
236  * return up to *num* user data pointers associated with
237  * the events that were in the UP state.
238  * Each retrieved event is automatically moved into the DOWN state.
239  * @param evq
240  *   event queue to retrieve events from.
241  * @param evd
242  *   An array of user data pointers associated with the events retrieved.
243  *   It must be large enough to store up to *num* pointers in it.
244  * @param num
245  *   Number of elements in the *evd* array.
246  * @return
247  *   number of of entries filled inside *evd* array.
248  */
249 static inline int32_t
250 tle_evq_get(struct tle_evq *evq, const void *evd[], uint32_t num)
251 {
252         uint32_t i, n;
253         struct tle_event *ev;
254
255         if (evq->nb_armed == 0)
256                 return 0;
257
258         rte_compiler_barrier();
259
260         rte_spinlock_lock(&evq->lock);
261         n = RTE_MIN(num, evq->nb_armed);
262         for (i = 0; i != n; i++) {
263                 ev = TAILQ_FIRST(&evq->armed);
264                 ev->state = TLE_SEV_DOWN;
265                 TAILQ_REMOVE(&evq->armed, ev, ql);
266                 evd[i] = ev->data;
267         }
268         evq->nb_armed -= n;
269         rte_spinlock_unlock(&evq->lock);
270         return n;
271 }
272
273
274 #ifdef __cplusplus
275 }
276 #endif
277
278 #endif /* _SEV_IMPL_H_ */