test mbuf attach
[dpdk.git] / lib / librte_stack / rte_stack.h
index 42d0427..abf6420 100644 (file)
@@ -4,9 +4,12 @@
 
 /**
  * @file rte_stack.h
- * @b EXPERIMENTAL: this API may change without prior notice
  *
- * RTE Stack
+ * RTE Stack.
+ *
+ * @warning
+ * @b EXPERIMENTAL:
+ * All functions in this file may be changed or removed without prior notice.
  *
  * librte_stack provides an API for configuration and use of a bounded stack of
  * pointers. Push and pop operations are MT-safe, allowing concurrent access,
@@ -20,6 +23,7 @@
 extern "C" {
 #endif
 
+#include <rte_atomic.h>
 #include <rte_compat.h>
 #include <rte_debug.h>
 #include <rte_errno.h>
@@ -32,6 +36,35 @@ extern "C" {
 #define RTE_STACK_NAMESIZE (RTE_MEMZONE_NAMESIZE - \
                           sizeof(RTE_STACK_MZ_PREFIX) + 1)
 
+struct rte_stack_lf_elem {
+       void *data;                     /**< Data pointer */
+       struct rte_stack_lf_elem *next; /**< Next pointer */
+};
+
+struct rte_stack_lf_head {
+       struct rte_stack_lf_elem *top; /**< Stack top */
+       uint64_t cnt; /**< Modification counter for avoiding ABA problem */
+};
+
+struct rte_stack_lf_list {
+       /** List head */
+       struct rte_stack_lf_head head __rte_aligned(16);
+       /** List len */
+       uint64_t len;
+};
+
+/* Structure containing two lock-free LIFO lists: the stack itself and a list
+ * of free linked-list elements.
+ */
+struct rte_stack_lf {
+       /** LIFO list of elements */
+       struct rte_stack_lf_list used __rte_cache_aligned;
+       /** LIFO list of free elements */
+       struct rte_stack_lf_list free __rte_cache_aligned;
+       /** LIFO elements */
+       struct rte_stack_lf_elem elems[] __rte_cache_aligned;
+};
+
 /* Structure containing the LIFO, its current length, and a lock for mutual
  * exclusion.
  */
@@ -51,10 +84,21 @@ struct rte_stack {
        const struct rte_memzone *memzone;
        uint32_t capacity; /**< Usable size of the stack. */
        uint32_t flags; /**< Flags supplied at creation. */
-       struct rte_stack_std stack_std; /**< LIFO structure. */
+       RTE_STD_C11
+       union {
+               struct rte_stack_lf stack_lf; /**< Lock-free LIFO structure. */
+               struct rte_stack_std stack_std; /**< LIFO structure. */
+       };
 } __rte_cache_aligned;
 
+/**
+ * The stack uses lock-free push and pop functions. This flag is only
+ * supported on x86_64 platforms, currently.
+ */
+#define RTE_STACK_F_LF 0x0001
+
 #include "rte_stack_std.h"
+#include "rte_stack_lf.h"
 
 /**
  * @warning
@@ -71,13 +115,17 @@ struct rte_stack {
  * @return
  *   Actual number of objects pushed (either 0 or *n*).
  */
-static __rte_always_inline unsigned int __rte_experimental
+__rte_experimental
+static __rte_always_inline unsigned int
 rte_stack_push(struct rte_stack *s, void * const *obj_table, unsigned int n)
 {
        RTE_ASSERT(s != NULL);
        RTE_ASSERT(obj_table != NULL);
 
-       return __rte_stack_std_push(s, obj_table, n);
+       if (s->flags & RTE_STACK_F_LF)
+               return __rte_stack_lf_push(s, obj_table, n);
+       else
+               return __rte_stack_std_push(s, obj_table, n);
 }
 
 /**
@@ -95,13 +143,17 @@ rte_stack_push(struct rte_stack *s, void * const *obj_table, unsigned int n)
  * @return
  *   Actual number of objects popped (either 0 or *n*).
  */
-static __rte_always_inline unsigned int __rte_experimental
+__rte_experimental
+static __rte_always_inline unsigned int
 rte_stack_pop(struct rte_stack *s, void **obj_table, unsigned int n)
 {
        RTE_ASSERT(s != NULL);
        RTE_ASSERT(obj_table != NULL);
 
-       return __rte_stack_std_pop(s, obj_table, n);
+       if (s->flags & RTE_STACK_F_LF)
+               return __rte_stack_lf_pop(s, obj_table, n);
+       else
+               return __rte_stack_std_pop(s, obj_table, n);
 }
 
 /**
@@ -115,12 +167,16 @@ rte_stack_pop(struct rte_stack *s, void **obj_table, unsigned int n)
  * @return
  *   The number of used entries in the stack.
  */
-static __rte_always_inline unsigned int __rte_experimental
+__rte_experimental
+static __rte_always_inline unsigned int
 rte_stack_count(struct rte_stack *s)
 {
        RTE_ASSERT(s != NULL);
 
-       return __rte_stack_std_count(s);
+       if (s->flags & RTE_STACK_F_LF)
+               return __rte_stack_lf_count(s);
+       else
+               return __rte_stack_std_count(s);
 }
 
 /**
@@ -134,7 +190,8 @@ rte_stack_count(struct rte_stack *s)
  * @return
  *   The number of free entries in the stack.
  */
-static __rte_always_inline unsigned int __rte_experimental
+__rte_experimental
+static __rte_always_inline unsigned int
 rte_stack_free_count(struct rte_stack *s)
 {
        RTE_ASSERT(s != NULL);
@@ -160,7 +217,10 @@ rte_stack_free_count(struct rte_stack *s)
  *   NUMA. The value can be *SOCKET_ID_ANY* if there is no NUMA
  *   constraint for the reserved zone.
  * @param flags
- *   Reserved for future use.
+ *   An OR of the following:
+ *    - RTE_STACK_F_LF: If this flag is set, the stack uses lock-free
+ *      variants of the push and pop functions. Otherwise, it achieves
+ *      thread-safety using a lock.
  * @return
  *   On success, the pointer to the new allocated stack. NULL on error with
  *    rte_errno set appropriately. Possible errno values include:
@@ -169,7 +229,8 @@ rte_stack_free_count(struct rte_stack *s)
  *    - ENOMEM - insufficient memory to create the stack
  *    - ENAMETOOLONG - name size exceeds RTE_STACK_NAMESIZE
  */
-struct rte_stack *__rte_experimental
+__rte_experimental
+struct rte_stack *
 rte_stack_create(const char *name, unsigned int count, int socket_id,
                 uint32_t flags);
 
@@ -182,7 +243,8 @@ rte_stack_create(const char *name, unsigned int count, int socket_id,
  * @param s
  *   Stack to free
  */
-void __rte_experimental
+__rte_experimental
+void
 rte_stack_free(struct rte_stack *s);
 
 /**
@@ -199,7 +261,8 @@ rte_stack_free(struct rte_stack *s);
  *    - ENOENT - Stack with name *name* not found.
  *    - EINVAL - *name* pointer is NULL.
  */
-struct rte_stack * __rte_experimental
+__rte_experimental
+struct rte_stack *
 rte_stack_lookup(const char *name);
 
 #ifdef __cplusplus