199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 299a2dd95SBruce Richardson * Copyright(c) 2019 Intel Corporation 399a2dd95SBruce Richardson */ 499a2dd95SBruce Richardson 599a2dd95SBruce Richardson /** 699a2dd95SBruce Richardson * @file rte_stack.h 799a2dd95SBruce Richardson * 899a2dd95SBruce Richardson * RTE Stack. 999a2dd95SBruce Richardson * 1099a2dd95SBruce Richardson * librte_stack provides an API for configuration and use of a bounded stack of 1199a2dd95SBruce Richardson * pointers. Push and pop operations are MT-safe, allowing concurrent access, 1299a2dd95SBruce Richardson * and the interface supports pushing and popping multiple pointers at a time. 1399a2dd95SBruce Richardson */ 1499a2dd95SBruce Richardson 1599a2dd95SBruce Richardson #ifndef _RTE_STACK_H_ 1699a2dd95SBruce Richardson #define _RTE_STACK_H_ 1799a2dd95SBruce Richardson 1899a2dd95SBruce Richardson #ifdef __cplusplus 1999a2dd95SBruce Richardson extern "C" { 2099a2dd95SBruce Richardson #endif 2199a2dd95SBruce Richardson 2299a2dd95SBruce Richardson #include <rte_debug.h> 2399a2dd95SBruce Richardson #include <rte_errno.h> 2499a2dd95SBruce Richardson #include <rte_memzone.h> 2599a2dd95SBruce Richardson #include <rte_spinlock.h> 2699a2dd95SBruce Richardson 2799a2dd95SBruce Richardson #define RTE_TAILQ_STACK_NAME "RTE_STACK" 2899a2dd95SBruce Richardson #define RTE_STACK_MZ_PREFIX "STK_" 2999a2dd95SBruce Richardson /** The maximum length of a stack name. */ 3099a2dd95SBruce Richardson #define RTE_STACK_NAMESIZE (RTE_MEMZONE_NAMESIZE - \ 3199a2dd95SBruce Richardson sizeof(RTE_STACK_MZ_PREFIX) + 1) 3299a2dd95SBruce Richardson 3399a2dd95SBruce Richardson struct rte_stack_lf_elem { 3499a2dd95SBruce Richardson void *data; /**< Data pointer */ 3599a2dd95SBruce Richardson struct rte_stack_lf_elem *next; /**< Next pointer */ 3699a2dd95SBruce Richardson }; 3799a2dd95SBruce Richardson 3899a2dd95SBruce Richardson struct rte_stack_lf_head { 3999a2dd95SBruce Richardson struct rte_stack_lf_elem *top; /**< Stack top */ 4099a2dd95SBruce Richardson uint64_t cnt; /**< Modification counter for avoiding ABA problem */ 4199a2dd95SBruce Richardson }; 4299a2dd95SBruce Richardson 4399a2dd95SBruce Richardson struct rte_stack_lf_list { 4499a2dd95SBruce Richardson /** List head */ 4599a2dd95SBruce Richardson struct rte_stack_lf_head head __rte_aligned(16); 4699a2dd95SBruce Richardson /** List len */ 47*b6a19ec1STyler Retzlaff RTE_ATOMIC(uint64_t) len; 4899a2dd95SBruce Richardson }; 4999a2dd95SBruce Richardson 5099a2dd95SBruce Richardson /* Structure containing two lock-free LIFO lists: the stack itself and a list 5199a2dd95SBruce Richardson * of free linked-list elements. 5299a2dd95SBruce Richardson */ 5399a2dd95SBruce Richardson struct rte_stack_lf { 5499a2dd95SBruce Richardson /** LIFO list of elements */ 5599a2dd95SBruce Richardson struct rte_stack_lf_list used __rte_cache_aligned; 5699a2dd95SBruce Richardson /** LIFO list of free elements */ 5799a2dd95SBruce Richardson struct rte_stack_lf_list free __rte_cache_aligned; 5899a2dd95SBruce Richardson /** LIFO elements */ 5999a2dd95SBruce Richardson struct rte_stack_lf_elem elems[] __rte_cache_aligned; 6099a2dd95SBruce Richardson }; 6199a2dd95SBruce Richardson 6299a2dd95SBruce Richardson /* Structure containing the LIFO, its current length, and a lock for mutual 6399a2dd95SBruce Richardson * exclusion. 6499a2dd95SBruce Richardson */ 6599a2dd95SBruce Richardson struct rte_stack_std { 6699a2dd95SBruce Richardson rte_spinlock_t lock; /**< LIFO lock */ 6799a2dd95SBruce Richardson uint32_t len; /**< LIFO len */ 6899a2dd95SBruce Richardson void *objs[]; /**< LIFO pointer table */ 6999a2dd95SBruce Richardson }; 7099a2dd95SBruce Richardson 7199a2dd95SBruce Richardson /* The RTE stack structure contains the LIFO structure itself, plus metadata 7299a2dd95SBruce Richardson * such as its name and memzone pointer. 7399a2dd95SBruce Richardson */ 7499a2dd95SBruce Richardson struct rte_stack { 7599a2dd95SBruce Richardson /** Name of the stack. */ 7699a2dd95SBruce Richardson char name[RTE_STACK_NAMESIZE] __rte_cache_aligned; 7799a2dd95SBruce Richardson /** Memzone containing the rte_stack structure. */ 7899a2dd95SBruce Richardson const struct rte_memzone *memzone; 7999a2dd95SBruce Richardson uint32_t capacity; /**< Usable size of the stack. */ 8099a2dd95SBruce Richardson uint32_t flags; /**< Flags supplied at creation. */ 8199a2dd95SBruce Richardson union { 8299a2dd95SBruce Richardson struct rte_stack_lf stack_lf; /**< Lock-free LIFO structure. */ 8399a2dd95SBruce Richardson struct rte_stack_std stack_std; /**< LIFO structure. */ 8499a2dd95SBruce Richardson }; 8599a2dd95SBruce Richardson } __rte_cache_aligned; 8699a2dd95SBruce Richardson 8799a2dd95SBruce Richardson /** 8899a2dd95SBruce Richardson * The stack uses lock-free push and pop functions. This flag is only 891abb185dSStanislaw Kardach * supported on x86_64 or arm64 platforms, currently. 9099a2dd95SBruce Richardson */ 9199a2dd95SBruce Richardson #define RTE_STACK_F_LF 0x0001 9299a2dd95SBruce Richardson 9399a2dd95SBruce Richardson #include "rte_stack_std.h" 9499a2dd95SBruce Richardson #include "rte_stack_lf.h" 9599a2dd95SBruce Richardson 9699a2dd95SBruce Richardson /** 9799a2dd95SBruce Richardson * Push several objects on the stack (MT-safe). 9899a2dd95SBruce Richardson * 9999a2dd95SBruce Richardson * @param s 10099a2dd95SBruce Richardson * A pointer to the stack structure. 10199a2dd95SBruce Richardson * @param obj_table 10299a2dd95SBruce Richardson * A pointer to a table of void * pointers (objects). 10399a2dd95SBruce Richardson * @param n 10499a2dd95SBruce Richardson * The number of objects to push on the stack from the obj_table. 10599a2dd95SBruce Richardson * @return 10699a2dd95SBruce Richardson * Actual number of objects pushed (either 0 or *n*). 10799a2dd95SBruce Richardson */ 10899a2dd95SBruce Richardson static __rte_always_inline unsigned int 10999a2dd95SBruce Richardson rte_stack_push(struct rte_stack *s, void * const *obj_table, unsigned int n) 11099a2dd95SBruce Richardson { 11199a2dd95SBruce Richardson RTE_ASSERT(s != NULL); 11299a2dd95SBruce Richardson RTE_ASSERT(obj_table != NULL); 11399a2dd95SBruce Richardson 11499a2dd95SBruce Richardson if (s->flags & RTE_STACK_F_LF) 11599a2dd95SBruce Richardson return __rte_stack_lf_push(s, obj_table, n); 11699a2dd95SBruce Richardson else 11799a2dd95SBruce Richardson return __rte_stack_std_push(s, obj_table, n); 11899a2dd95SBruce Richardson } 11999a2dd95SBruce Richardson 12099a2dd95SBruce Richardson /** 12199a2dd95SBruce Richardson * Pop several objects from the stack (MT-safe). 12299a2dd95SBruce Richardson * 12399a2dd95SBruce Richardson * @param s 12499a2dd95SBruce Richardson * A pointer to the stack structure. 12599a2dd95SBruce Richardson * @param obj_table 12699a2dd95SBruce Richardson * A pointer to a table of void * pointers (objects). 12799a2dd95SBruce Richardson * @param n 12899a2dd95SBruce Richardson * The number of objects to pull from the stack. 12999a2dd95SBruce Richardson * @return 13099a2dd95SBruce Richardson * Actual number of objects popped (either 0 or *n*). 13199a2dd95SBruce Richardson */ 13299a2dd95SBruce Richardson static __rte_always_inline unsigned int 13399a2dd95SBruce Richardson rte_stack_pop(struct rte_stack *s, void **obj_table, unsigned int n) 13499a2dd95SBruce Richardson { 13599a2dd95SBruce Richardson RTE_ASSERT(s != NULL); 13699a2dd95SBruce Richardson RTE_ASSERT(obj_table != NULL); 13799a2dd95SBruce Richardson 13899a2dd95SBruce Richardson if (s->flags & RTE_STACK_F_LF) 13999a2dd95SBruce Richardson return __rte_stack_lf_pop(s, obj_table, n); 14099a2dd95SBruce Richardson else 14199a2dd95SBruce Richardson return __rte_stack_std_pop(s, obj_table, n); 14299a2dd95SBruce Richardson } 14399a2dd95SBruce Richardson 14499a2dd95SBruce Richardson /** 14599a2dd95SBruce Richardson * Return the number of used entries in a stack. 14699a2dd95SBruce Richardson * 14799a2dd95SBruce Richardson * @param s 14899a2dd95SBruce Richardson * A pointer to the stack structure. 14999a2dd95SBruce Richardson * @return 15099a2dd95SBruce Richardson * The number of used entries in the stack. 15199a2dd95SBruce Richardson */ 15299a2dd95SBruce Richardson static __rte_always_inline unsigned int 15399a2dd95SBruce Richardson rte_stack_count(struct rte_stack *s) 15499a2dd95SBruce Richardson { 15599a2dd95SBruce Richardson RTE_ASSERT(s != NULL); 15699a2dd95SBruce Richardson 15799a2dd95SBruce Richardson if (s->flags & RTE_STACK_F_LF) 15899a2dd95SBruce Richardson return __rte_stack_lf_count(s); 15999a2dd95SBruce Richardson else 16099a2dd95SBruce Richardson return __rte_stack_std_count(s); 16199a2dd95SBruce Richardson } 16299a2dd95SBruce Richardson 16399a2dd95SBruce Richardson /** 16499a2dd95SBruce Richardson * Return the number of free entries in a stack. 16599a2dd95SBruce Richardson * 16699a2dd95SBruce Richardson * @param s 16799a2dd95SBruce Richardson * A pointer to the stack structure. 16899a2dd95SBruce Richardson * @return 16999a2dd95SBruce Richardson * The number of free entries in the stack. 17099a2dd95SBruce Richardson */ 17199a2dd95SBruce Richardson static __rte_always_inline unsigned int 17299a2dd95SBruce Richardson rte_stack_free_count(struct rte_stack *s) 17399a2dd95SBruce Richardson { 17499a2dd95SBruce Richardson RTE_ASSERT(s != NULL); 17599a2dd95SBruce Richardson 17699a2dd95SBruce Richardson return s->capacity - rte_stack_count(s); 17799a2dd95SBruce Richardson } 17899a2dd95SBruce Richardson 17999a2dd95SBruce Richardson /** 18099a2dd95SBruce Richardson * Create a new stack named *name* in memory. 18199a2dd95SBruce Richardson * 18299a2dd95SBruce Richardson * This function uses ``memzone_reserve()`` to allocate memory for a stack of 18399a2dd95SBruce Richardson * size *count*. The behavior of the stack is controlled by the *flags*. 18499a2dd95SBruce Richardson * 18599a2dd95SBruce Richardson * @param name 18699a2dd95SBruce Richardson * The name of the stack. 18799a2dd95SBruce Richardson * @param count 18899a2dd95SBruce Richardson * The size of the stack. 18999a2dd95SBruce Richardson * @param socket_id 19099a2dd95SBruce Richardson * The *socket_id* argument is the socket identifier in case of 19199a2dd95SBruce Richardson * NUMA. The value can be *SOCKET_ID_ANY* if there is no NUMA 19299a2dd95SBruce Richardson * constraint for the reserved zone. 19399a2dd95SBruce Richardson * @param flags 19499a2dd95SBruce Richardson * An OR of the following: 19599a2dd95SBruce Richardson * - RTE_STACK_F_LF: If this flag is set, the stack uses lock-free 19699a2dd95SBruce Richardson * variants of the push and pop functions. Otherwise, it achieves 19799a2dd95SBruce Richardson * thread-safety using a lock. 19899a2dd95SBruce Richardson * @return 19999a2dd95SBruce Richardson * On success, the pointer to the new allocated stack. NULL on error with 20099a2dd95SBruce Richardson * rte_errno set appropriately. Possible errno values include: 20199a2dd95SBruce Richardson * - ENOSPC - the maximum number of memzones has already been allocated 20299a2dd95SBruce Richardson * - EEXIST - a stack with the same name already exists 20399a2dd95SBruce Richardson * - ENOMEM - insufficient memory to create the stack 20499a2dd95SBruce Richardson * - ENAMETOOLONG - name size exceeds RTE_STACK_NAMESIZE 2051abb185dSStanislaw Kardach * - ENOTSUP - platform does not support given flags combination. 20699a2dd95SBruce Richardson */ 20799a2dd95SBruce Richardson struct rte_stack * 20899a2dd95SBruce Richardson rte_stack_create(const char *name, unsigned int count, int socket_id, 20999a2dd95SBruce Richardson uint32_t flags); 21099a2dd95SBruce Richardson 21199a2dd95SBruce Richardson /** 21299a2dd95SBruce Richardson * Free all memory used by the stack. 21399a2dd95SBruce Richardson * 21499a2dd95SBruce Richardson * @param s 215448e01f1SStephen Hemminger * Pointer to stack created with rte_stack_create(). 216448e01f1SStephen Hemminger * If s is NULL, no operation is performed. 21799a2dd95SBruce Richardson */ 21899a2dd95SBruce Richardson void 21999a2dd95SBruce Richardson rte_stack_free(struct rte_stack *s); 22099a2dd95SBruce Richardson 22199a2dd95SBruce Richardson /** 22299a2dd95SBruce Richardson * Lookup a stack by its name. 22399a2dd95SBruce Richardson * 22499a2dd95SBruce Richardson * @param name 22599a2dd95SBruce Richardson * The name of the stack. 22699a2dd95SBruce Richardson * @return 22799a2dd95SBruce Richardson * The pointer to the stack matching the name, or NULL if not found, 22899a2dd95SBruce Richardson * with rte_errno set appropriately. Possible rte_errno values include: 22999a2dd95SBruce Richardson * - ENOENT - Stack with name *name* not found. 23099a2dd95SBruce Richardson * - EINVAL - *name* pointer is NULL. 23199a2dd95SBruce Richardson */ 23299a2dd95SBruce Richardson struct rte_stack * 23399a2dd95SBruce Richardson rte_stack_lookup(const char *name); 23499a2dd95SBruce Richardson 23599a2dd95SBruce Richardson #ifdef __cplusplus 23699a2dd95SBruce Richardson } 23799a2dd95SBruce Richardson #endif 23899a2dd95SBruce Richardson 23999a2dd95SBruce Richardson #endif /* _RTE_STACK_H_ */ 240