Initial commit of tldk code.
[tldk.git] / lib / libtle_udp / tle_event.h
diff --git a/lib/libtle_udp/tle_event.h b/lib/libtle_udp/tle_event.h
new file mode 100644 (file)
index 0000000..1a5c436
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2016  Intel Corporation.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _SEV_IMPL_H_
+#define _SEV_IMPL_H_
+
+#include <rte_common.h>
+#include <rte_spinlock.h>
+#include <rte_atomic.h>
+#include <sys/queue.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct tle_evq;
+
+/**
+ * Possible states of the event.
+ */
+enum tle_ev_state {
+       TLE_SEV_IDLE,
+       TLE_SEV_DOWN,
+       TLE_SEV_UP,
+       TLE_SEV_NUM
+};
+
+struct tle_event {
+       TAILQ_ENTRY(tle_event) ql;
+       struct tle_evq *head;
+       const void *data;
+       enum tle_ev_state state;
+} __rte_cache_aligned;
+
+struct tle_evq {
+       rte_spinlock_t lock;
+       uint32_t nb_events;
+       uint32_t nb_armed;
+       uint32_t nb_free;
+       TAILQ_HEAD(, tle_event) armed;
+       TAILQ_HEAD(, tle_event) free;
+       struct tle_event events[0];
+};
+
+/**
+ * event queue creation parameters.
+ */
+struct tle_evq_param {
+       int32_t socket_id;    /**< socket ID to allocate memory from. */
+       uint32_t max_events;  /**< max number of events in queue. */
+};
+
+/**
+ * create event queue.
+ * @param prm
+ *   Parameters used to create and initialise the queue.
+ * @return
+ *   Pointer to new event queue structure,
+ *   or NULL on error, with error code set in rte_errno.
+ *   Possible rte_errno errors include:
+ *   - EINVAL - invalid parameter passed to function
+ *   - ENOMEM - out of memory
+ */
+struct tle_evq *tle_evq_create(const struct tle_evq_param *prm);
+
+/**
+ * Destroy given event queue.
+ *
+ * @param evq
+ *   event queue to destroy
+ */
+void tle_evq_destroy(struct tle_evq *evq);
+
+/**
+ * allocate a new event within given event queue.
+ * @param evq
+ *    event queue to allocate a new stream within.
+ * @param data
+ *   User data to be associated with that event.
+ * @return
+ *   Pointer to event structure that can be used in future tle_event API calls,
+ *   or NULL on error, with error code set in rte_errno.
+ *   Possible rte_errno errors include:
+ *   - EINVAL - invalid parameter passed to function
+ *   - ENOMEM - max limit of allocated events reached for that context
+ */
+struct tle_event *tle_event_alloc(struct tle_evq *evq, const void *data);
+
+/**
+ * free an allocated event.
+ * @param ev
+ *   Pointer to the event to free.
+ */
+void tle_event_free(struct tle_event *ev);
+
+
+/**
+ * move event from DOWN to UP state.
+ * @param ev
+ *   Pointer to the event.
+ */
+static inline void
+tle_event_raise(struct tle_event *ev)
+{
+       struct tle_evq *q;
+
+       if (ev->state != TLE_SEV_DOWN)
+               return;
+
+       q = ev->head;
+       rte_compiler_barrier();
+
+       rte_spinlock_lock(&q->lock);
+       if (ev->state == TLE_SEV_DOWN) {
+               ev->state = TLE_SEV_UP;
+               TAILQ_INSERT_TAIL(&q->armed, ev, ql);
+               q->nb_armed++;
+       }
+       rte_spinlock_unlock(&q->lock);
+}
+
+/**
+ * move event from UP to DOWN state.
+ * @param ev
+ *   Pointer to the event.
+ */
+static inline void
+tle_event_down(struct tle_event *ev)
+{
+       struct tle_evq *q;
+
+       if (ev->state != TLE_SEV_UP)
+               return;
+
+       q = ev->head;
+       rte_compiler_barrier();
+
+       rte_spinlock_lock(&q->lock);
+       if (ev->state == TLE_SEV_UP) {
+               ev->state = TLE_SEV_DOWN;
+               TAILQ_REMOVE(&q->armed, ev, ql);
+               q->nb_armed--;
+       }
+       rte_spinlock_unlock(&q->lock);
+}
+
+/**
+ * move from IDLE to DOWN/UP state.
+ * @param ev
+ *   Pointer to the event.
+ * @param st
+ *   new state for the event.
+ */
+static inline void
+tle_event_active(struct tle_event *ev, enum tle_ev_state st)
+{
+       struct tle_evq *q;
+
+       if (st == ev->state)
+               return;
+
+       q = ev->head;
+       rte_compiler_barrier();
+
+       rte_spinlock_lock(&q->lock);
+       if (st > ev->state) {
+               if (st == TLE_SEV_UP) {
+                       TAILQ_INSERT_TAIL(&q->armed, ev, ql);
+                       q->nb_armed++;
+               }
+               ev->state = st;
+       }
+       rte_spinlock_unlock(&q->lock);
+}
+
+/**
+ * move event IDLE state.
+ * @param ev
+ *   Pointer to the event.
+ */
+static inline void
+tle_event_idle(struct tle_event *ev)
+{
+       struct tle_evq *q;
+
+       if (ev->state == TLE_SEV_IDLE)
+               return;
+
+       q = ev->head;
+       rte_compiler_barrier();
+
+       rte_spinlock_lock(&q->lock);
+       if (ev->state == TLE_SEV_UP) {
+               TAILQ_REMOVE(&q->armed, ev, ql);
+               q->nb_armed--;
+       }
+       ev->state = TLE_SEV_IDLE;
+       rte_spinlock_unlock(&q->lock);
+}
+
+
+/*
+ * return up to *num* user data pointers associated with
+ * the events that were in the UP state.
+ * Each retrieved event is automatically moved into the DOWN state.
+ * @param evq
+ *   event queue to retrieve events from.
+ * @param evd
+ *   An array of user data pointers associated with the events retrieved.
+ *   It must be large enough to store up to *num* pointers in it.
+ * @param num
+ *   Number of elements in the *evd* array.
+ * @return
+ *   number of of entries filled inside *evd* array.
+ */
+static inline int32_t
+tle_evq_get(struct tle_evq *evq, const void *evd[], uint32_t num)
+{
+       uint32_t i, n;
+       struct tle_event *ev;
+
+       if (evq->nb_armed == 0)
+               return 0;
+
+       rte_compiler_barrier();
+
+       rte_spinlock_lock(&evq->lock);
+       n = RTE_MIN(num, evq->nb_armed);
+       for (i = 0; i != n; i++) {
+               ev = TAILQ_FIRST(&evq->armed);
+               ev->state = TLE_SEV_DOWN;
+               TAILQ_REMOVE(&evq->armed, ev, ql);
+               evd[i] = ev->data;
+       }
+       evq->nb_armed -= n;
+       rte_spinlock_unlock(&evq->lock);
+       return n;
+}
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SEV_IMPL_H_ */