From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <Honnappa.Nagarahalli@arm.com>
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 <dev@dpdk.org>; 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 <Honnappa.Nagarahalli@arm.com>
To: Gage Eads <gage.eads@intel.com>, "dev@dpdk.org" <dev@dpdk.org>
CC: "olivier.matz@6wind.com" <olivier.matz@6wind.com>,
 "arybchenko@solarflare.com" <arybchenko@solarflare.com>,
 "bruce.richardson@intel.com" <bruce.richardson@intel.com>,
 "konstantin.ananyev@intel.com" <konstantin.ananyev@intel.com>, "Gavin Hu (Arm
 Technology China)" <Gavin.Hu@arm.com>, nd <nd@arm.com>, "thomas@monjalon.net"
 <thomas@monjalon.net>, nd <nd@arm.com>
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: <VE1PR08MB5149B4FD26B816BA51F7B58998590@VE1PR08MB5149.eurprd08.prod.outlook.com>
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: <VE1PR08MB51689D87C7BD56D23FECE07E98590@VE1PR08MB5168.eurprd08.prod.outlook.com>
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 <dev.dpdk.org>
List-Unsubscribe: <https://mails.dpdk.org/options/dev>,
 <mailto:dev-request@dpdk.org?subject=unsubscribe>
List-Archive: <http://mails.dpdk.org/archives/dev/>
List-Post: <mailto:dev@dpdk.org>
List-Help: <mailto:dev-request@dpdk.org?subject=help>
List-Subscribe: <https://mails.dpdk.org/listinfo/dev>,
 <mailto:dev-request@dpdk.org?subject=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 <gage.eads@intel.com>
> 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) <Gavin.Hu@arm.com>; Honnappa Nagarahalli
> <Honnappa.Nagarahalli@arm.com>; nd <nd@arm.com>;
> 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 <gage.eads@intel.com>
> ---
>  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 <gage.eads@intel.com>
> +M: Olivier Matz <olivier.matz@6wind.com>
> +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 <string.h>
> +
> +#include <rte_atomic.h>
> +#include <rte_eal.h>
> +#include <rte_eal_memconfig.h>
> +#include <rte_errno.h>
> +#include <rte_malloc.h>
> +#include <rte_memzone.h>
> +#include <rte_rwlock.h>
> +#include <rte_tailq.h>
> +
> +#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 <rte_errno.h>
> +#include <rte_memzone.h>
> +#include <rte_spinlock.h>
> +
> +#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 <rte_log.h>
> +
> +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: <dev-bounces@dpdk.org>
Received: from dpdk.org (dpdk.org [92.243.14.124])
	by dpdk.space (Postfix) with ESMTP id B3685A0679
	for <public@inbox.dpdk.org>; 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 <dev@dpdk.org>; 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 <Honnappa.Nagarahalli@arm.com>
To: Gage Eads <gage.eads@intel.com>, "dev@dpdk.org" <dev@dpdk.org>
CC: "olivier.matz@6wind.com" <olivier.matz@6wind.com>,
 "arybchenko@solarflare.com" <arybchenko@solarflare.com>,
 "bruce.richardson@intel.com" <bruce.richardson@intel.com>,
 "konstantin.ananyev@intel.com" <konstantin.ananyev@intel.com>, "Gavin Hu (Arm
 Technology China)" <Gavin.Hu@arm.com>, nd <nd@arm.com>, "thomas@monjalon.net"
 <thomas@monjalon.net>, nd <nd@arm.com>
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:
 <VE1PR08MB5149B4FD26B816BA51F7B58998590@VE1PR08MB5149.eurprd08.prod.outlook.com>
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: <VE1PR08MB51689D87C7BD56D23FECE07E98590@VE1PR08MB5168.eurprd08.prod.outlook.com>
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 <dev.dpdk.org>
List-Unsubscribe: <https://mails.dpdk.org/options/dev>,
 <mailto:dev-request@dpdk.org?subject=unsubscribe>
List-Archive: <http://mails.dpdk.org/archives/dev/>
List-Post: <mailto:dev@dpdk.org>
List-Help: <mailto:dev-request@dpdk.org?subject=help>
List-Subscribe: <https://mails.dpdk.org/listinfo/dev>,
 <mailto:dev-request@dpdk.org?subject=subscribe>
Errors-To: dev-bounces@dpdk.org
Sender: "dev" <dev-bounces@dpdk.org>
Message-ID: <20190328232654.PPraIGIf0ljwZBRFNh2LGEJROEMU7PYKtBKoSbRi4Ow@z>

Hi Gage,
	Apologies for the late comments.

> -----Original Message-----
> From: Gage Eads <gage.eads@intel.com>
> 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) <Gavin.Hu@arm.com>; Honnappa Nagarahalli
> <Honnappa.Nagarahalli@arm.com>; nd <nd@arm.com>;
> 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 <gage.eads@intel.com>
> ---
>  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 <gage.eads@intel.com>
> +M: Olivier Matz <olivier.matz@6wind.com>
> +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 <string.h>
> +
> +#include <rte_atomic.h>
> +#include <rte_eal.h>
> +#include <rte_eal_memconfig.h>
> +#include <rte_errno.h>
> +#include <rte_malloc.h>
> +#include <rte_memzone.h>
> +#include <rte_rwlock.h>
> +#include <rte_tailq.h>
> +
> +#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 <rte_errno.h>
> +#include <rte_memzone.h>
> +#include <rte_spinlock.h>
> +
> +#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 <rte_log.h>
> +
> +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