From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from EUR03-AM5-obe.outbound.protection.outlook.com (mail-eopbgr30088.outbound.protection.outlook.com [40.107.3.88]) by dpdk.org (Postfix) with ESMTP id 601F523D for ; Fri, 29 Mar 2019 00:26:58 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=armh.onmicrosoft.com; s=selector1-arm-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=py4n9hv2v7XojRa0daSiMgNK+GagRy/azWQMKe0nPIc=; b=DjkaeRtVhU5GIg4qcWgdAfZ99KcQ1wbMIgluH52f/42qIv5urB9SYKH0XU9zq0PhcyyJc/7arRhhz9n7mSWphTVMxwQ58kYy3n2jD2jp8VRbphoxQ3RzaBxNB3Ma7JS8SvwWMP8IJYeSQDTX66LlAP8mGfMvI3O0Lp68pOdnxEI= Received: from VE1PR08MB5149.eurprd08.prod.outlook.com (20.179.30.152) by VE1PR08MB5168.eurprd08.prod.outlook.com (20.179.30.218) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.1750.15; Thu, 28 Mar 2019 23:26:54 +0000 Received: from VE1PR08MB5149.eurprd08.prod.outlook.com ([fe80::e0ae:ecad:ec5:8177]) by VE1PR08MB5149.eurprd08.prod.outlook.com ([fe80::e0ae:ecad:ec5:8177%2]) with mapi id 15.20.1750.017; Thu, 28 Mar 2019 23:26:54 +0000 From: Honnappa Nagarahalli To: Gage Eads , "dev@dpdk.org" CC: "olivier.matz@6wind.com" , "arybchenko@solarflare.com" , "bruce.richardson@intel.com" , "konstantin.ananyev@intel.com" , "Gavin Hu (Arm Technology China)" , nd , "thomas@monjalon.net" , nd Thread-Topic: [PATCH v3 1/8] stack: introduce rte stack library Thread-Index: AQHU1CtVrsaMA7YCkEOnYy6dB4cOVqYgkw6A Date: Thu, 28 Mar 2019 23:26:54 +0000 Message-ID: References: <20190305164256.2367-1-gage.eads@intel.com> <20190306144559.391-1-gage.eads@intel.com> <20190306144559.391-2-gage.eads@intel.com> In-Reply-To: <20190306144559.391-2-gage.eads@intel.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: authentication-results: spf=none (sender IP is ) smtp.mailfrom=Honnappa.Nagarahalli@arm.com; x-originating-ip: [217.140.111.135] x-ms-publictraffictype: Email x-ms-office365-filtering-correlation-id: 5e5fca03-5ceb-4c9f-f772-08d6b3d4dd54 x-ms-office365-filtering-ht: Tenant x-microsoft-antispam: BCL:0; PCL:0; RULEID:(2390118)(7020095)(4652040)(8989299)(5600127)(711020)(4605104)(4618075)(4534185)(4627221)(201703031133081)(201702281549075)(8990200)(2017052603328)(7153060)(7193020); SRVR:VE1PR08MB5168; x-ms-traffictypediagnostic: VE1PR08MB5168: x-ld-processed: f34e5979-57d9-4aaa-ad4d-b122a662184d,ExtAddr nodisclaimer: True x-microsoft-antispam-prvs: x-forefront-prvs: 0990C54589 x-forefront-antispam-report: SFV:NSPM; SFS:(10009020)(39860400002)(366004)(346002)(136003)(376002)(396003)(199004)(189003)(13464003)(86362001)(486006)(71190400001)(7696005)(53936002)(8936002)(25786009)(2501003)(14454004)(8676002)(53546011)(81156014)(6506007)(76176011)(81166006)(316002)(110136005)(54906003)(6246003)(5660300002)(4326008)(55016002)(53946003)(478600001)(72206003)(229853002)(99286004)(68736007)(105586002)(30864003)(6436002)(106356001)(74316002)(305945005)(9686003)(14444005)(33656002)(256004)(2906002)(3846002)(7736002)(66066001)(97736004)(186003)(6116002)(26005)(52536014)(71200400001)(102836004)(11346002)(446003)(476003)(579004)(559001); DIR:OUT; SFP:1101; SCL:1; SRVR:VE1PR08MB5168; H:VE1PR08MB5149.eurprd08.prod.outlook.com; FPR:; SPF:None; LANG:en; PTR:InfoNoRecords; A:1; MX:1; received-spf: None (protection.outlook.com: arm.com does not designate permitted sender hosts) x-ms-exchange-senderadcheck: 1 x-microsoft-antispam-message-info: VBVp0vpH9bwPOW/aTBJUBL4P50NnbCsr3e6BRKNIG2Ko9CKMHFtYQ0dr8iCw7dwvT+6vW6CtYJMQE9qaZBEX9YuFRmBN94DDccCQurGrtAaldPYf7RaofIrextt4UJgFUfwQiEMIK2oaToJTVPph/KbHPfBcCPeT3tdkRjAxLJEoJEaR6rbznaySPpAMgwdIWv42coNoggN/q9OBEkR4+6mifOXpcAB37cRth0cmmkpAtIlJ2kYOppWhuLWocHTPdb82xthAyZ//BT6p9z2kqJypGsq3YvrfNOXhYRn7UUK0ARz6xFtrlrTrAhWl8DC8S7NCE0iabQiMZzjXYrD1zibACF434GgrU7/5FwQn69OJot9W2l6TNWihQHqQMm9fD8wCXi41qLMtXIusxic47cjvjaRrxxokIGFIw2xcp7Q= Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 X-OriginatorOrg: arm.com X-MS-Exchange-CrossTenant-Network-Message-Id: 5e5fca03-5ceb-4c9f-f772-08d6b3d4dd54 X-MS-Exchange-CrossTenant-originalarrivaltime: 28 Mar 2019 23:26:54.6174 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: f34e5979-57d9-4aaa-ad4d-b122a662184d X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-Transport-CrossTenantHeadersStamped: VE1PR08MB5168 Subject: Re: [dpdk-dev] [PATCH v3 1/8] stack: introduce rte stack library X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 28 Mar 2019 23:26:58 -0000 Hi Gage, Apologies for the late comments. > -----Original Message----- > From: Gage Eads > Sent: Wednesday, March 6, 2019 8:46 AM > To: dev@dpdk.org > Cc: olivier.matz@6wind.com; arybchenko@solarflare.com; > bruce.richardson@intel.com; konstantin.ananyev@intel.com; Gavin Hu (Arm > Technology China) ; Honnappa Nagarahalli > ; nd ; > thomas@monjalon.net > Subject: [PATCH v3 1/8] stack: introduce rte stack library >=20 > The rte_stack library provides an API for configuration and use of a boun= ded > stack of pointers. Push and pop operations are MT-safe, allowing concurre= nt > access, and the interface supports pushing and popping multiple pointers = at a > time. >=20 > The library's interface is modeled after another DPDK data structure, rte= _ring, > and its lock-based implementation is derived from the stack mempool > handler. An upcoming commit will migrate the stack mempool handler to > rte_stack. >=20 > Signed-off-by: Gage Eads > --- > MAINTAINERS | 6 + > config/common_base | 5 + > doc/api/doxy-api-index.md | 1 + > doc/api/doxy-api.conf.in | 1 + > doc/guides/prog_guide/index.rst | 1 + > doc/guides/prog_guide/stack_lib.rst | 28 ++++ > doc/guides/rel_notes/release_19_05.rst | 5 + > lib/Makefile | 2 + > lib/librte_stack/Makefile | 23 +++ > lib/librte_stack/meson.build | 8 + > lib/librte_stack/rte_stack.c | 194 +++++++++++++++++++++++ > lib/librte_stack/rte_stack.h | 274 > +++++++++++++++++++++++++++++++++ > lib/librte_stack/rte_stack_pvt.h | 34 ++++ > lib/librte_stack/rte_stack_version.map | 9 ++ > lib/meson.build | 2 +- > mk/rte.app.mk | 1 + > 16 files changed, 593 insertions(+), 1 deletion(-) create mode 100644 > doc/guides/prog_guide/stack_lib.rst > create mode 100644 lib/librte_stack/Makefile create mode 100644 > lib/librte_stack/meson.build create mode 100644 lib/librte_stack/rte_sta= ck.c > create mode 100644 lib/librte_stack/rte_stack.h create mode 100644 > lib/librte_stack/rte_stack_pvt.h create mode 100644 > lib/librte_stack/rte_stack_version.map >=20 > diff --git a/MAINTAINERS b/MAINTAINERS > index 097cfb4f3..5fca30823 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -405,6 +405,12 @@ F: drivers/raw/skeleton_rawdev/ > F: app/test/test_rawdev.c > F: doc/guides/prog_guide/rawdev.rst >=20 > +Stack API - EXPERIMENTAL > +M: Gage Eads > +M: Olivier Matz > +F: lib/librte_stack/ > +F: doc/guides/prog_guide/stack_lib.rst > + >=20 > Memory Pool Drivers > ------------------- > diff --git a/config/common_base b/config/common_base index > 0b09a9348..1b45dea6c 100644 > --- a/config/common_base > +++ b/config/common_base > @@ -980,3 +980,8 @@ CONFIG_RTE_APP_CRYPTO_PERF=3Dy # Compile the > eventdev application # CONFIG_RTE_APP_EVENTDEV=3Dy > + > +# > +# Compile librte_stack > +# > +CONFIG_RTE_LIBRTE_STACK=3Dy > diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md index > d95ad566c..0df8848c0 100644 > --- a/doc/api/doxy-api-index.md > +++ b/doc/api/doxy-api-index.md > @@ -124,6 +124,7 @@ The public API headers are grouped by topics: > [mbuf] (@ref rte_mbuf.h), > [mbuf pool ops] (@ref rte_mbuf_pool_ops.h), > [ring] (@ref rte_ring.h), > + [stack] (@ref rte_stack.h), > [tailq] (@ref rte_tailq.h), > [bitmap] (@ref rte_bitmap.h) >=20 > diff --git a/doc/api/doxy-api.conf.in b/doc/api/doxy-api.conf.in index > a365e669b..7722fc3e9 100644 > --- a/doc/api/doxy-api.conf.in > +++ b/doc/api/doxy-api.conf.in > @@ -55,6 +55,7 @@ INPUT =3D @TOPDIR@/doc/api/doxy-api- > index.md \ > @TOPDIR@/lib/librte_ring \ > @TOPDIR@/lib/librte_sched \ > @TOPDIR@/lib/librte_security \ > + @TOPDIR@/lib/librte_stack \ > @TOPDIR@/lib/librte_table \ > @TOPDIR@/lib/librte_telemetry \ > @TOPDIR@/lib/librte_timer \ diff --git > a/doc/guides/prog_guide/index.rst b/doc/guides/prog_guide/index.rst index > 6726b1e8d..f4f60862f 100644 > --- a/doc/guides/prog_guide/index.rst > +++ b/doc/guides/prog_guide/index.rst > @@ -55,6 +55,7 @@ Programmer's Guide > metrics_lib > bpf_lib > ipsec_lib > + stack_lib > source_org > dev_kit_build_system > dev_kit_root_make_help > diff --git a/doc/guides/prog_guide/stack_lib.rst > b/doc/guides/prog_guide/stack_lib.rst > new file mode 100644 > index 000000000..25a8cc38a > --- /dev/null > +++ b/doc/guides/prog_guide/stack_lib.rst > @@ -0,0 +1,28 @@ > +.. SPDX-License-Identifier: BSD-3-Clause > + Copyright(c) 2019 Intel Corporation. > + > +Stack Library > +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > + > +DPDK's stack library provides an API for configuration and use of a > +bounded stack of pointers. > + > +The stack library provides the following basic operations: > + > +* Create a uniquely named stack of a user-specified size and using a > + user-specified socket. > + > +* Push and pop a burst of one or more stack objects (pointers). These > function > + are multi-threading safe. > + > +* Free a previously created stack. > + > +* Lookup a pointer to a stack by its name. > + > +* Query a stack's current depth and number of free entries. > + > +Implementation > +~~~~~~~~~~~~~~ > + > +The stack consists of a contiguous array of pointers, a current index, > +and a spinlock. Accesses to the stack are made multi-thread safe by the > spinlock. > diff --git a/doc/guides/rel_notes/release_19_05.rst > b/doc/guides/rel_notes/release_19_05.rst > index 4a3e2a7f3..8c649a954 100644 > --- a/doc/guides/rel_notes/release_19_05.rst > +++ b/doc/guides/rel_notes/release_19_05.rst > @@ -77,6 +77,11 @@ New Features > which includes the directory name, lib name, filenames, makefile, docs= , > macros, functions, structs and any other strings in the code. >=20 > +* **Added Stack API.** > + > + Added a new stack API for configuration and use of a bounded stack of > + pointers. The API provides MT-safe push and pop operations that can > + operate on one or more pointers per operation. >=20 > Removed Items > ------------- > diff --git a/lib/Makefile b/lib/Makefile index ffbfd0d94..d941bd849 10064= 4 > --- a/lib/Makefile > +++ b/lib/Makefile > @@ -109,6 +109,8 @@ DIRS-$(CONFIG_RTE_LIBRTE_IPSEC) +=3D librte_ipsec > DEPDIRS-librte_ipsec :=3D librte_eal librte_mbuf librte_cryptodev > librte_security > DIRS-$(CONFIG_RTE_LIBRTE_TELEMETRY) +=3D librte_telemetry DEPDIRS- > librte_telemetry :=3D librte_eal librte_metrics librte_ethdev > +DIRS-$(CONFIG_RTE_LIBRTE_STACK) +=3D librte_stack DEPDIRS-librte_stack := =3D > +librte_eal >=20 > ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y) > DIRS-$(CONFIG_RTE_LIBRTE_KNI) +=3D librte_kni diff --git > a/lib/librte_stack/Makefile b/lib/librte_stack/Makefile new file mode 100= 644 > index 000000000..e956b6535 > --- /dev/null > +++ b/lib/librte_stack/Makefile > @@ -0,0 +1,23 @@ > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2019 Intel > +Corporation > + > +include $(RTE_SDK)/mk/rte.vars.mk > + > +# library name > +LIB =3D librte_stack.a > + > +CFLAGS +=3D $(WERROR_FLAGS) -I$(SRCDIR) -O3 CFLAGS +=3D > +-DALLOW_EXPERIMENTAL_API LDLIBS +=3D -lrte_eal > + > +EXPORT_MAP :=3D rte_stack_version.map > + > +LIBABIVER :=3D 1 > + > +# all source are stored in SRCS-y > +SRCS-$(CONFIG_RTE_LIBRTE_STACK) :=3D rte_stack.c > + > +# install includes > +SYMLINK-$(CONFIG_RTE_LIBRTE_STACK)-include :=3D rte_stack.h > + > +include $(RTE_SDK)/mk/rte.lib.mk > diff --git a/lib/librte_stack/meson.build b/lib/librte_stack/meson.build = new > file mode 100644 index 000000000..99f43710e > --- /dev/null > +++ b/lib/librte_stack/meson.build > @@ -0,0 +1,8 @@ > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2019 Intel > +Corporation > + > +allow_experimental_apis =3D true > + > +version =3D 1 > +sources =3D files('rte_stack.c') > +headers =3D files('rte_stack.h') > diff --git a/lib/librte_stack/rte_stack.c b/lib/librte_stack/rte_stack.c = new file > mode 100644 index 000000000..96dffdf44 > --- /dev/null > +++ b/lib/librte_stack/rte_stack.c > @@ -0,0 +1,194 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2019 Intel Corporation > + */ > + > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "rte_stack.h" > +#include "rte_stack_pvt.h" > + > +int stack_logtype; > + > +TAILQ_HEAD(rte_stack_list, rte_tailq_entry); > + > +static struct rte_tailq_elem rte_stack_tailq =3D { > + .name =3D RTE_TAILQ_STACK_NAME, > +}; > +EAL_REGISTER_TAILQ(rte_stack_tailq) > + > +static void > +rte_stack_std_init(struct rte_stack *s) { > + rte_spinlock_init(&s->stack_std.lock); > +} > + > +static void > +rte_stack_init(struct rte_stack *s) > +{ > + memset(s, 0, sizeof(*s)); > + > + rte_stack_std_init(s); > +} > + > +static ssize_t > +rte_stack_get_memsize(unsigned int count) { > + ssize_t sz =3D sizeof(struct rte_stack); > + > + /* Add padding to avoid false sharing conflicts */ > + sz +=3D RTE_CACHE_LINE_ROUNDUP(count * sizeof(void *)) + > + 2 * RTE_CACHE_LINE_SIZE; I did not understand how the false sharing is caused and how this padding i= s solving the issue. Verbose comments would help. > + > + return sz; > +} > + > +struct rte_stack * > +rte_stack_create(const char *name, unsigned int count, int socket_id, > + uint32_t flags) > +{ > + char mz_name[RTE_MEMZONE_NAMESIZE]; > + struct rte_stack_list *stack_list; > + const struct rte_memzone *mz; > + struct rte_tailq_entry *te; > + struct rte_stack *s; > + unsigned int sz; > + int ret; > + > + RTE_SET_USED(flags); > + > + sz =3D rte_stack_get_memsize(count); > + > + ret =3D snprintf(mz_name, sizeof(mz_name), "%s%s", > + RTE_STACK_MZ_PREFIX, name); > + if (ret < 0 || ret >=3D (int)sizeof(mz_name)) { > + rte_errno =3D ENAMETOOLONG; > + return NULL; > + } > + > + te =3D rte_zmalloc("STACK_TAILQ_ENTRY", sizeof(*te), 0); > + if (te =3D=3D NULL) { > + STACK_LOG_ERR("Cannot reserve memory for tailq\n"); > + rte_errno =3D ENOMEM; > + return NULL; > + } > + > + rte_rwlock_write_lock(RTE_EAL_TAILQ_RWLOCK); > + I think there is a need to check if a stack with the same name exists alrea= dy. > + mz =3D rte_memzone_reserve_aligned(mz_name, sz, socket_id, > + 0, __alignof__(*s)); > + if (mz =3D=3D NULL) { > + STACK_LOG_ERR("Cannot reserve stack memzone!\n"); > + rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK); > + rte_free(te); > + return NULL; > + } > + > + s =3D mz->addr; > + > + rte_stack_init(s); > + > + /* Store the name for later lookups */ > + ret =3D snprintf(s->name, sizeof(s->name), "%s", name); > + if (ret < 0 || ret >=3D (int)sizeof(s->name)) { > + rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK); > + > + rte_errno =3D ENAMETOOLONG; > + rte_free(te); > + rte_memzone_free(mz); > + return NULL; > + } > + > + s->memzone =3D mz; > + s->capacity =3D count; > + s->flags =3D flags; > + > + te->data =3D s; > + > + stack_list =3D RTE_TAILQ_CAST(rte_stack_tailq.head, rte_stack_list); > + > + TAILQ_INSERT_TAIL(stack_list, te, next); > + > + rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK); > + > + return s; > +} > + > +void > +rte_stack_free(struct rte_stack *s) > +{ > + struct rte_stack_list *stack_list; > + struct rte_tailq_entry *te; > + > + if (s =3D=3D NULL) > + return; > + Adding a check to make sure the length of the stack is 0 would help catch i= ssues? > + stack_list =3D RTE_TAILQ_CAST(rte_stack_tailq.head, rte_stack_list); > + rte_rwlock_write_lock(RTE_EAL_TAILQ_RWLOCK); > + > + /* find out tailq entry */ > + TAILQ_FOREACH(te, stack_list, next) { > + if (te->data =3D=3D s) > + break; > + } > + > + if (te =3D=3D NULL) { > + rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK); > + return; > + } > + > + TAILQ_REMOVE(stack_list, te, next); > + > + rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK); > + > + rte_free(te); > + > + rte_memzone_free(s->memzone); > +} > + > +struct rte_stack * > +rte_stack_lookup(const char *name) > +{ > + struct rte_stack_list *stack_list; > + struct rte_tailq_entry *te; > + struct rte_stack *r =3D NULL; > + > + if (name =3D=3D NULL) { > + rte_errno =3D EINVAL; > + return NULL; > + } > + > + stack_list =3D RTE_TAILQ_CAST(rte_stack_tailq.head, rte_stack_list); > + > + rte_rwlock_read_lock(RTE_EAL_TAILQ_RWLOCK); > + > + TAILQ_FOREACH(te, stack_list, next) { > + r =3D (struct rte_stack *) te->data; > + if (strncmp(name, r->name, RTE_STACK_NAMESIZE) =3D=3D 0) > + break; > + } > + > + rte_rwlock_read_unlock(RTE_EAL_TAILQ_RWLOCK); > + > + if (te =3D=3D NULL) { > + rte_errno =3D ENOENT; > + return NULL; > + } > + > + return r; > +} > + > +RTE_INIT(librte_stack_init_log) > +{ > + stack_logtype =3D rte_log_register("lib.stack"); > + if (stack_logtype >=3D 0) > + rte_log_set_level(stack_logtype, RTE_LOG_NOTICE); } > diff --git a/lib/librte_stack/rte_stack.h b/lib/librte_stack/rte_stack.h = new file > mode 100644 index 000000000..7a633deb5 > --- /dev/null > +++ b/lib/librte_stack/rte_stack.h > @@ -0,0 +1,274 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2019 Intel Corporation > + */ > + > +/** > + * @file rte_stack.h > + * @b EXPERIMENTAL: this API may change without prior notice > + * > + * RTE Stack > + * > + * 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, > + * and the interface supports pushing and popping multiple pointers at a > time. > + */ > + > +#ifndef _RTE_STACK_H_ > +#define _RTE_STACK_H_ > + > +#ifdef __cplusplus > +extern "C" { > +#endif > + > +#include > +#include > +#include > + > +#define RTE_TAILQ_STACK_NAME "RTE_STACK" > +#define RTE_STACK_MZ_PREFIX "STK_" Nit, "STACK_" would be easier to debug > +/** The maximum length of a stack name. */ #define RTE_STACK_NAMESIZE > +(RTE_MEMZONE_NAMESIZE - \ > + sizeof(RTE_STACK_MZ_PREFIX) + 1) > + > +/* Structure containing the LIFO, its current length, and a lock for > +mutual > + * exclusion. > + */ > +struct rte_stack_std { > + rte_spinlock_t lock; /**< LIFO lock */ > + uint32_t len; /**< LIFO len */ > + void *objs[]; /**< LIFO pointer table */ }; > + > +/* The RTE stack structure contains the LIFO structure itself, plus > +metadata > + * such as its name and memzone pointer. > + */ > +struct rte_stack { > + /** Name of the stack. */ > + char name[RTE_STACK_NAMESIZE] __rte_cache_aligned; > + /** Memzone containing the rte_stack structure. */ > + 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_cache_aligned; > + > +/** > + * @internal Push several objects on the stack (MT-safe). > + * > + * @param s > + * A pointer to the stack structure. > + * @param obj_table > + * A pointer to a table of void * pointers (objects). > + * @param n > + * The number of objects to push on the stack from the obj_table. > + * @return > + * Actual number of objects pushed (either 0 or *n*). > + */ > +static __rte_always_inline unsigned int __rte_experimental This is an internal function. Is '__rte_experimental' tag required? > +rte_stack_std_push(struct rte_stack *s, void * const *obj_table, > +unsigned int n) { Since this is an internal function, does it make sense to add '__' to the b= eginning of the function name (similar to what is done in rte_ring?). > + struct rte_stack_std *stack =3D &s->stack_std; > + unsigned int index; > + void **cache_objs; > + > + rte_spinlock_lock(&stack->lock); > + cache_objs =3D &stack->objs[stack->len]; > + > + /* Is there sufficient space in the stack? */ > + if ((stack->len + n) > s->capacity) { > + rte_spinlock_unlock(&stack->lock); > + return 0; > + } > + > + /* Add elements back into the cache */ > + for (index =3D 0; index < n; ++index, obj_table++) > + cache_objs[index] =3D *obj_table; > + > + stack->len +=3D n; > + > + rte_spinlock_unlock(&stack->lock); > + return n; > +} > + > +/** > + * @warning > + * @b EXPERIMENTAL: this API may change without prior notice > + * > + * Push several objects on the stack (MT-safe). > + * > + * @param s > + * A pointer to the stack structure. > + * @param obj_table > + * A pointer to a table of void * pointers (objects). > + * @param n > + * The number of objects to push on the stack from the obj_table. > + * @return > + * Actual number of objects pushed (either 0 or *n*). > + */ > +static __rte_always_inline unsigned int __rte_experimental > +rte_stack_push(struct rte_stack *s, void * const *obj_table, unsigned > +int n) { > + return rte_stack_std_push(s, obj_table, n); } > + > +/** > + * @internal Pop several objects from the stack (MT-safe). > + * > + * @param s > + * A pointer to the stack structure. > + * @param obj_table > + * A pointer to a table of void * pointers (objects). > + * @param n > + * The number of objects to pull from the stack. > + * @return > + * Actual number of objects popped (either 0 or *n*). > + */ > +static __rte_always_inline unsigned int __rte_experimental This is an internal function. Is '__rte_experimental' tag required? > +rte_stack_std_pop(struct rte_stack *s, void **obj_table, unsigned int > +n) { > + struct rte_stack_std *stack =3D &s->stack_std; > + unsigned int index, len; > + void **cache_objs; > + > + rte_spinlock_lock(&stack->lock); > + > + if (unlikely(n > stack->len)) { > + rte_spinlock_unlock(&stack->lock); > + return 0; > + } > + > + cache_objs =3D stack->objs; > + > + for (index =3D 0, len =3D stack->len - 1; index < n; > + ++index, len--, obj_table++) > + *obj_table =3D cache_objs[len]; > + > + stack->len -=3D n; > + rte_spinlock_unlock(&stack->lock); > + > + return n; > +} > + > +/** > + * @warning > + * @b EXPERIMENTAL: this API may change without prior notice > + * > + * Pop several objects from the stack (MT-safe). > + * > + * @param s > + * A pointer to the stack structure. > + * @param obj_table > + * A pointer to a table of void * pointers (objects). > + * @param n > + * The number of objects to pull from the stack. > + * @return > + * Actual number of objects popped (either 0 or *n*). > + */ > +static __rte_always_inline unsigned int __rte_experimental > +rte_stack_pop(struct rte_stack *s, void **obj_table, unsigned int n) { > + if (unlikely(n =3D=3D 0 || obj_table =3D=3D NULL)) > + return 0; 's =3D=3D NULL' can be added as well. Similar check is missing in 'rte_stac= k_push'. Since these are data-path APIs, RTE_ASSERT would be better. > + > + return rte_stack_std_pop(s, obj_table, n); } > + > +/** > + * @warning > + * @b EXPERIMENTAL: this API may change without prior notice > + * > + * Return the number of used entries in a stack. > + * > + * @param s > + * A pointer to the stack structure. > + * @return > + * The number of used entries in the stack. > + */ > +static __rte_always_inline unsigned int __rte_experimental > +rte_stack_count(struct rte_stack *s) { > + return (unsigned int)s->stack_std.len; } > + > +/** > + * @warning > + * @b EXPERIMENTAL: this API may change without prior notice > + * > + * Return the number of free entries in a stack. > + * > + * @param s > + * A pointer to the stack structure. > + * @return > + * The number of free entries in the stack. > + */ > +static __rte_always_inline unsigned int __rte_experimental > +rte_stack_free_count(struct rte_stack *s) { > + return s->capacity - rte_stack_count(s); } > + > +/** > + * @warning > + * @b EXPERIMENTAL: this API may change without prior notice > + * > + * Create a new stack named *name* in memory. > + * > + * This function uses ``memzone_reserve()`` to allocate memory for a > +stack of > + * size *count*. The behavior of the stack is controlled by the *flags*. > + * > + * @param name > + * The name of the stack. > + * @param count > + * The size of the stack. > + * @param socket_id > + * The *socket_id* argument is the socket identifier in case of > + * NUMA. The value can be *SOCKET_ID_ANY* if there is no NUMA > + * constraint for the reserved zone. > + * @param flags > + * Reserved for future use. > + * @return > + * On success, the pointer to the new allocated stack. NULL on error w= ith > + * rte_errno set appropriately. Possible errno values include: > + * - ENOSPC - the maximum number of memzones has already been > allocated > + * - EEXIST - a stack with the same name already exists This is not implemented currently > + * - ENOMEM - insufficient memory to create the stack > + * - ENAMETOOLONG - name size exceeds RTE_STACK_NAMESIZE > + */ > +struct rte_stack *__rte_experimental > +rte_stack_create(const char *name, unsigned int count, int socket_id, > + uint32_t flags); > + > +/** > + * @warning > + * @b EXPERIMENTAL: this API may change without prior notice > + * > + * Free all memory used by the stack. > + * > + * @param s > + * Stack to free > + */ > +void __rte_experimental > +rte_stack_free(struct rte_stack *s); > + > +/** > + * @warning > + * @b EXPERIMENTAL: this API may change without prior notice > + * > + * Lookup a stack by its name. > + * > + * @param name > + * The name of the stack. > + * @return > + * The pointer to the stack matching the name, or NULL if not found, > + * with rte_errno set appropriately. Possible rte_errno values include= : > + * - ENOENT - Stack with name *name* not found. > + * - EINVAL - *name* pointer is NULL. > + */ > +struct rte_stack * __rte_experimental > +rte_stack_lookup(const char *name); > + > +#ifdef __cplusplus > +} > +#endif > + > +#endif /* _RTE_STACK_H_ */ > diff --git a/lib/librte_stack/rte_stack_pvt.h b/lib/librte_stack/rte_stac= k_pvt.h > new file mode 100644 > index 000000000..4a6a7bdb3 > --- /dev/null > +++ b/lib/librte_stack/rte_stack_pvt.h > @@ -0,0 +1,34 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2019 Intel Corporation > + */ > + > +#ifndef _RTE_STACK_PVT_H_ > +#define _RTE_STACK_PVT_H_ > + > +#ifdef __cplusplus > +extern "C" { > +#endif > + > +#include > + > +extern int stack_logtype; > + > +#define STACK_LOG(level, fmt, args...) \ > + rte_log(RTE_LOG_ ##level, stack_logtype, "%s(): "fmt "\n", \ > + __func__, ##args) > + > +#define STACK_LOG_ERR(fmt, args...) \ > + STACK_LOG(ERR, fmt, ## args) > + > +#define STACK_LOG_WARN(fmt, args...) \ > + STACK_LOG(WARNING, fmt, ## args) > + > +#define STACK_LOG_INFO(fmt, args...) \ > + STACK_LOG(INFO, fmt, ## args) > + > + > +#ifdef __cplusplus > +} > +#endif > + > +#endif /* _RTE_STACK_PVT_H_ */ > diff --git a/lib/librte_stack/rte_stack_version.map > b/lib/librte_stack/rte_stack_version.map > new file mode 100644 > index 000000000..6662679c3 > --- /dev/null > +++ b/lib/librte_stack/rte_stack_version.map > @@ -0,0 +1,9 @@ > +EXPERIMENTAL { > + global: > + > + rte_stack_create; > + rte_stack_free; > + rte_stack_lookup; > + > + local: *; > +}; > diff --git a/lib/meson.build b/lib/meson.build index 99957ba7d..90115477f > 100644 > --- a/lib/meson.build > +++ b/lib/meson.build > @@ -22,7 +22,7 @@ libraries =3D [ > 'gro', 'gso', 'ip_frag', 'jobstats', > 'kni', 'latencystats', 'lpm', 'member', > 'power', 'pdump', 'rawdev', > - 'reorder', 'sched', 'security', 'vhost', > + 'reorder', 'sched', 'security', 'stack', 'vhost', > #ipsec lib depends on crypto and security > 'ipsec', > # add pkt framework libs which use other libs from above diff --git > a/mk/rte.app.mk b/mk/rte.app.mk index 3c40f9df2..8decfb851 100644 > --- a/mk/rte.app.mk > +++ b/mk/rte.app.mk > @@ -87,6 +87,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_SECURITY) +=3D - > lrte_security > _LDLIBS-$(CONFIG_RTE_LIBRTE_COMPRESSDEV) +=3D -lrte_compressdev > _LDLIBS-$(CONFIG_RTE_LIBRTE_EVENTDEV) +=3D -lrte_eventdev > _LDLIBS-$(CONFIG_RTE_LIBRTE_RAWDEV) +=3D -lrte_rawdev > +_LDLIBS-$(CONFIG_RTE_LIBRTE_STACK) +=3D -lrte_stack > _LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER) +=3D -lrte_timer > _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL) +=3D -lrte_mempool > _LDLIBS-$(CONFIG_RTE_DRIVER_MEMPOOL_RING) +=3D -lrte_mempool_ring > -- > 2.13.6 From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from dpdk.org (dpdk.org [92.243.14.124]) by dpdk.space (Postfix) with ESMTP id B3685A0679 for ; Fri, 29 Mar 2019 00:27:00 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 7EA382BFA; Fri, 29 Mar 2019 00:27:00 +0100 (CET) Received: from EUR03-AM5-obe.outbound.protection.outlook.com (mail-eopbgr30088.outbound.protection.outlook.com [40.107.3.88]) by dpdk.org (Postfix) with ESMTP id 601F523D for ; Fri, 29 Mar 2019 00:26:58 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=armh.onmicrosoft.com; s=selector1-arm-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=py4n9hv2v7XojRa0daSiMgNK+GagRy/azWQMKe0nPIc=; b=DjkaeRtVhU5GIg4qcWgdAfZ99KcQ1wbMIgluH52f/42qIv5urB9SYKH0XU9zq0PhcyyJc/7arRhhz9n7mSWphTVMxwQ58kYy3n2jD2jp8VRbphoxQ3RzaBxNB3Ma7JS8SvwWMP8IJYeSQDTX66LlAP8mGfMvI3O0Lp68pOdnxEI= Received: from VE1PR08MB5149.eurprd08.prod.outlook.com (20.179.30.152) by VE1PR08MB5168.eurprd08.prod.outlook.com (20.179.30.218) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.1750.15; Thu, 28 Mar 2019 23:26:54 +0000 Received: from VE1PR08MB5149.eurprd08.prod.outlook.com ([fe80::e0ae:ecad:ec5:8177]) by VE1PR08MB5149.eurprd08.prod.outlook.com ([fe80::e0ae:ecad:ec5:8177%2]) with mapi id 15.20.1750.017; Thu, 28 Mar 2019 23:26:54 +0000 From: Honnappa Nagarahalli To: Gage Eads , "dev@dpdk.org" CC: "olivier.matz@6wind.com" , "arybchenko@solarflare.com" , "bruce.richardson@intel.com" , "konstantin.ananyev@intel.com" , "Gavin Hu (Arm Technology China)" , nd , "thomas@monjalon.net" , nd Thread-Topic: [PATCH v3 1/8] stack: introduce rte stack library Thread-Index: AQHU1CtVrsaMA7YCkEOnYy6dB4cOVqYgkw6A Date: Thu, 28 Mar 2019 23:26:54 +0000 Message-ID: References: <20190305164256.2367-1-gage.eads@intel.com> <20190306144559.391-1-gage.eads@intel.com> <20190306144559.391-2-gage.eads@intel.com> In-Reply-To: <20190306144559.391-2-gage.eads@intel.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: authentication-results: spf=none (sender IP is ) smtp.mailfrom=Honnappa.Nagarahalli@arm.com; x-originating-ip: [217.140.111.135] x-ms-publictraffictype: Email x-ms-office365-filtering-correlation-id: 5e5fca03-5ceb-4c9f-f772-08d6b3d4dd54 x-ms-office365-filtering-ht: Tenant x-microsoft-antispam: BCL:0; PCL:0; RULEID:(2390118)(7020095)(4652040)(8989299)(5600127)(711020)(4605104)(4618075)(4534185)(4627221)(201703031133081)(201702281549075)(8990200)(2017052603328)(7153060)(7193020); SRVR:VE1PR08MB5168; x-ms-traffictypediagnostic: VE1PR08MB5168: x-ld-processed: f34e5979-57d9-4aaa-ad4d-b122a662184d,ExtAddr nodisclaimer: True x-microsoft-antispam-prvs: x-forefront-prvs: 0990C54589 x-forefront-antispam-report: SFV:NSPM; SFS:(10009020)(39860400002)(366004)(346002)(136003)(376002)(396003)(199004)(189003)(13464003)(86362001)(486006)(71190400001)(7696005)(53936002)(8936002)(25786009)(2501003)(14454004)(8676002)(53546011)(81156014)(6506007)(76176011)(81166006)(316002)(110136005)(54906003)(6246003)(5660300002)(4326008)(55016002)(53946003)(478600001)(72206003)(229853002)(99286004)(68736007)(105586002)(30864003)(6436002)(106356001)(74316002)(305945005)(9686003)(14444005)(33656002)(256004)(2906002)(3846002)(7736002)(66066001)(97736004)(186003)(6116002)(26005)(52536014)(71200400001)(102836004)(11346002)(446003)(476003)(579004)(559001); DIR:OUT; SFP:1101; SCL:1; SRVR:VE1PR08MB5168; H:VE1PR08MB5149.eurprd08.prod.outlook.com; FPR:; SPF:None; LANG:en; PTR:InfoNoRecords; A:1; MX:1; received-spf: None (protection.outlook.com: arm.com does not designate permitted sender hosts) x-ms-exchange-senderadcheck: 1 x-microsoft-antispam-message-info: VBVp0vpH9bwPOW/aTBJUBL4P50NnbCsr3e6BRKNIG2Ko9CKMHFtYQ0dr8iCw7dwvT+6vW6CtYJMQE9qaZBEX9YuFRmBN94DDccCQurGrtAaldPYf7RaofIrextt4UJgFUfwQiEMIK2oaToJTVPph/KbHPfBcCPeT3tdkRjAxLJEoJEaR6rbznaySPpAMgwdIWv42coNoggN/q9OBEkR4+6mifOXpcAB37cRth0cmmkpAtIlJ2kYOppWhuLWocHTPdb82xthAyZ//BT6p9z2kqJypGsq3YvrfNOXhYRn7UUK0ARz6xFtrlrTrAhWl8DC8S7NCE0iabQiMZzjXYrD1zibACF434GgrU7/5FwQn69OJot9W2l6TNWihQHqQMm9fD8wCXi41qLMtXIusxic47cjvjaRrxxokIGFIw2xcp7Q= Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 X-OriginatorOrg: arm.com X-MS-Exchange-CrossTenant-Network-Message-Id: 5e5fca03-5ceb-4c9f-f772-08d6b3d4dd54 X-MS-Exchange-CrossTenant-originalarrivaltime: 28 Mar 2019 23:26:54.6174 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: f34e5979-57d9-4aaa-ad4d-b122a662184d X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-Transport-CrossTenantHeadersStamped: VE1PR08MB5168 Subject: Re: [dpdk-dev] [PATCH v3 1/8] stack: introduce rte stack library X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Message-ID: <20190328232654.PPraIGIf0ljwZBRFNh2LGEJROEMU7PYKtBKoSbRi4Ow@z> Hi Gage, Apologies for the late comments. > -----Original Message----- > From: Gage Eads > Sent: Wednesday, March 6, 2019 8:46 AM > To: dev@dpdk.org > Cc: olivier.matz@6wind.com; arybchenko@solarflare.com; > bruce.richardson@intel.com; konstantin.ananyev@intel.com; Gavin Hu (Arm > Technology China) ; Honnappa Nagarahalli > ; nd ; > thomas@monjalon.net > Subject: [PATCH v3 1/8] stack: introduce rte stack library >=20 > The rte_stack library provides an API for configuration and use of a boun= ded > stack of pointers. Push and pop operations are MT-safe, allowing concurre= nt > access, and the interface supports pushing and popping multiple pointers = at a > time. >=20 > The library's interface is modeled after another DPDK data structure, rte= _ring, > and its lock-based implementation is derived from the stack mempool > handler. An upcoming commit will migrate the stack mempool handler to > rte_stack. >=20 > Signed-off-by: Gage Eads > --- > MAINTAINERS | 6 + > config/common_base | 5 + > doc/api/doxy-api-index.md | 1 + > doc/api/doxy-api.conf.in | 1 + > doc/guides/prog_guide/index.rst | 1 + > doc/guides/prog_guide/stack_lib.rst | 28 ++++ > doc/guides/rel_notes/release_19_05.rst | 5 + > lib/Makefile | 2 + > lib/librte_stack/Makefile | 23 +++ > lib/librte_stack/meson.build | 8 + > lib/librte_stack/rte_stack.c | 194 +++++++++++++++++++++++ > lib/librte_stack/rte_stack.h | 274 > +++++++++++++++++++++++++++++++++ > lib/librte_stack/rte_stack_pvt.h | 34 ++++ > lib/librte_stack/rte_stack_version.map | 9 ++ > lib/meson.build | 2 +- > mk/rte.app.mk | 1 + > 16 files changed, 593 insertions(+), 1 deletion(-) create mode 100644 > doc/guides/prog_guide/stack_lib.rst > create mode 100644 lib/librte_stack/Makefile create mode 100644 > lib/librte_stack/meson.build create mode 100644 lib/librte_stack/rte_sta= ck.c > create mode 100644 lib/librte_stack/rte_stack.h create mode 100644 > lib/librte_stack/rte_stack_pvt.h create mode 100644 > lib/librte_stack/rte_stack_version.map >=20 > diff --git a/MAINTAINERS b/MAINTAINERS > index 097cfb4f3..5fca30823 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -405,6 +405,12 @@ F: drivers/raw/skeleton_rawdev/ > F: app/test/test_rawdev.c > F: doc/guides/prog_guide/rawdev.rst >=20 > +Stack API - EXPERIMENTAL > +M: Gage Eads > +M: Olivier Matz > +F: lib/librte_stack/ > +F: doc/guides/prog_guide/stack_lib.rst > + >=20 > Memory Pool Drivers > ------------------- > diff --git a/config/common_base b/config/common_base index > 0b09a9348..1b45dea6c 100644 > --- a/config/common_base > +++ b/config/common_base > @@ -980,3 +980,8 @@ CONFIG_RTE_APP_CRYPTO_PERF=3Dy # Compile the > eventdev application # CONFIG_RTE_APP_EVENTDEV=3Dy > + > +# > +# Compile librte_stack > +# > +CONFIG_RTE_LIBRTE_STACK=3Dy > diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md index > d95ad566c..0df8848c0 100644 > --- a/doc/api/doxy-api-index.md > +++ b/doc/api/doxy-api-index.md > @@ -124,6 +124,7 @@ The public API headers are grouped by topics: > [mbuf] (@ref rte_mbuf.h), > [mbuf pool ops] (@ref rte_mbuf_pool_ops.h), > [ring] (@ref rte_ring.h), > + [stack] (@ref rte_stack.h), > [tailq] (@ref rte_tailq.h), > [bitmap] (@ref rte_bitmap.h) >=20 > diff --git a/doc/api/doxy-api.conf.in b/doc/api/doxy-api.conf.in index > a365e669b..7722fc3e9 100644 > --- a/doc/api/doxy-api.conf.in > +++ b/doc/api/doxy-api.conf.in > @@ -55,6 +55,7 @@ INPUT =3D @TOPDIR@/doc/api/doxy-api- > index.md \ > @TOPDIR@/lib/librte_ring \ > @TOPDIR@/lib/librte_sched \ > @TOPDIR@/lib/librte_security \ > + @TOPDIR@/lib/librte_stack \ > @TOPDIR@/lib/librte_table \ > @TOPDIR@/lib/librte_telemetry \ > @TOPDIR@/lib/librte_timer \ diff --git > a/doc/guides/prog_guide/index.rst b/doc/guides/prog_guide/index.rst index > 6726b1e8d..f4f60862f 100644 > --- a/doc/guides/prog_guide/index.rst > +++ b/doc/guides/prog_guide/index.rst > @@ -55,6 +55,7 @@ Programmer's Guide > metrics_lib > bpf_lib > ipsec_lib > + stack_lib > source_org > dev_kit_build_system > dev_kit_root_make_help > diff --git a/doc/guides/prog_guide/stack_lib.rst > b/doc/guides/prog_guide/stack_lib.rst > new file mode 100644 > index 000000000..25a8cc38a > --- /dev/null > +++ b/doc/guides/prog_guide/stack_lib.rst > @@ -0,0 +1,28 @@ > +.. SPDX-License-Identifier: BSD-3-Clause > + Copyright(c) 2019 Intel Corporation. > + > +Stack Library > +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > + > +DPDK's stack library provides an API for configuration and use of a > +bounded stack of pointers. > + > +The stack library provides the following basic operations: > + > +* Create a uniquely named stack of a user-specified size and using a > + user-specified socket. > + > +* Push and pop a burst of one or more stack objects (pointers). These > function > + are multi-threading safe. > + > +* Free a previously created stack. > + > +* Lookup a pointer to a stack by its name. > + > +* Query a stack's current depth and number of free entries. > + > +Implementation > +~~~~~~~~~~~~~~ > + > +The stack consists of a contiguous array of pointers, a current index, > +and a spinlock. Accesses to the stack are made multi-thread safe by the > spinlock. > diff --git a/doc/guides/rel_notes/release_19_05.rst > b/doc/guides/rel_notes/release_19_05.rst > index 4a3e2a7f3..8c649a954 100644 > --- a/doc/guides/rel_notes/release_19_05.rst > +++ b/doc/guides/rel_notes/release_19_05.rst > @@ -77,6 +77,11 @@ New Features > which includes the directory name, lib name, filenames, makefile, docs= , > macros, functions, structs and any other strings in the code. >=20 > +* **Added Stack API.** > + > + Added a new stack API for configuration and use of a bounded stack of > + pointers. The API provides MT-safe push and pop operations that can > + operate on one or more pointers per operation. >=20 > Removed Items > ------------- > diff --git a/lib/Makefile b/lib/Makefile index ffbfd0d94..d941bd849 10064= 4 > --- a/lib/Makefile > +++ b/lib/Makefile > @@ -109,6 +109,8 @@ DIRS-$(CONFIG_RTE_LIBRTE_IPSEC) +=3D librte_ipsec > DEPDIRS-librte_ipsec :=3D librte_eal librte_mbuf librte_cryptodev > librte_security > DIRS-$(CONFIG_RTE_LIBRTE_TELEMETRY) +=3D librte_telemetry DEPDIRS- > librte_telemetry :=3D librte_eal librte_metrics librte_ethdev > +DIRS-$(CONFIG_RTE_LIBRTE_STACK) +=3D librte_stack DEPDIRS-librte_stack := =3D > +librte_eal >=20 > ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y) > DIRS-$(CONFIG_RTE_LIBRTE_KNI) +=3D librte_kni diff --git > a/lib/librte_stack/Makefile b/lib/librte_stack/Makefile new file mode 100= 644 > index 000000000..e956b6535 > --- /dev/null > +++ b/lib/librte_stack/Makefile > @@ -0,0 +1,23 @@ > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2019 Intel > +Corporation > + > +include $(RTE_SDK)/mk/rte.vars.mk > + > +# library name > +LIB =3D librte_stack.a > + > +CFLAGS +=3D $(WERROR_FLAGS) -I$(SRCDIR) -O3 CFLAGS +=3D > +-DALLOW_EXPERIMENTAL_API LDLIBS +=3D -lrte_eal > + > +EXPORT_MAP :=3D rte_stack_version.map > + > +LIBABIVER :=3D 1 > + > +# all source are stored in SRCS-y > +SRCS-$(CONFIG_RTE_LIBRTE_STACK) :=3D rte_stack.c > + > +# install includes > +SYMLINK-$(CONFIG_RTE_LIBRTE_STACK)-include :=3D rte_stack.h > + > +include $(RTE_SDK)/mk/rte.lib.mk > diff --git a/lib/librte_stack/meson.build b/lib/librte_stack/meson.build = new > file mode 100644 index 000000000..99f43710e > --- /dev/null > +++ b/lib/librte_stack/meson.build > @@ -0,0 +1,8 @@ > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2019 Intel > +Corporation > + > +allow_experimental_apis =3D true > + > +version =3D 1 > +sources =3D files('rte_stack.c') > +headers =3D files('rte_stack.h') > diff --git a/lib/librte_stack/rte_stack.c b/lib/librte_stack/rte_stack.c = new file > mode 100644 index 000000000..96dffdf44 > --- /dev/null > +++ b/lib/librte_stack/rte_stack.c > @@ -0,0 +1,194 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2019 Intel Corporation > + */ > + > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "rte_stack.h" > +#include "rte_stack_pvt.h" > + > +int stack_logtype; > + > +TAILQ_HEAD(rte_stack_list, rte_tailq_entry); > + > +static struct rte_tailq_elem rte_stack_tailq =3D { > + .name =3D RTE_TAILQ_STACK_NAME, > +}; > +EAL_REGISTER_TAILQ(rte_stack_tailq) > + > +static void > +rte_stack_std_init(struct rte_stack *s) { > + rte_spinlock_init(&s->stack_std.lock); > +} > + > +static void > +rte_stack_init(struct rte_stack *s) > +{ > + memset(s, 0, sizeof(*s)); > + > + rte_stack_std_init(s); > +} > + > +static ssize_t > +rte_stack_get_memsize(unsigned int count) { > + ssize_t sz =3D sizeof(struct rte_stack); > + > + /* Add padding to avoid false sharing conflicts */ > + sz +=3D RTE_CACHE_LINE_ROUNDUP(count * sizeof(void *)) + > + 2 * RTE_CACHE_LINE_SIZE; I did not understand how the false sharing is caused and how this padding i= s solving the issue. Verbose comments would help. > + > + return sz; > +} > + > +struct rte_stack * > +rte_stack_create(const char *name, unsigned int count, int socket_id, > + uint32_t flags) > +{ > + char mz_name[RTE_MEMZONE_NAMESIZE]; > + struct rte_stack_list *stack_list; > + const struct rte_memzone *mz; > + struct rte_tailq_entry *te; > + struct rte_stack *s; > + unsigned int sz; > + int ret; > + > + RTE_SET_USED(flags); > + > + sz =3D rte_stack_get_memsize(count); > + > + ret =3D snprintf(mz_name, sizeof(mz_name), "%s%s", > + RTE_STACK_MZ_PREFIX, name); > + if (ret < 0 || ret >=3D (int)sizeof(mz_name)) { > + rte_errno =3D ENAMETOOLONG; > + return NULL; > + } > + > + te =3D rte_zmalloc("STACK_TAILQ_ENTRY", sizeof(*te), 0); > + if (te =3D=3D NULL) { > + STACK_LOG_ERR("Cannot reserve memory for tailq\n"); > + rte_errno =3D ENOMEM; > + return NULL; > + } > + > + rte_rwlock_write_lock(RTE_EAL_TAILQ_RWLOCK); > + I think there is a need to check if a stack with the same name exists alrea= dy. > + mz =3D rte_memzone_reserve_aligned(mz_name, sz, socket_id, > + 0, __alignof__(*s)); > + if (mz =3D=3D NULL) { > + STACK_LOG_ERR("Cannot reserve stack memzone!\n"); > + rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK); > + rte_free(te); > + return NULL; > + } > + > + s =3D mz->addr; > + > + rte_stack_init(s); > + > + /* Store the name for later lookups */ > + ret =3D snprintf(s->name, sizeof(s->name), "%s", name); > + if (ret < 0 || ret >=3D (int)sizeof(s->name)) { > + rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK); > + > + rte_errno =3D ENAMETOOLONG; > + rte_free(te); > + rte_memzone_free(mz); > + return NULL; > + } > + > + s->memzone =3D mz; > + s->capacity =3D count; > + s->flags =3D flags; > + > + te->data =3D s; > + > + stack_list =3D RTE_TAILQ_CAST(rte_stack_tailq.head, rte_stack_list); > + > + TAILQ_INSERT_TAIL(stack_list, te, next); > + > + rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK); > + > + return s; > +} > + > +void > +rte_stack_free(struct rte_stack *s) > +{ > + struct rte_stack_list *stack_list; > + struct rte_tailq_entry *te; > + > + if (s =3D=3D NULL) > + return; > + Adding a check to make sure the length of the stack is 0 would help catch i= ssues? > + stack_list =3D RTE_TAILQ_CAST(rte_stack_tailq.head, rte_stack_list); > + rte_rwlock_write_lock(RTE_EAL_TAILQ_RWLOCK); > + > + /* find out tailq entry */ > + TAILQ_FOREACH(te, stack_list, next) { > + if (te->data =3D=3D s) > + break; > + } > + > + if (te =3D=3D NULL) { > + rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK); > + return; > + } > + > + TAILQ_REMOVE(stack_list, te, next); > + > + rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK); > + > + rte_free(te); > + > + rte_memzone_free(s->memzone); > +} > + > +struct rte_stack * > +rte_stack_lookup(const char *name) > +{ > + struct rte_stack_list *stack_list; > + struct rte_tailq_entry *te; > + struct rte_stack *r =3D NULL; > + > + if (name =3D=3D NULL) { > + rte_errno =3D EINVAL; > + return NULL; > + } > + > + stack_list =3D RTE_TAILQ_CAST(rte_stack_tailq.head, rte_stack_list); > + > + rte_rwlock_read_lock(RTE_EAL_TAILQ_RWLOCK); > + > + TAILQ_FOREACH(te, stack_list, next) { > + r =3D (struct rte_stack *) te->data; > + if (strncmp(name, r->name, RTE_STACK_NAMESIZE) =3D=3D 0) > + break; > + } > + > + rte_rwlock_read_unlock(RTE_EAL_TAILQ_RWLOCK); > + > + if (te =3D=3D NULL) { > + rte_errno =3D ENOENT; > + return NULL; > + } > + > + return r; > +} > + > +RTE_INIT(librte_stack_init_log) > +{ > + stack_logtype =3D rte_log_register("lib.stack"); > + if (stack_logtype >=3D 0) > + rte_log_set_level(stack_logtype, RTE_LOG_NOTICE); } > diff --git a/lib/librte_stack/rte_stack.h b/lib/librte_stack/rte_stack.h = new file > mode 100644 index 000000000..7a633deb5 > --- /dev/null > +++ b/lib/librte_stack/rte_stack.h > @@ -0,0 +1,274 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2019 Intel Corporation > + */ > + > +/** > + * @file rte_stack.h > + * @b EXPERIMENTAL: this API may change without prior notice > + * > + * RTE Stack > + * > + * 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, > + * and the interface supports pushing and popping multiple pointers at a > time. > + */ > + > +#ifndef _RTE_STACK_H_ > +#define _RTE_STACK_H_ > + > +#ifdef __cplusplus > +extern "C" { > +#endif > + > +#include > +#include > +#include > + > +#define RTE_TAILQ_STACK_NAME "RTE_STACK" > +#define RTE_STACK_MZ_PREFIX "STK_" Nit, "STACK_" would be easier to debug > +/** The maximum length of a stack name. */ #define RTE_STACK_NAMESIZE > +(RTE_MEMZONE_NAMESIZE - \ > + sizeof(RTE_STACK_MZ_PREFIX) + 1) > + > +/* Structure containing the LIFO, its current length, and a lock for > +mutual > + * exclusion. > + */ > +struct rte_stack_std { > + rte_spinlock_t lock; /**< LIFO lock */ > + uint32_t len; /**< LIFO len */ > + void *objs[]; /**< LIFO pointer table */ }; > + > +/* The RTE stack structure contains the LIFO structure itself, plus > +metadata > + * such as its name and memzone pointer. > + */ > +struct rte_stack { > + /** Name of the stack. */ > + char name[RTE_STACK_NAMESIZE] __rte_cache_aligned; > + /** Memzone containing the rte_stack structure. */ > + 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_cache_aligned; > + > +/** > + * @internal Push several objects on the stack (MT-safe). > + * > + * @param s > + * A pointer to the stack structure. > + * @param obj_table > + * A pointer to a table of void * pointers (objects). > + * @param n > + * The number of objects to push on the stack from the obj_table. > + * @return > + * Actual number of objects pushed (either 0 or *n*). > + */ > +static __rte_always_inline unsigned int __rte_experimental This is an internal function. Is '__rte_experimental' tag required? > +rte_stack_std_push(struct rte_stack *s, void * const *obj_table, > +unsigned int n) { Since this is an internal function, does it make sense to add '__' to the b= eginning of the function name (similar to what is done in rte_ring?). > + struct rte_stack_std *stack =3D &s->stack_std; > + unsigned int index; > + void **cache_objs; > + > + rte_spinlock_lock(&stack->lock); > + cache_objs =3D &stack->objs[stack->len]; > + > + /* Is there sufficient space in the stack? */ > + if ((stack->len + n) > s->capacity) { > + rte_spinlock_unlock(&stack->lock); > + return 0; > + } > + > + /* Add elements back into the cache */ > + for (index =3D 0; index < n; ++index, obj_table++) > + cache_objs[index] =3D *obj_table; > + > + stack->len +=3D n; > + > + rte_spinlock_unlock(&stack->lock); > + return n; > +} > + > +/** > + * @warning > + * @b EXPERIMENTAL: this API may change without prior notice > + * > + * Push several objects on the stack (MT-safe). > + * > + * @param s > + * A pointer to the stack structure. > + * @param obj_table > + * A pointer to a table of void * pointers (objects). > + * @param n > + * The number of objects to push on the stack from the obj_table. > + * @return > + * Actual number of objects pushed (either 0 or *n*). > + */ > +static __rte_always_inline unsigned int __rte_experimental > +rte_stack_push(struct rte_stack *s, void * const *obj_table, unsigned > +int n) { > + return rte_stack_std_push(s, obj_table, n); } > + > +/** > + * @internal Pop several objects from the stack (MT-safe). > + * > + * @param s > + * A pointer to the stack structure. > + * @param obj_table > + * A pointer to a table of void * pointers (objects). > + * @param n > + * The number of objects to pull from the stack. > + * @return > + * Actual number of objects popped (either 0 or *n*). > + */ > +static __rte_always_inline unsigned int __rte_experimental This is an internal function. Is '__rte_experimental' tag required? > +rte_stack_std_pop(struct rte_stack *s, void **obj_table, unsigned int > +n) { > + struct rte_stack_std *stack =3D &s->stack_std; > + unsigned int index, len; > + void **cache_objs; > + > + rte_spinlock_lock(&stack->lock); > + > + if (unlikely(n > stack->len)) { > + rte_spinlock_unlock(&stack->lock); > + return 0; > + } > + > + cache_objs =3D stack->objs; > + > + for (index =3D 0, len =3D stack->len - 1; index < n; > + ++index, len--, obj_table++) > + *obj_table =3D cache_objs[len]; > + > + stack->len -=3D n; > + rte_spinlock_unlock(&stack->lock); > + > + return n; > +} > + > +/** > + * @warning > + * @b EXPERIMENTAL: this API may change without prior notice > + * > + * Pop several objects from the stack (MT-safe). > + * > + * @param s > + * A pointer to the stack structure. > + * @param obj_table > + * A pointer to a table of void * pointers (objects). > + * @param n > + * The number of objects to pull from the stack. > + * @return > + * Actual number of objects popped (either 0 or *n*). > + */ > +static __rte_always_inline unsigned int __rte_experimental > +rte_stack_pop(struct rte_stack *s, void **obj_table, unsigned int n) { > + if (unlikely(n =3D=3D 0 || obj_table =3D=3D NULL)) > + return 0; 's =3D=3D NULL' can be added as well. Similar check is missing in 'rte_stac= k_push'. Since these are data-path APIs, RTE_ASSERT would be better. > + > + return rte_stack_std_pop(s, obj_table, n); } > + > +/** > + * @warning > + * @b EXPERIMENTAL: this API may change without prior notice > + * > + * Return the number of used entries in a stack. > + * > + * @param s > + * A pointer to the stack structure. > + * @return > + * The number of used entries in the stack. > + */ > +static __rte_always_inline unsigned int __rte_experimental > +rte_stack_count(struct rte_stack *s) { > + return (unsigned int)s->stack_std.len; } > + > +/** > + * @warning > + * @b EXPERIMENTAL: this API may change without prior notice > + * > + * Return the number of free entries in a stack. > + * > + * @param s > + * A pointer to the stack structure. > + * @return > + * The number of free entries in the stack. > + */ > +static __rte_always_inline unsigned int __rte_experimental > +rte_stack_free_count(struct rte_stack *s) { > + return s->capacity - rte_stack_count(s); } > + > +/** > + * @warning > + * @b EXPERIMENTAL: this API may change without prior notice > + * > + * Create a new stack named *name* in memory. > + * > + * This function uses ``memzone_reserve()`` to allocate memory for a > +stack of > + * size *count*. The behavior of the stack is controlled by the *flags*. > + * > + * @param name > + * The name of the stack. > + * @param count > + * The size of the stack. > + * @param socket_id > + * The *socket_id* argument is the socket identifier in case of > + * NUMA. The value can be *SOCKET_ID_ANY* if there is no NUMA > + * constraint for the reserved zone. > + * @param flags > + * Reserved for future use. > + * @return > + * On success, the pointer to the new allocated stack. NULL on error w= ith > + * rte_errno set appropriately. Possible errno values include: > + * - ENOSPC - the maximum number of memzones has already been > allocated > + * - EEXIST - a stack with the same name already exists This is not implemented currently > + * - ENOMEM - insufficient memory to create the stack > + * - ENAMETOOLONG - name size exceeds RTE_STACK_NAMESIZE > + */ > +struct rte_stack *__rte_experimental > +rte_stack_create(const char *name, unsigned int count, int socket_id, > + uint32_t flags); > + > +/** > + * @warning > + * @b EXPERIMENTAL: this API may change without prior notice > + * > + * Free all memory used by the stack. > + * > + * @param s > + * Stack to free > + */ > +void __rte_experimental > +rte_stack_free(struct rte_stack *s); > + > +/** > + * @warning > + * @b EXPERIMENTAL: this API may change without prior notice > + * > + * Lookup a stack by its name. > + * > + * @param name > + * The name of the stack. > + * @return > + * The pointer to the stack matching the name, or NULL if not found, > + * with rte_errno set appropriately. Possible rte_errno values include= : > + * - ENOENT - Stack with name *name* not found. > + * - EINVAL - *name* pointer is NULL. > + */ > +struct rte_stack * __rte_experimental > +rte_stack_lookup(const char *name); > + > +#ifdef __cplusplus > +} > +#endif > + > +#endif /* _RTE_STACK_H_ */ > diff --git a/lib/librte_stack/rte_stack_pvt.h b/lib/librte_stack/rte_stac= k_pvt.h > new file mode 100644 > index 000000000..4a6a7bdb3 > --- /dev/null > +++ b/lib/librte_stack/rte_stack_pvt.h > @@ -0,0 +1,34 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2019 Intel Corporation > + */ > + > +#ifndef _RTE_STACK_PVT_H_ > +#define _RTE_STACK_PVT_H_ > + > +#ifdef __cplusplus > +extern "C" { > +#endif > + > +#include > + > +extern int stack_logtype; > + > +#define STACK_LOG(level, fmt, args...) \ > + rte_log(RTE_LOG_ ##level, stack_logtype, "%s(): "fmt "\n", \ > + __func__, ##args) > + > +#define STACK_LOG_ERR(fmt, args...) \ > + STACK_LOG(ERR, fmt, ## args) > + > +#define STACK_LOG_WARN(fmt, args...) \ > + STACK_LOG(WARNING, fmt, ## args) > + > +#define STACK_LOG_INFO(fmt, args...) \ > + STACK_LOG(INFO, fmt, ## args) > + > + > +#ifdef __cplusplus > +} > +#endif > + > +#endif /* _RTE_STACK_PVT_H_ */ > diff --git a/lib/librte_stack/rte_stack_version.map > b/lib/librte_stack/rte_stack_version.map > new file mode 100644 > index 000000000..6662679c3 > --- /dev/null > +++ b/lib/librte_stack/rte_stack_version.map > @@ -0,0 +1,9 @@ > +EXPERIMENTAL { > + global: > + > + rte_stack_create; > + rte_stack_free; > + rte_stack_lookup; > + > + local: *; > +}; > diff --git a/lib/meson.build b/lib/meson.build index 99957ba7d..90115477f > 100644 > --- a/lib/meson.build > +++ b/lib/meson.build > @@ -22,7 +22,7 @@ libraries =3D [ > 'gro', 'gso', 'ip_frag', 'jobstats', > 'kni', 'latencystats', 'lpm', 'member', > 'power', 'pdump', 'rawdev', > - 'reorder', 'sched', 'security', 'vhost', > + 'reorder', 'sched', 'security', 'stack', 'vhost', > #ipsec lib depends on crypto and security > 'ipsec', > # add pkt framework libs which use other libs from above diff --git > a/mk/rte.app.mk b/mk/rte.app.mk index 3c40f9df2..8decfb851 100644 > --- a/mk/rte.app.mk > +++ b/mk/rte.app.mk > @@ -87,6 +87,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_SECURITY) +=3D - > lrte_security > _LDLIBS-$(CONFIG_RTE_LIBRTE_COMPRESSDEV) +=3D -lrte_compressdev > _LDLIBS-$(CONFIG_RTE_LIBRTE_EVENTDEV) +=3D -lrte_eventdev > _LDLIBS-$(CONFIG_RTE_LIBRTE_RAWDEV) +=3D -lrte_rawdev > +_LDLIBS-$(CONFIG_RTE_LIBRTE_STACK) +=3D -lrte_stack > _LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER) +=3D -lrte_timer > _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL) +=3D -lrte_mempool > _LDLIBS-$(CONFIG_RTE_DRIVER_MEMPOOL_RING) +=3D -lrte_mempool_ring > -- > 2.13.6