tle_event.h revision aa97dd1c
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
26extern "C" {
27#endif
28
29struct tle_evq;
30
31/**
32 * Possible states of the event.
33 */
34enum tle_ev_state {
35	TLE_SEV_IDLE,
36	TLE_SEV_DOWN,
37	TLE_SEV_UP,
38	TLE_SEV_NUM
39};
40
41struct 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
48struct 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 */
61struct 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 */
77struct 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 */
85void 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 */
100struct 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 */
107void 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 */
115static inline void
116tle_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 */
140static inline void
141tle_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 */
167static inline void
168tle_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 */
194static inline void
195tle_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
214static inline void
215tle_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 */
249static inline int32_t
250tle_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_ */
279