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