14418919fSjohnjiang /* SPDX-License-Identifier: BSD-3-Clause
24418919fSjohnjiang * Copyright(c) 2019 Intel Corporation
34418919fSjohnjiang */
44418919fSjohnjiang
54418919fSjohnjiang /**
64418919fSjohnjiang * @file rte_stack.h
74418919fSjohnjiang *
8*0c6bd470Sfengbojiang * RTE Stack.
9*0c6bd470Sfengbojiang *
104418919fSjohnjiang * librte_stack provides an API for configuration and use of a bounded stack of
114418919fSjohnjiang * pointers. Push and pop operations are MT-safe, allowing concurrent access,
124418919fSjohnjiang * and the interface supports pushing and popping multiple pointers at a time.
134418919fSjohnjiang */
144418919fSjohnjiang
154418919fSjohnjiang #ifndef _RTE_STACK_H_
164418919fSjohnjiang #define _RTE_STACK_H_
174418919fSjohnjiang
184418919fSjohnjiang #ifdef __cplusplus
194418919fSjohnjiang extern "C" {
204418919fSjohnjiang #endif
214418919fSjohnjiang
224418919fSjohnjiang #include <rte_atomic.h>
234418919fSjohnjiang #include <rte_compat.h>
244418919fSjohnjiang #include <rte_debug.h>
254418919fSjohnjiang #include <rte_errno.h>
264418919fSjohnjiang #include <rte_memzone.h>
274418919fSjohnjiang #include <rte_spinlock.h>
284418919fSjohnjiang
294418919fSjohnjiang #define RTE_TAILQ_STACK_NAME "RTE_STACK"
304418919fSjohnjiang #define RTE_STACK_MZ_PREFIX "STK_"
314418919fSjohnjiang /** The maximum length of a stack name. */
324418919fSjohnjiang #define RTE_STACK_NAMESIZE (RTE_MEMZONE_NAMESIZE - \
334418919fSjohnjiang sizeof(RTE_STACK_MZ_PREFIX) + 1)
344418919fSjohnjiang
354418919fSjohnjiang struct rte_stack_lf_elem {
364418919fSjohnjiang void *data; /**< Data pointer */
374418919fSjohnjiang struct rte_stack_lf_elem *next; /**< Next pointer */
384418919fSjohnjiang };
394418919fSjohnjiang
404418919fSjohnjiang struct rte_stack_lf_head {
414418919fSjohnjiang struct rte_stack_lf_elem *top; /**< Stack top */
424418919fSjohnjiang uint64_t cnt; /**< Modification counter for avoiding ABA problem */
434418919fSjohnjiang };
444418919fSjohnjiang
454418919fSjohnjiang struct rte_stack_lf_list {
464418919fSjohnjiang /** List head */
474418919fSjohnjiang struct rte_stack_lf_head head __rte_aligned(16);
484418919fSjohnjiang /** List len */
494418919fSjohnjiang uint64_t len;
504418919fSjohnjiang };
514418919fSjohnjiang
524418919fSjohnjiang /* Structure containing two lock-free LIFO lists: the stack itself and a list
534418919fSjohnjiang * of free linked-list elements.
544418919fSjohnjiang */
554418919fSjohnjiang struct rte_stack_lf {
564418919fSjohnjiang /** LIFO list of elements */
574418919fSjohnjiang struct rte_stack_lf_list used __rte_cache_aligned;
584418919fSjohnjiang /** LIFO list of free elements */
594418919fSjohnjiang struct rte_stack_lf_list free __rte_cache_aligned;
604418919fSjohnjiang /** LIFO elements */
614418919fSjohnjiang struct rte_stack_lf_elem elems[] __rte_cache_aligned;
624418919fSjohnjiang };
634418919fSjohnjiang
644418919fSjohnjiang /* Structure containing the LIFO, its current length, and a lock for mutual
654418919fSjohnjiang * exclusion.
664418919fSjohnjiang */
674418919fSjohnjiang struct rte_stack_std {
684418919fSjohnjiang rte_spinlock_t lock; /**< LIFO lock */
694418919fSjohnjiang uint32_t len; /**< LIFO len */
704418919fSjohnjiang void *objs[]; /**< LIFO pointer table */
714418919fSjohnjiang };
724418919fSjohnjiang
734418919fSjohnjiang /* The RTE stack structure contains the LIFO structure itself, plus metadata
744418919fSjohnjiang * such as its name and memzone pointer.
754418919fSjohnjiang */
764418919fSjohnjiang struct rte_stack {
774418919fSjohnjiang /** Name of the stack. */
784418919fSjohnjiang char name[RTE_STACK_NAMESIZE] __rte_cache_aligned;
794418919fSjohnjiang /** Memzone containing the rte_stack structure. */
804418919fSjohnjiang const struct rte_memzone *memzone;
814418919fSjohnjiang uint32_t capacity; /**< Usable size of the stack. */
824418919fSjohnjiang uint32_t flags; /**< Flags supplied at creation. */
834418919fSjohnjiang RTE_STD_C11
844418919fSjohnjiang union {
854418919fSjohnjiang struct rte_stack_lf stack_lf; /**< Lock-free LIFO structure. */
864418919fSjohnjiang struct rte_stack_std stack_std; /**< LIFO structure. */
874418919fSjohnjiang };
884418919fSjohnjiang } __rte_cache_aligned;
894418919fSjohnjiang
904418919fSjohnjiang /**
914418919fSjohnjiang * The stack uses lock-free push and pop functions. This flag is only
924418919fSjohnjiang * supported on x86_64 platforms, currently.
934418919fSjohnjiang */
944418919fSjohnjiang #define RTE_STACK_F_LF 0x0001
954418919fSjohnjiang
964418919fSjohnjiang #include "rte_stack_std.h"
974418919fSjohnjiang #include "rte_stack_lf.h"
984418919fSjohnjiang
994418919fSjohnjiang /**
1004418919fSjohnjiang * Push several objects on the stack (MT-safe).
1014418919fSjohnjiang *
1024418919fSjohnjiang * @param s
1034418919fSjohnjiang * A pointer to the stack structure.
1044418919fSjohnjiang * @param obj_table
1054418919fSjohnjiang * A pointer to a table of void * pointers (objects).
1064418919fSjohnjiang * @param n
1074418919fSjohnjiang * The number of objects to push on the stack from the obj_table.
1084418919fSjohnjiang * @return
1094418919fSjohnjiang * Actual number of objects pushed (either 0 or *n*).
1104418919fSjohnjiang */
1114418919fSjohnjiang static __rte_always_inline unsigned int
rte_stack_push(struct rte_stack * s,void * const * obj_table,unsigned int n)1124418919fSjohnjiang rte_stack_push(struct rte_stack *s, void * const *obj_table, unsigned int n)
1134418919fSjohnjiang {
1144418919fSjohnjiang RTE_ASSERT(s != NULL);
1154418919fSjohnjiang RTE_ASSERT(obj_table != NULL);
1164418919fSjohnjiang
1174418919fSjohnjiang if (s->flags & RTE_STACK_F_LF)
1184418919fSjohnjiang return __rte_stack_lf_push(s, obj_table, n);
1194418919fSjohnjiang else
1204418919fSjohnjiang return __rte_stack_std_push(s, obj_table, n);
1214418919fSjohnjiang }
1224418919fSjohnjiang
1234418919fSjohnjiang /**
1244418919fSjohnjiang * Pop several objects from the stack (MT-safe).
1254418919fSjohnjiang *
1264418919fSjohnjiang * @param s
1274418919fSjohnjiang * A pointer to the stack structure.
1284418919fSjohnjiang * @param obj_table
1294418919fSjohnjiang * A pointer to a table of void * pointers (objects).
1304418919fSjohnjiang * @param n
1314418919fSjohnjiang * The number of objects to pull from the stack.
1324418919fSjohnjiang * @return
1334418919fSjohnjiang * Actual number of objects popped (either 0 or *n*).
1344418919fSjohnjiang */
1354418919fSjohnjiang static __rte_always_inline unsigned int
rte_stack_pop(struct rte_stack * s,void ** obj_table,unsigned int n)1364418919fSjohnjiang rte_stack_pop(struct rte_stack *s, void **obj_table, unsigned int n)
1374418919fSjohnjiang {
1384418919fSjohnjiang RTE_ASSERT(s != NULL);
1394418919fSjohnjiang RTE_ASSERT(obj_table != NULL);
1404418919fSjohnjiang
1414418919fSjohnjiang if (s->flags & RTE_STACK_F_LF)
1424418919fSjohnjiang return __rte_stack_lf_pop(s, obj_table, n);
1434418919fSjohnjiang else
1444418919fSjohnjiang return __rte_stack_std_pop(s, obj_table, n);
1454418919fSjohnjiang }
1464418919fSjohnjiang
1474418919fSjohnjiang /**
1484418919fSjohnjiang * Return the number of used entries in a stack.
1494418919fSjohnjiang *
1504418919fSjohnjiang * @param s
1514418919fSjohnjiang * A pointer to the stack structure.
1524418919fSjohnjiang * @return
1534418919fSjohnjiang * The number of used entries in the stack.
1544418919fSjohnjiang */
1554418919fSjohnjiang static __rte_always_inline unsigned int
rte_stack_count(struct rte_stack * s)1564418919fSjohnjiang rte_stack_count(struct rte_stack *s)
1574418919fSjohnjiang {
1584418919fSjohnjiang RTE_ASSERT(s != NULL);
1594418919fSjohnjiang
1604418919fSjohnjiang if (s->flags & RTE_STACK_F_LF)
1614418919fSjohnjiang return __rte_stack_lf_count(s);
1624418919fSjohnjiang else
1634418919fSjohnjiang return __rte_stack_std_count(s);
1644418919fSjohnjiang }
1654418919fSjohnjiang
1664418919fSjohnjiang /**
1674418919fSjohnjiang * Return the number of free entries in a stack.
1684418919fSjohnjiang *
1694418919fSjohnjiang * @param s
1704418919fSjohnjiang * A pointer to the stack structure.
1714418919fSjohnjiang * @return
1724418919fSjohnjiang * The number of free entries in the stack.
1734418919fSjohnjiang */
1744418919fSjohnjiang static __rte_always_inline unsigned int
rte_stack_free_count(struct rte_stack * s)1754418919fSjohnjiang rte_stack_free_count(struct rte_stack *s)
1764418919fSjohnjiang {
1774418919fSjohnjiang RTE_ASSERT(s != NULL);
1784418919fSjohnjiang
1794418919fSjohnjiang return s->capacity - rte_stack_count(s);
1804418919fSjohnjiang }
1814418919fSjohnjiang
1824418919fSjohnjiang /**
1834418919fSjohnjiang * Create a new stack named *name* in memory.
1844418919fSjohnjiang *
1854418919fSjohnjiang * This function uses ``memzone_reserve()`` to allocate memory for a stack of
1864418919fSjohnjiang * size *count*. The behavior of the stack is controlled by the *flags*.
1874418919fSjohnjiang *
1884418919fSjohnjiang * @param name
1894418919fSjohnjiang * The name of the stack.
1904418919fSjohnjiang * @param count
1914418919fSjohnjiang * The size of the stack.
1924418919fSjohnjiang * @param socket_id
1934418919fSjohnjiang * The *socket_id* argument is the socket identifier in case of
1944418919fSjohnjiang * NUMA. The value can be *SOCKET_ID_ANY* if there is no NUMA
1954418919fSjohnjiang * constraint for the reserved zone.
1964418919fSjohnjiang * @param flags
1974418919fSjohnjiang * An OR of the following:
1984418919fSjohnjiang * - RTE_STACK_F_LF: If this flag is set, the stack uses lock-free
1994418919fSjohnjiang * variants of the push and pop functions. Otherwise, it achieves
2004418919fSjohnjiang * thread-safety using a lock.
2014418919fSjohnjiang * @return
2024418919fSjohnjiang * On success, the pointer to the new allocated stack. NULL on error with
2034418919fSjohnjiang * rte_errno set appropriately. Possible errno values include:
2044418919fSjohnjiang * - ENOSPC - the maximum number of memzones has already been allocated
2054418919fSjohnjiang * - EEXIST - a stack with the same name already exists
2064418919fSjohnjiang * - ENOMEM - insufficient memory to create the stack
2074418919fSjohnjiang * - ENAMETOOLONG - name size exceeds RTE_STACK_NAMESIZE
2084418919fSjohnjiang */
2094418919fSjohnjiang struct rte_stack *
2104418919fSjohnjiang rte_stack_create(const char *name, unsigned int count, int socket_id,
2114418919fSjohnjiang uint32_t flags);
2124418919fSjohnjiang
2134418919fSjohnjiang /**
2144418919fSjohnjiang * Free all memory used by the stack.
2154418919fSjohnjiang *
2164418919fSjohnjiang * @param s
2174418919fSjohnjiang * Stack to free
2184418919fSjohnjiang */
2194418919fSjohnjiang void
2204418919fSjohnjiang rte_stack_free(struct rte_stack *s);
2214418919fSjohnjiang
2224418919fSjohnjiang /**
2234418919fSjohnjiang * Lookup a stack by its name.
2244418919fSjohnjiang *
2254418919fSjohnjiang * @param name
2264418919fSjohnjiang * The name of the stack.
2274418919fSjohnjiang * @return
2284418919fSjohnjiang * The pointer to the stack matching the name, or NULL if not found,
2294418919fSjohnjiang * with rte_errno set appropriately. Possible rte_errno values include:
2304418919fSjohnjiang * - ENOENT - Stack with name *name* not found.
2314418919fSjohnjiang * - EINVAL - *name* pointer is NULL.
2324418919fSjohnjiang */
2334418919fSjohnjiang struct rte_stack *
2344418919fSjohnjiang rte_stack_lookup(const char *name);
2354418919fSjohnjiang
2364418919fSjohnjiang #ifdef __cplusplus
2374418919fSjohnjiang }
2384418919fSjohnjiang #endif
2394418919fSjohnjiang
2404418919fSjohnjiang #endif /* _RTE_STACK_H_ */
241