get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/139012/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 139012,
    "url": "https://patches.dpdk.org/api/patches/139012/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/20240401013729.1466298-2-aditya.ambadipudi@arm.com/",
    "project": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<20240401013729.1466298-2-aditya.ambadipudi@arm.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20240401013729.1466298-2-aditya.ambadipudi@arm.com",
    "date": "2024-04-01T01:37:28",
    "name": "[v1,1/2] deque: add multi-thread unsafe double ended queue",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "6f00d2b0ee620210d3edf02a775676f31567ce89",
    "submitter": {
        "id": 3303,
        "url": "https://patches.dpdk.org/api/people/3303/?format=api",
        "name": "Aditya Ambadipudi",
        "email": "aditya.ambadipudi@arm.com"
    },
    "delegate": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/20240401013729.1466298-2-aditya.ambadipudi@arm.com/mbox/",
    "series": [
        {
            "id": 31651,
            "url": "https://patches.dpdk.org/api/series/31651/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=31651",
            "date": "2024-04-01T01:37:27",
            "name": "deque: add multithread unsafe deque library",
            "version": 1,
            "mbox": "https://patches.dpdk.org/series/31651/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/139012/comments/",
    "check": "warning",
    "checks": "https://patches.dpdk.org/api/patches/139012/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from mails.dpdk.org (mails.dpdk.org [217.70.189.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 8C9CD43D9B;\n\tMon,  1 Apr 2024 03:37:48 +0200 (CEST)",
            "from mails.dpdk.org (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id A8190402CC;\n\tMon,  1 Apr 2024 03:37:42 +0200 (CEST)",
            "from foss.arm.com (foss.arm.com [217.140.110.172])\n by mails.dpdk.org (Postfix) with ESMTP id 5EFE940265\n for <dev@dpdk.org>; Mon,  1 Apr 2024 03:37:41 +0200 (CEST)",
            "from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14])\n by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 2912011FB;\n Sun, 31 Mar 2024 18:38:13 -0700 (PDT)",
            "from 2u-thunderx2.usa.Arm.com (unknown [10.118.12.78])\n by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 411B13F64C;\n Sun, 31 Mar 2024 18:37:40 -0700 (PDT)"
        ],
        "From": "Aditya Ambadipudi <aditya.ambadipudi@arm.com>",
        "To": "dev@dpdk.org, jackmin@nvidia.com, stephen@networkplumber.org,\n matan@nvidia.com, viacheslavo@nvidia.com, roretzla@linux.microsoft.com,\n konstantin.v.ananyev@yandex.ru, konstantin.ananyev@huawei.com,\n mb@smartsharesystems.com, hofors@lysator.liu.se",
        "Cc": "Honnappa.Nagarahalli@arm.com, Dhruv.Tripathi@arm.com,\n wathsala.vithanage@arm.com, aditya.ambadipudi@arm.com,\n ganeshaditya1@gmail.com, nd@arm.com,\n Honnappa Nagarahalli <honnappa.nagarahalli@arm.com>",
        "Subject": "[PATCH v1 1/2] deque: add multi-thread unsafe double ended queue",
        "Date": "Sun, 31 Mar 2024 20:37:28 -0500",
        "Message-Id": "<20240401013729.1466298-2-aditya.ambadipudi@arm.com>",
        "X-Mailer": "git-send-email 2.25.1",
        "In-Reply-To": "<20240401013729.1466298-1-aditya.ambadipudi@arm.com>",
        "References": "<20230821060420.3509667-1-honnappa.nagarahalli@arm.com>\n <20240401013729.1466298-1-aditya.ambadipudi@arm.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <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>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org"
    },
    "content": "From: Honnappa Nagarahalli <honnappa.nagarahalli@arm.com>\n\nAdd a multi-thread unsafe double ended queue data structure. This\nlibrary provides a simple and efficient alternative to multi-thread\nsafe ring when multi-thread safety is not required.\n\nSigned-off-by: Aditya Ambadipudi <aditya.ambadipudi@arm.com>\nSigned-off-by: Honnappa Nagarahalli <honnappa.nagarahalli@arm.com>\n---\n .mailmap                   |   1 +\n lib/deque/meson.build      |  11 +\n lib/deque/rte_deque.c      | 194 +++++++++++++\n lib/deque/rte_deque.h      | 533 ++++++++++++++++++++++++++++++++++++\n lib/deque/rte_deque_core.h |  82 ++++++\n lib/deque/rte_deque_pvt.h  | 538 +++++++++++++++++++++++++++++++++++++\n lib/deque/rte_deque_zc.h   | 430 +++++++++++++++++++++++++++++\n lib/deque/version.map      |  14 +\n lib/meson.build            |   1 +\n 9 files changed, 1804 insertions(+)\n create mode 100644 lib/deque/meson.build\n create mode 100644 lib/deque/rte_deque.c\n create mode 100644 lib/deque/rte_deque.h\n create mode 100644 lib/deque/rte_deque_core.h\n create mode 100644 lib/deque/rte_deque_pvt.h\n create mode 100644 lib/deque/rte_deque_zc.h\n create mode 100644 lib/deque/version.map",
    "diff": "diff --git a/.mailmap b/.mailmap\nindex 3843868716..8e705ab6ab 100644\n--- a/.mailmap\n+++ b/.mailmap\n@@ -17,6 +17,7 @@ Adam Bynes <adambynes@outlook.com>\n Adam Dybkowski <adamx.dybkowski@intel.com>\n Adam Ludkiewicz <adam.ludkiewicz@intel.com>\n Adham Masarwah <adham@nvidia.com> <adham@mellanox.com>\n+Aditya Ambadipudi <aditya.ambadipudi@arm.com>\n Adrian Moreno <amorenoz@redhat.com>\n Adrian Podlawski <adrian.podlawski@intel.com>\n Adrien Mazarguil <adrien.mazarguil@6wind.com>\ndiff --git a/lib/deque/meson.build b/lib/deque/meson.build\nnew file mode 100644\nindex 0000000000..1ff45fc39f\n--- /dev/null\n+++ b/lib/deque/meson.build\n@@ -0,0 +1,11 @@\n+# SPDX-License-Identifier: BSD-3-Clause\n+# Copyright(c) 2024 Arm Limited\n+\n+sources = files('rte_deque.c')\n+headers = files('rte_deque.h')\n+# most sub-headers are not for direct inclusion\n+indirect_headers += files (\n+        'rte_deque_core.h',\n+        'rte_deque_pvt.h',\n+        'rte_deque_zc.h'\n+)\ndiff --git a/lib/deque/rte_deque.c b/lib/deque/rte_deque.c\nnew file mode 100644\nindex 0000000000..3b08b91a98\n--- /dev/null\n+++ b/lib/deque/rte_deque.c\n@@ -0,0 +1,194 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2024 Arm Limited\n+ */\n+\n+#include <stdio.h>\n+#include <stdalign.h>\n+#include <string.h>\n+#include <stdint.h>\n+#include <inttypes.h>\n+#include <errno.h>\n+#include <sys/queue.h>\n+\n+#include <rte_common.h>\n+#include <rte_log.h>\n+#include <rte_memzone.h>\n+#include <rte_malloc.h>\n+#include <rte_eal_memconfig.h>\n+#include <rte_errno.h>\n+#include <rte_string_fns.h>\n+\n+#include \"rte_deque.h\"\n+\n+/* mask of all valid flag values to deque_create() */\n+#define __RTE_DEQUE_F_MASK (RTE_DEQUE_F_EXACT_SZ)\n+ssize_t\n+rte_deque_get_memsize_elem(unsigned int esize, unsigned int count)\n+{\n+\tssize_t sz;\n+\n+\t/* Check if element size is a multiple of 4B */\n+\tif (esize % 4 != 0) {\n+\t\trte_log(RTE_LOG_ERR, rte_deque_log_type,\n+\t\t\t\"%s(): element size is not a multiple of 4\\n\",\n+\t\t\t__func__);\n+\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/* count must be a power of 2 */\n+\tif ((!RTE_IS_POWER_OF_2(count)) || (count > RTE_DEQUE_SZ_MASK)) {\n+\t\trte_log(RTE_LOG_ERR, rte_deque_log_type,\n+\t\t\t\"%s(): Requested number of elements is invalid,\"\n+\t\t\t\"must be power of 2, and not exceed %u\\n\",\n+\t\t\t__func__, RTE_DEQUE_SZ_MASK);\n+\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tsz = sizeof(struct rte_deque) + (ssize_t)count * esize;\n+\tsz = RTE_ALIGN(sz, RTE_CACHE_LINE_SIZE);\n+\treturn sz;\n+}\n+\n+void\n+rte_deque_reset(struct rte_deque *d)\n+{\n+\td->head = 0;\n+\td->tail = 0;\n+}\n+\n+int\n+rte_deque_init(struct rte_deque *d, const char *name, unsigned int count,\n+\tunsigned int flags)\n+{\n+\tint ret;\n+\n+\t/* compilation-time checks */\n+\tRTE_BUILD_BUG_ON((sizeof(struct rte_deque) &\n+\t\t\t  RTE_CACHE_LINE_MASK) != 0);\n+\n+\t/* future proof flags, only allow supported values */\n+\tif (flags & ~__RTE_DEQUE_F_MASK) {\n+\t\trte_log(RTE_LOG_ERR, rte_deque_log_type,\n+\t\t\t\"%s(): Unsupported flags requested %#x\\n\",\n+\t\t\t__func__, flags);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/* init the deque structure */\n+\tmemset(d, 0, sizeof(*d));\n+\tret = strlcpy(d->name, name, sizeof(d->name));\n+\tif (ret < 0 || ret >= (int)sizeof(d->name))\n+\t\treturn -ENAMETOOLONG;\n+\td->flags = flags;\n+\n+\tif (flags & RTE_DEQUE_F_EXACT_SZ) {\n+\t\td->size = rte_align32pow2(count + 1);\n+\t\td->mask = d->size - 1;\n+\t\td->capacity = count;\n+\t} else {\n+\t\tif ((!RTE_IS_POWER_OF_2(count)) || (count > RTE_DEQUE_SZ_MASK)) {\n+\t\t\trte_log(RTE_LOG_ERR, rte_deque_log_type,\n+\t\t\t\t\"%s(): Requested size is invalid, must be power\"\n+\t\t\t\t\" of 2, and not exceed the size limit %u\\n\",\n+\t\t\t\t__func__, RTE_DEQUE_SZ_MASK);\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t\td->size = count;\n+\t\td->mask = count - 1;\n+\t\td->capacity = d->mask;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/* create the deque for a given element size */\n+struct rte_deque *\n+rte_deque_create(const char *name, unsigned int esize, unsigned int count,\n+\t\tint socket_id, unsigned int flags)\n+{\n+\tchar mz_name[RTE_MEMZONE_NAMESIZE];\n+\tstruct rte_deque *d;\n+\tconst struct rte_memzone *mz;\n+\tssize_t deque_size;\n+\tint mz_flags = 0;\n+\tconst unsigned int requested_count = count;\n+\tint ret;\n+\n+\t/* for an exact size deque, round up from count to a power of two */\n+\tif (flags & RTE_DEQUE_F_EXACT_SZ)\n+\t\tcount = rte_align32pow2(count + 1);\n+\n+\tdeque_size = rte_deque_get_memsize_elem(esize, count);\n+\tif (deque_size < 0) {\n+\t\trte_errno = -deque_size;\n+\t\treturn NULL;\n+\t}\n+\n+\tret = snprintf(mz_name, sizeof(mz_name), \"%s%s\",\n+\t\tRTE_DEQUE_MZ_PREFIX, name);\n+\tif (ret < 0 || ret >= (int)sizeof(mz_name)) {\n+\t\trte_errno = ENAMETOOLONG;\n+\t\treturn NULL;\n+\t}\n+\n+\t/* reserve a memory zone for this deque. If we can't get rte_config or\n+\t * we are secondary process, the memzone_reserve function will set\n+\t * rte_errno for us appropriately - hence no check in this function\n+\t */\n+\tmz = rte_memzone_reserve_aligned(mz_name, deque_size, socket_id,\n+\t\t\t\t\t mz_flags, alignof(struct rte_deque));\n+\tif (mz != NULL) {\n+\t\td = mz->addr;\n+\t\t/* no need to check return value here, we already checked the\n+\t\t * arguments above\n+\t\t */\n+\t\trte_deque_init(d, name, requested_count, flags);\n+\t\td->memzone = mz;\n+\t} else {\n+\t\td = NULL;\n+\t\trte_log(RTE_LOG_ERR, rte_deque_log_type,\n+\t\t\t\"%s(): Cannot reserve memory\\n\", __func__);\n+\t}\n+\treturn d;\n+}\n+\n+/* free the deque */\n+void\n+rte_deque_free(struct rte_deque *d)\n+{\n+\tif (d == NULL)\n+\t\treturn;\n+\n+\t/*\n+\t * Deque was not created with rte_deque_create,\n+\t * therefore, there is no memzone to free.\n+\t */\n+\tif (d->memzone == NULL) {\n+\t\trte_log(RTE_LOG_ERR, rte_deque_log_type,\n+\t\t\t\"%s(): Cannot free deque, not created \"\n+\t\t\t\"with rte_deque_create()\\n\", __func__);\n+\t\treturn;\n+\t}\n+\n+\tif (rte_memzone_free(d->memzone) != 0)\n+\t\trte_log(RTE_LOG_ERR, rte_deque_log_type,\n+\t\t\t\"%s(): Cannot free memory\\n\", __func__);\n+}\n+\n+/* dump the status of the deque on the console */\n+void\n+rte_deque_dump(FILE *f, const struct rte_deque *d)\n+{\n+\tfprintf(f, \"deque <%s>@%p\\n\", d->name, d);\n+\tfprintf(f, \"  flags=%x\\n\", d->flags);\n+\tfprintf(f, \"  size=%\"PRIu32\"\\n\", d->size);\n+\tfprintf(f, \"  capacity=%\"PRIu32\"\\n\", d->capacity);\n+\tfprintf(f, \"  head=%\"PRIu32\"\\n\", d->head);\n+\tfprintf(f, \"  tail=%\"PRIu32\"\\n\", d->tail);\n+\tfprintf(f, \"  used=%u\\n\", rte_deque_count(d));\n+\tfprintf(f, \"  avail=%u\\n\", rte_deque_free_count(d));\n+}\n+\n+RTE_LOG_REGISTER_DEFAULT(rte_deque_log_type, ERR);\ndiff --git a/lib/deque/rte_deque.h b/lib/deque/rte_deque.h\nnew file mode 100644\nindex 0000000000..1ac74ca539\n--- /dev/null\n+++ b/lib/deque/rte_deque.h\n@@ -0,0 +1,533 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2024 Arm Limited\n+ */\n+\n+#ifndef _RTE_DEQUE_H_\n+#define _RTE_DEQUE_H_\n+\n+/**\n+ * @file\n+ * RTE double ended queue (Deque)\n+ *\n+ * This fixed-size queue does not provide concurrent access by\n+ * multiple threads. If required, the application should use locks\n+ * to protect the deque from concurrent access.\n+ *\n+ * - Double ended queue\n+ * - Maximum size is fixed\n+ * - Store objects of any size\n+ * - Single/bulk/burst dequeue at tail or head\n+ * - Single/bulk/burst enqueue at head or tail\n+ *\n+ */\n+\n+#ifdef __cplusplus\n+extern \"C\" {\n+#endif\n+\n+#include <rte_deque_core.h>\n+#include <rte_deque_pvt.h>\n+#include <rte_deque_zc.h>\n+\n+/**\n+ * Calculate the memory size needed for a deque\n+ *\n+ * This function returns the number of bytes needed for a deque, given\n+ * the number of objects and the object size. This value is the sum of\n+ * the size of the structure rte_deque and the size of the memory needed\n+ * by the objects. The value is aligned to a cache line size.\n+ *\n+ * @param esize\n+ *   The size of deque object, in bytes. It must be a multiple of 4.\n+ * @param count\n+ *   The number of objects in the deque (must be a power of 2).\n+ * @return\n+ *   - The memory size needed for the deque on success.\n+ *   - -EINVAL if count is not a power of 2.\n+ */\n+__rte_experimental\n+ssize_t rte_deque_get_memsize_elem(unsigned int esize, unsigned int count);\n+\n+/**\n+ * Initialize a deque structure.\n+ *\n+ * Initialize a deque structure in memory pointed by \"d\". The size of the\n+ * memory area must be large enough to store the deque structure and the\n+ * object table. It is advised to use rte_deque_get_memsize() to get the\n+ * appropriate size.\n+ *\n+ * The deque size is set to *count*, which must be a power of two.\n+ * The real usable deque size is *count-1* instead of *count* to\n+ * differentiate a full deque from an empty deque.\n+ *\n+ * @param d\n+ *   The pointer to the deque structure followed by the objects table.\n+ * @param name\n+ *   The name of the deque.\n+ * @param count\n+ *   The number of objects in the deque (must be a power of 2,\n+ *   unless RTE_DEQUE_F_EXACT_SZ is set in flags).\n+ * @param flags\n+ *   - RTE_DEQUE_F_EXACT_SZ: If this flag is set, the deque will hold\n+ *     exactly the requested number of objects, and the requested size\n+ *     will be rounded up to the next power of two, but the usable space\n+ *     will be exactly that requested. Worst case, if a power-of-2 size is\n+ *     requested, half the deque space will be wasted.\n+ *     Without this flag set, the deque size requested must be a power of 2,\n+ *     and the usable space will be that size - 1.\n+ * @return\n+ *   0 on success, or a negative value on error.\n+ */\n+__rte_experimental\n+int rte_deque_init(struct rte_deque *d, const char *name, unsigned int count,\n+\t\tunsigned int flags);\n+\n+/**\n+ * Create a new deque named *name* in memory.\n+ *\n+ * This function uses ``memzone_reserve()`` to allocate memory. Then it\n+ * calls rte_deque_init() to initialize an empty deque.\n+ *\n+ * The new deque size is set to *count*, which must be a power of two.\n+ * The real usable deque size is *count-1* instead of *count* to\n+ * differentiate a full deque from an empty deque.\n+ *\n+ * @param name\n+ *   The name of the deque.\n+ * @param esize\n+ *   The size of deque object, in bytes. It must be a multiple of 4.\n+ * @param count\n+ *   The size of the deque (must be a power of 2,\n+ *   unless RTE_DEQUE_F_EXACT_SZ is set in flags).\n+ * @param socket_id\n+ *   The *socket_id* argument is the socket identifier in case of\n+ *   NUMA. The value can be *SOCKET_ID_ANY* if there is no NUMA\n+ *   constraint for the reserved zone.\n+ * @param flags\n+ *   - RTE_DEQUE_F_EXACT_SZ: If this flag is set, the deque will hold exactly the\n+ *     requested number of entries, and the requested size will be rounded up\n+ *     to the next power of two, but the usable space will be exactly that\n+ *     requested. Worst case, if a power-of-2 size is requested, half the\n+ *     deque space will be wasted.\n+ *     Without this flag set, the deque size requested must be a power of 2,\n+ *     and the usable space will be that size - 1.\n+ * @return\n+ *   On success, the pointer to the new allocated deque. NULL on error with\n+ *    rte_errno set appropriately. Possible errno values include:\n+ *    - E_RTE_NO_CONFIG - function could not get pointer to rte_config structure\n+ *    - EINVAL - count provided is not a power of 2\n+ *    - ENOSPC - the maximum number of memzones has already been allocated\n+ *    - EEXIST - a memzone with the same name already exists\n+ *    - ENOMEM - no appropriate memory area found in which to create memzone\n+ */\n+__rte_experimental\n+struct rte_deque *rte_deque_create(const char *name, unsigned int esize,\n+\t\t\t\tunsigned int count, int socket_id,\n+\t\t\t\tunsigned int flags);\n+\n+/**\n+ * De-allocate all memory used by the deque.\n+ *\n+ * @param d\n+ *   Deque to free.\n+ *   If NULL then, the function does nothing.\n+ */\n+__rte_experimental\n+void rte_deque_free(struct rte_deque *d);\n+\n+/**\n+ * Dump the status of the deque to a file.\n+ *\n+ * @param f\n+ *   A pointer to a file for output\n+ * @param d\n+ *   A pointer to the deque structure.\n+ */\n+__rte_experimental\n+void rte_deque_dump(FILE *f, const struct rte_deque *d);\n+\n+/**\n+ * Return the number of entries in a deque.\n+ *\n+ * @param d\n+ *   A pointer to the deque structure.\n+ * @return\n+ *   The number of entries in the deque.\n+ */\n+static inline unsigned int\n+rte_deque_count(const struct rte_deque *d)\n+{\n+\treturn (d->head - d->tail) & d->mask;\n+}\n+\n+/**\n+ * Return the number of free entries in a deque.\n+ *\n+ * @param d\n+ *   A pointer to the deque structure.\n+ * @return\n+ *   The number of free entries in the deque.\n+ */\n+static inline unsigned int\n+rte_deque_free_count(const struct rte_deque *d)\n+{\n+\treturn d->capacity - rte_deque_count(d);\n+}\n+\n+/**\n+ * Enqueue fixed number of objects on a deque.\n+ *\n+ * This function copies the objects at the head of the deque and\n+ * moves the head index.\n+ *\n+ * @param d\n+ *   A pointer to the deque structure.\n+ * @param obj_table\n+ *   A pointer to a table of objects.\n+ * @param esize\n+ *   The size of deque object, in bytes. It must be a multiple of 4.\n+ *   This must be the same value used while creating the deque. Otherwise\n+ *   the results are undefined.\n+ * @param n\n+ *   The number of objects to add in the deque from the obj_table.\n+ * @param free_space\n+ *   Returns the amount of space in the deque after the enqueue operation\n+ *   has finished.\n+ * @return\n+ *   The number of objects enqueued, either 0 or n\n+ */\n+__rte_experimental\n+static __rte_always_inline unsigned int\n+rte_deque_enqueue_bulk_elem(struct rte_deque *d,\n+\t\t\tconst void *obj_table,\n+\t\t\tunsigned int esize,\n+\t\t\tunsigned int n,\n+\t\t\tunsigned int *free_space)\n+{\n+\t*free_space = rte_deque_free_count(d);\n+\tif (unlikely(n > *free_space))\n+\t\treturn 0;\n+\t*free_space -= n;\n+\treturn __rte_deque_enqueue_at_head(d, obj_table, esize, n);\n+}\n+\n+/**\n+ * Enqueue up to a maximum number of objects on a deque.\n+ *\n+ * This function copies the objects at the head of the deque and\n+ * moves the head index.\n+ *\n+ * @param d\n+ *   A pointer to the deque structure.\n+ * @param obj_table\n+ *   A pointer to a table of objects.\n+ * @param esize\n+ *   The size of deque object, in bytes. It must be a multiple of 4.\n+ *   This must be the same value used while creating the deque. Otherwise\n+ *   the results are undefined.\n+ * @param n\n+ *   The number of objects to add in the deque from the obj_table.\n+ * @param free_space\n+ *   Returns the amount of space in the deque after the enqueue operation\n+ *   has finished.\n+ * @return\n+ *   - n: Actual number of objects enqueued.\n+ */\n+__rte_experimental\n+static __rte_always_inline unsigned int\n+rte_deque_enqueue_burst_elem(struct rte_deque *d, const void *obj_table,\n+\t\t\tunsigned int esize, unsigned int n,\n+\t\t\tunsigned int *free_space)\n+{\n+\tunsigned int avail_space = rte_deque_free_count(d);\n+\tunsigned int to_be_enqueued = (n <= avail_space ? n : avail_space);\n+\t*free_space = avail_space - n;\n+\treturn __rte_deque_enqueue_at_head(d, obj_table, esize, to_be_enqueued);\n+}\n+\n+/**\n+ * Enqueue fixed number of objects on a deque at the tail.\n+ *\n+ * This function copies the objects at the tail of the deque and\n+ * moves the tail index (backwards).\n+ *\n+ * @param d\n+ *   A pointer to the deque structure.\n+ * @param obj_table\n+ *   A pointer to a table of objects.\n+ * @param esize\n+ *   The size of deque object, in bytes. It must be a multiple of 4.\n+ *   This must be the same value used while creating the deque. Otherwise\n+ *   the results are undefined.\n+ * @param n\n+ *   The number of objects to add in the deque from the obj_table.\n+ * @param free_space\n+ *   Returns the amount of space in the deque after the enqueue operation\n+ *   has finished.\n+ * @return\n+ *   The number of objects enqueued, either 0 or n\n+ */\n+__rte_experimental\n+static __rte_always_inline unsigned int\n+rte_deque_enqueue_at_tail_bulk_elem(struct rte_deque *d,\n+\t\t\t\t const void *obj_table, unsigned int esize,\n+\t\t\t\t unsigned int n, unsigned int *free_space)\n+{\n+\t*free_space = rte_deque_free_count(d);\n+\tif (unlikely(n > *free_space))\n+\t\treturn 0;\n+\t*free_space -= n;\n+\treturn __rte_deque_enqueue_at_tail(d, obj_table, esize, n);\n+}\n+\n+/**\n+ * Enqueue up to a maximum number of objects on a deque at the tail.\n+ *\n+ * This function copies the objects at the tail of the deque and\n+ * moves the tail index (backwards).\n+ *\n+ * @param d\n+ *   A pointer to the deque structure.\n+ * @param obj_table\n+ *   A pointer to a table of objects.\n+ * @param esize\n+ *   The size of deque object, in bytes. It must be a multiple of 4.\n+ *   This must be the same value used while creating the deque. Otherwise\n+ *   the results are undefined.\n+ * @param n\n+ *   The number of objects to add in the deque from the obj_table.\n+ * @param free_space\n+ *   Returns the amount of space in the deque after the enqueue operation\n+ *   has finished.\n+ * @return\n+ *   - n: Actual number of objects enqueued.\n+ */\n+__rte_experimental\n+static __rte_always_inline unsigned int\n+rte_deque_enqueue_at_tail_burst_elem(struct rte_deque *d,\n+\t\t\t\tconst void *obj_table, unsigned int esize,\n+\t\t\t\tunsigned int n, unsigned int *free_space)\n+{\n+\tunsigned int avail_space = rte_deque_free_count(d);\n+\tunsigned int to_be_enqueued = (n <= avail_space ? n : avail_space);\n+\t*free_space = avail_space - to_be_enqueued;\n+\treturn __rte_deque_enqueue_at_tail(d, obj_table, esize, to_be_enqueued);\n+}\n+\n+/**\n+ * Dequeue a fixed number of objects from a deque.\n+ *\n+ * This function copies the objects from the tail of the deque and\n+ * moves the tail index.\n+ *\n+ * @param d\n+ *   A pointer to the deque structure.\n+ * @param obj_table\n+ *   A pointer to a table of objects that will be filled.\n+ * @param esize\n+ *   The size of deque object, in bytes. It must be a multiple of 4.\n+ *   This must be the same value used while creating the deque. Otherwise\n+ *   the results are undefined.\n+ * @param n\n+ *   The number of objects to dequeue from the deque to the obj_table.\n+ * @param available\n+ *   Returns the number of remaining deque entries after the dequeue\n+ *   has finished.\n+ * @return\n+ *   The number of objects dequeued, either 0 or n\n+ */\n+__rte_experimental\n+static __rte_always_inline unsigned int\n+rte_deque_dequeue_bulk_elem(struct rte_deque *d, void *obj_table,\n+\t\t\tunsigned int esize, unsigned int n,\n+\t\t\tunsigned int *available)\n+{\n+\t*available = rte_deque_count(d);\n+\tif (unlikely(n > *available))\n+\t\treturn 0;\n+\t*available -= n;\n+\treturn __rte_deque_dequeue_at_tail(d, obj_table, esize, n);\n+}\n+\n+/**\n+ * Dequeue up to a maximum number of objects from a deque.\n+ *\n+ * This function copies the objects from the tail of the deque and\n+ * moves the tail index.\n+ *\n+ * @param d\n+ *   A pointer to the deque structure.\n+ * @param obj_table\n+ *   A pointer to a table of objects that will be filled.\n+ * @param esize\n+ *   The size of deque object, in bytes. It must be a multiple of 4.\n+ *   This must be the same value used while creating the deque. Otherwise\n+ *   the results are undefined.\n+ * @param n\n+ *   The number of objects to dequeue from the deque to the obj_table.\n+ * @param available\n+ *   Returns the number of remaining deque entries after the dequeue\n+ *   has finished.\n+ * @return\n+ *   - Number of objects dequeued\n+ */\n+__rte_experimental\n+static __rte_always_inline unsigned int\n+rte_deque_dequeue_burst_elem(struct rte_deque *d, void *obj_table,\n+\t\t\tunsigned int esize, unsigned int n,\n+\t\t\tunsigned int *available)\n+{\n+\tunsigned int count = rte_deque_count(d);\n+\tunsigned int to_be_dequeued = (n <= count ? n : count);\n+\t*available = count - to_be_dequeued;\n+\treturn __rte_deque_dequeue_at_tail(d, obj_table, esize, to_be_dequeued);\n+}\n+\n+/**\n+ * Dequeue a fixed number of objects from a deque from the head.\n+ *\n+ * This function copies the objects from the head of the deque and\n+ * moves the head index (backwards).\n+ *\n+ * @param d\n+ *   A pointer to the deque structure.\n+ * @param obj_table\n+ *   A pointer to a table of objects that will be filled.\n+ * @param esize\n+ *   The size of deque object, in bytes. It must be a multiple of 4.\n+ *   This must be the same value used while creating the deque. Otherwise\n+ *   the results are undefined.\n+ * @param n\n+ *   The number of objects to dequeue from the deque to the obj_table.\n+ * @param available\n+ *   Returns the number of remaining deque entries after the dequeue\n+ *   has finished.\n+ * @return\n+ *   The number of objects dequeued, either 0 or n\n+ */\n+__rte_experimental\n+static __rte_always_inline unsigned int\n+rte_deque_dequeue_at_head_bulk_elem(struct rte_deque *d, void *obj_table,\n+\t\t\tunsigned int esize, unsigned int n,\n+\t\t\tunsigned int *available)\n+{\n+\t*available = rte_deque_count(d);\n+\tif (unlikely(n > *available))\n+\t\treturn 0;\n+\t*available -= n;\n+\treturn __rte_deque_dequeue_at_head(d, obj_table, esize, n);\n+}\n+\n+/**\n+ * Dequeue up to a maximum number of objects from a deque from the head.\n+ *\n+ * This function copies the objects from the head of the deque and\n+ * moves the head index (backwards).\n+ *\n+ * @param d\n+ *   A pointer to the deque structure.\n+ * @param obj_table\n+ *   A pointer to a table of objects that will be filled.\n+ * @param esize\n+ *   The size of deque object, in bytes. It must be a multiple of 4.\n+ *   This must be the same value used while creating the deque. Otherwise\n+ *   the results are undefined.\n+ * @param n\n+ *   The number of objects to dequeue from the deque to the obj_table.\n+ * @param available\n+ *   Returns the number of remaining deque entries after the dequeue\n+ *   has finished.\n+ * @return\n+ *   - Number of objects dequeued\n+ */\n+__rte_experimental\n+static __rte_always_inline unsigned int\n+rte_deque_dequeue_at_head_burst_elem(struct rte_deque *d, void *obj_table,\n+\t\t\tunsigned int esize, unsigned int n,\n+\t\t\tunsigned int *available)\n+{\n+\tunsigned int count = rte_deque_count(d);\n+\tunsigned int to_be_dequeued = (n <= count ? n : count);\n+\t*available = count - to_be_dequeued;\n+\treturn __rte_deque_dequeue_at_head(d, obj_table, esize, to_be_dequeued);\n+}\n+\n+/**\n+ * Flush a deque.\n+ *\n+ * This function flush all the objects in a deque\n+ *\n+ * @warning\n+ * Make sure the deque is not in use while calling this function.\n+ *\n+ * @param d\n+ *   A pointer to the deque structure.\n+ */\n+__rte_experimental\n+void rte_deque_reset(struct rte_deque *d);\n+\n+/**\n+ * Test if a deque is full.\n+ *\n+ * @param d\n+ *   A pointer to the deque structure.\n+ * @return\n+ *   - 1: The deque is full.\n+ *   - 0: The deque is not full.\n+ */\n+static inline int\n+rte_deque_full(const struct rte_deque *d)\n+{\n+\treturn rte_deque_free_count(d) == 0;\n+}\n+\n+/**\n+ * Test if a deque is empty.\n+ *\n+ * @param d\n+ *   A pointer to the deque structure.\n+ * @return\n+ *   - 1: The deque is empty.\n+ *   - 0: The deque is not empty.\n+ */\n+static inline int\n+rte_deque_empty(const struct rte_deque *d)\n+{\n+\treturn d->tail == d->head;\n+}\n+\n+/**\n+ * Return the size of the deque.\n+ *\n+ * @param d\n+ *   A pointer to the deque structure.\n+ * @return\n+ *   The size of the data store used by the deque.\n+ *   NOTE: this is not the same as the usable space in the deque. To query that\n+ *   use ``rte_deque_get_capacity()``.\n+ */\n+static inline unsigned int\n+rte_deque_get_size(const struct rte_deque *d)\n+{\n+\treturn d->size;\n+}\n+\n+/**\n+ * Return the number of objects which can be stored in the deque.\n+ *\n+ * @param d\n+ *   A pointer to the deque structure.\n+ * @return\n+ *   The usable size of the deque.\n+ */\n+static inline unsigned int\n+rte_deque_get_capacity(const struct rte_deque *d)\n+{\n+\treturn d->capacity;\n+}\n+\n+#ifdef __cplusplus\n+}\n+#endif\n+\n+#endif /* _RTE_DEQUE_H_ */\ndiff --git a/lib/deque/rte_deque_core.h b/lib/deque/rte_deque_core.h\nnew file mode 100644\nindex 0000000000..ff82b80d38\n--- /dev/null\n+++ b/lib/deque/rte_deque_core.h\n@@ -0,0 +1,82 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2024 Arm Limited\n+ */\n+\n+#ifndef _RTE_DEQUE_CORE_H_\n+#define _RTE_DEQUE_CORE_H_\n+\n+/**\n+ * @file\n+ * This file contains definition of RTE deque structure, init flags and\n+ * some related macros. This file should not be included directly,\n+ * include rte_deque.h instead.\n+ */\n+\n+#ifdef __cplusplus\n+extern \"C\" {\n+#endif\n+\n+#include <stdio.h>\n+#include <stdint.h>\n+#include <string.h>\n+#include <errno.h>\n+#include <rte_common.h>\n+#include <rte_config.h>\n+#include <rte_memory.h>\n+#include <rte_lcore.h>\n+#include <rte_atomic.h>\n+#include <rte_branch_prediction.h>\n+#include <rte_memzone.h>\n+#include <rte_pause.h>\n+#include <rte_debug.h>\n+\n+extern int rte_deque_log_type;\n+\n+#define RTE_DEQUE_MZ_PREFIX \"DEQUE_\"\n+/** The maximum length of a deque name. */\n+#define RTE_DEQUE_NAMESIZE (RTE_MEMZONE_NAMESIZE - \\\n+\t\t\t   sizeof(RTE_DEQUE_MZ_PREFIX) + 1)\n+\n+/**\n+ * Double ended queue (deque) structure.\n+ *\n+ * The producer and the consumer have a head and a tail index. These indices\n+ * are not between 0 and size(deque)-1. These indices are between 0 and\n+ * 2^32 -1. Their value is masked while accessing the objects in deque.\n+ * These indices are unsigned 32bits. Hence the result of the subtraction is\n+ * always a modulo of 2^32 and it is between 0 and capacity.\n+ */\n+struct rte_deque {\n+\talignas(RTE_CACHE_LINE_SIZE) char name[RTE_DEQUE_NAMESIZE];\n+\t/**< Name of the deque */\n+\tint flags;\n+\t/**< Flags supplied at creation. */\n+\tconst struct rte_memzone *memzone;\n+\t/**< Memzone, if any, containing the rte_deque */\n+\n+\talignas(RTE_CACHE_LINE_SIZE) char pad0; /**< empty cache line */\n+\n+\tuint32_t size;           /**< Size of deque. */\n+\tuint32_t mask;           /**< Mask (size-1) of deque. */\n+\tuint32_t capacity;       /**< Usable size of deque */\n+\t/** Ring head and tail pointers. */\n+\tvolatile uint32_t head;\n+\tvolatile uint32_t tail;\n+};\n+\n+/**\n+ * Deque is to hold exactly requested number of entries.\n+ * Without this flag set, the deque size requested must be a power of 2, and the\n+ * usable space will be that size - 1. With the flag, the requested size will\n+ * be rounded up to the next power of two, but the usable space will be exactly\n+ * that requested. Worst case, if a power-of-2 size is requested, half the\n+ * deque space will be wasted.\n+ */\n+#define RTE_DEQUE_F_EXACT_SZ 0x0004\n+#define RTE_DEQUE_SZ_MASK  (0x7fffffffU) /**< Ring size mask */\n+\n+#ifdef __cplusplus\n+}\n+#endif\n+\n+#endif /* _RTE_DEQUE_CORE_H_ */\ndiff --git a/lib/deque/rte_deque_pvt.h b/lib/deque/rte_deque_pvt.h\nnew file mode 100644\nindex 0000000000..931bbd4d19\n--- /dev/null\n+++ b/lib/deque/rte_deque_pvt.h\n@@ -0,0 +1,538 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2024 Arm Limited\n+ */\n+\n+#ifndef _RTE_DEQUE_PVT_H_\n+#define _RTE_DEQUE_PVT_H_\n+\n+#define __RTE_DEQUE_COUNT(d) ((d->head - d->tail) & d->mask)\n+#define __RTE_DEQUE_FREE_SPACE(d) (d->capacity - __RTE_DEQUE_COUNT(d))\n+\n+static __rte_always_inline void\n+__rte_deque_enqueue_elems_head_32(struct rte_deque *d,\n+\t\t\t\tconst unsigned int size,\n+\t\t\t\tuint32_t idx,\n+\t\t\t\tconst void *obj_table,\n+\t\t\t\tunsigned int n)\n+{\n+\tunsigned int i;\n+\tuint32_t *deque = (uint32_t *)&d[1];\n+\tconst uint32_t *obj = (const uint32_t *)obj_table;\n+\tif (likely(idx + n <= size)) {\n+\t\tfor (i = 0; i < (n & ~0x7); i += 8, idx += 8) {\n+\t\t\tdeque[idx] = obj[i];\n+\t\t\tdeque[idx + 1] = obj[i + 1];\n+\t\t\tdeque[idx + 2] = obj[i + 2];\n+\t\t\tdeque[idx + 3] = obj[i + 3];\n+\t\t\tdeque[idx + 4] = obj[i + 4];\n+\t\t\tdeque[idx + 5] = obj[i + 5];\n+\t\t\tdeque[idx + 6] = obj[i + 6];\n+\t\t\tdeque[idx + 7] = obj[i + 7];\n+\t\t}\n+\t\tswitch (n & 0x7) {\n+\t\tcase 7:\n+\t\t\tdeque[idx++] = obj[i++]; /* fallthrough */\n+\t\tcase 6:\n+\t\t\tdeque[idx++] = obj[i++]; /* fallthrough */\n+\t\tcase 5:\n+\t\t\tdeque[idx++] = obj[i++]; /* fallthrough */\n+\t\tcase 4:\n+\t\t\tdeque[idx++] = obj[i++]; /* fallthrough */\n+\t\tcase 3:\n+\t\t\tdeque[idx++] = obj[i++]; /* fallthrough */\n+\t\tcase 2:\n+\t\t\tdeque[idx++] = obj[i++]; /* fallthrough */\n+\t\tcase 1:\n+\t\t\tdeque[idx++] = obj[i++]; /* fallthrough */\n+\t\t}\n+\t} else {\n+\t\tfor (i = 0; idx < size; i++, idx++)\n+\t\t\tdeque[idx] = obj[i];\n+\t\t/* Start at the beginning */\n+\t\tfor (idx = 0; i < n; i++, idx++)\n+\t\t\tdeque[idx] = obj[i];\n+\t}\n+}\n+\n+static __rte_always_inline void\n+__rte_deque_enqueue_elems_head_64(struct rte_deque *d,\n+\t\t\t\tconst void *obj_table,\n+\t\t\t\tunsigned int n)\n+{\n+\tunsigned int i;\n+\tconst uint32_t size = d->size;\n+\tuint32_t idx = (d->head & d->mask);\n+\tuint64_t *deque = (uint64_t *)&d[1];\n+\tconst unaligned_uint64_t *obj = (const unaligned_uint64_t *)obj_table;\n+\tif (likely(idx + n <= size)) {\n+\t\tfor (i = 0; i < (n & ~0x3); i += 4, idx += 4) {\n+\t\t\tdeque[idx] = obj[i];\n+\t\t\tdeque[idx + 1] = obj[i + 1];\n+\t\t\tdeque[idx + 2] = obj[i + 2];\n+\t\t\tdeque[idx + 3] = obj[i + 3];\n+\t\t}\n+\t\tswitch (n & 0x3) {\n+\t\tcase 3:\n+\t\t\tdeque[idx++] = obj[i++]; /* fallthrough */\n+\t\tcase 2:\n+\t\t\tdeque[idx++] = obj[i++]; /* fallthrough */\n+\t\tcase 1:\n+\t\t\tdeque[idx++] = obj[i++]; /* fallthrough */\n+\t\t}\n+\t} else {\n+\t\tfor (i = 0; idx < size; i++, idx++)\n+\t\t\tdeque[idx] = obj[i];\n+\t\t/* Start at the beginning */\n+\t\tfor (idx = 0; i < n; i++, idx++)\n+\t\t\tdeque[idx] = obj[i];\n+\t}\n+}\n+\n+static __rte_always_inline void\n+__rte_deque_enqueue_elems_head_128(struct rte_deque *d,\n+\t\t\t\tconst void *obj_table,\n+\t\t\t\tunsigned int n)\n+{\n+\tunsigned int i;\n+\tconst uint32_t size = d->size;\n+\tuint32_t idx = (d->head & d->mask);\n+\trte_int128_t *deque = (rte_int128_t *)&d[1];\n+\tconst rte_int128_t *obj = (const rte_int128_t *)obj_table;\n+\tif (likely(idx + n <= size)) {\n+\t\tfor (i = 0; i < (n & ~0x1); i += 2, idx += 2)\n+\t\t\tmemcpy((void *)(deque + idx),\n+\t\t\t\t(const void *)(obj + i), 32);\n+\t\tswitch (n & 0x1) {\n+\t\tcase 1:\n+\t\t\tmemcpy((void *)(deque + idx),\n+\t\t\t\t(const void *)(obj + i), 16);\n+\t\t}\n+\t} else {\n+\t\tfor (i = 0; idx < size; i++, idx++)\n+\t\t\tmemcpy((void *)(deque + idx),\n+\t\t\t\t(const void *)(obj + i), 16);\n+\t\t/* Start at the beginning */\n+\t\tfor (idx = 0; i < n; i++, idx++)\n+\t\t\tmemcpy((void *)(deque + idx),\n+\t\t\t\t(const void *)(obj + i), 16);\n+\t}\n+}\n+\n+static __rte_always_inline unsigned int\n+__rte_deque_enqueue_at_head(struct rte_deque *d,\n+\t\t\tconst void *obj_table,\n+\t\t\tunsigned int esize,\n+\t\t\tunsigned int n)\n+{\n+\t/* 8B and 16B copies implemented individually because on some platforms\n+\t * there are 64 bit and 128 bit registers available for direct copying.\n+\t */\n+\tif (esize == 8)\n+\t\t__rte_deque_enqueue_elems_head_64(d, obj_table, n);\n+\telse if (esize == 16)\n+\t\t__rte_deque_enqueue_elems_head_128(d, obj_table, n);\n+\telse {\n+\t\tuint32_t idx, scale, nd_idx, nd_num, nd_size;\n+\n+\t\t/* Normalize to uint32_t */\n+\t\tscale = esize / sizeof(uint32_t);\n+\t\tnd_num = n * scale;\n+\t\tidx = d->head & d->mask;\n+\t\tnd_idx = idx * scale;\n+\t\tnd_size = d->size * scale;\n+\t\t__rte_deque_enqueue_elems_head_32(d, nd_size, nd_idx,\n+\t\t\t\t\t\tobj_table, nd_num);\n+\t}\n+\td->head = (d->head + n) & d->mask;\n+\treturn n;\n+}\n+\n+static __rte_always_inline void\n+__rte_deque_enqueue_elems_tail_32(struct rte_deque *d,\n+\t\t\t\tconst unsigned int mask,\n+\t\t\t\tuint32_t idx,\n+\t\t\t\tconst void *obj_table,\n+\t\t\t\tunsigned int n,\n+\t\t\t\tconst unsigned int scale,\n+\t\t\t\tconst unsigned int elem_size)\n+{\n+\tunsigned int i;\n+\tuint32_t *deque = (uint32_t *)&d[1];\n+\tconst uint32_t *obj = (const uint32_t *)obj_table;\n+\n+\tif (likely(idx >= n)) {\n+\t\tfor (i = 0; i < n; idx -= scale, i += scale)\n+\t\t\tmemcpy(&deque[idx], &obj[i], elem_size);\n+\t} else {\n+\t\tfor (i = 0; (int32_t)idx >= 0; idx -= scale, i += scale)\n+\t\t\tmemcpy(&deque[idx], &obj[i], elem_size);\n+\n+\t\t/* Start at the ending */\n+\t\tidx = mask;\n+\t\tfor (; i < n; idx -= scale, i += scale)\n+\t\t\tmemcpy(&deque[idx], &obj[i], elem_size);\n+\t}\n+}\n+\n+static __rte_always_inline void\n+__rte_deque_enqueue_elems_tail_64(struct rte_deque *d,\n+\t\t\t\tconst void *obj_table,\n+\t\t\t\tunsigned int n)\n+{\n+\tunsigned int i;\n+\tuint32_t idx = (d->tail & d->mask);\n+\tuint64_t *deque = (uint64_t *)&d[1];\n+\tconst unaligned_uint64_t *obj = (const unaligned_uint64_t *)obj_table;\n+\tif (likely((int32_t)(idx - n) >= 0)) {\n+\t\tfor (i = 0; i < (n & ~0x3); i += 4, idx -= 4) {\n+\t\t\tdeque[idx] = obj[i];\n+\t\t\tdeque[idx - 1] = obj[i + 1];\n+\t\t\tdeque[idx - 2] = obj[i + 2];\n+\t\t\tdeque[idx - 3] = obj[i + 3];\n+\t\t}\n+\t\tswitch (n & 0x3) {\n+\t\tcase 3:\n+\t\t\tdeque[idx--] = obj[i++]; /* fallthrough */\n+\t\tcase 2:\n+\t\t\tdeque[idx--] = obj[i++]; /* fallthrough */\n+\t\tcase 1:\n+\t\t\tdeque[idx--] = obj[i++]; /* fallthrough */\n+\t\t}\n+\t} else {\n+\t\tfor (i = 0; (int32_t)idx >= 0; i++, idx--)\n+\t\t\tdeque[idx] = obj[i];\n+\t\t/* Start at the ending */\n+\t\tfor (idx = d->mask; i < n; i++, idx--)\n+\t\t\tdeque[idx] = obj[i];\n+\t}\n+}\n+\n+static __rte_always_inline void\n+__rte_deque_enqueue_elems_tail_128(struct rte_deque *d,\n+\t\t\t\tconst void *obj_table,\n+\t\t\t\tunsigned int n)\n+{\n+\tunsigned int i;\n+\tuint32_t idx = (d->tail & d->mask);\n+\trte_int128_t *deque = (rte_int128_t *)&d[1];\n+\tconst rte_int128_t *obj = (const rte_int128_t *)obj_table;\n+\tif (likely((int32_t)(idx - n) >= 0)) {\n+\t\tfor (i = 0; i < (n & ~0x1); i += 2, idx -= 2) {\n+\t\t\tdeque[idx] = obj[i];\n+\t\t\tdeque[idx - 1] = obj[i + 1];\n+\t\t}\n+\t\tswitch (n & 0x1) {\n+\t\tcase 1:\n+\t\t\tmemcpy((void *)(deque + idx),\n+\t\t\t\t(const void *)(obj + i), 16);\n+\t\t}\n+\t} else {\n+\t\tfor (i = 0; (int32_t)idx >= 0; i++, idx--)\n+\t\t\tmemcpy((void *)(deque + idx),\n+\t\t\t\t(const void *)(obj + i), 16);\n+\t\t/* Start at the ending */\n+\t\tfor (idx = d->mask; i < n; i++, idx--)\n+\t\t\tmemcpy((void *)(deque + idx),\n+\t\t\t\t(const void *)(obj + i), 16);\n+\t}\n+}\n+\n+static __rte_always_inline unsigned int\n+__rte_deque_enqueue_at_tail(struct rte_deque *d,\n+\t\t\tconst void *obj_table,\n+\t\t\tunsigned int esize,\n+\t\t\tunsigned int n)\n+{\n+\t/* The tail point must point at an empty cell when enqueuing */\n+\td->tail--;\n+\n+\t/* 8B and 16B copies implemented individually because on some platforms\n+\t * there are 64 bit and 128 bit registers available for direct copying.\n+\t */\n+\tif (esize == 8)\n+\t\t__rte_deque_enqueue_elems_tail_64(d, obj_table, n);\n+\telse if (esize == 16)\n+\t\t__rte_deque_enqueue_elems_tail_128(d, obj_table, n);\n+\telse {\n+\t\tuint32_t idx, scale, nd_idx, nd_num, nd_mask;\n+\n+\t\t/* Normalize to uint32_t */\n+\t\tscale = esize / sizeof(uint32_t);\n+\t\tnd_num = n * scale;\n+\t\tidx = d->tail & d->mask;\n+\t\tnd_idx = idx * scale;\n+\t\tnd_mask = d->mask * scale;\n+\t\t__rte_deque_enqueue_elems_tail_32(d, nd_mask, nd_idx, obj_table,\n+\t\t\t\t\t\tnd_num, scale, esize);\n+\t}\n+\n+\t/* The +1 is because the tail needs to point at a\n+\t * non-empty memory location after the enqueuing operation.\n+\t */\n+\td->tail = (d->tail - n + 1) & d->mask;\n+\treturn n;\n+}\n+\n+static __rte_always_inline void\n+__rte_deque_dequeue_elems_32(struct rte_deque *d,\n+\t\t\tconst unsigned int size,\n+\t\t\tuint32_t idx,\n+\t\t\tvoid *obj_table,\n+\t\t\tunsigned int n)\n+{\n+\tunsigned int i;\n+\tconst uint32_t *deque = (const uint32_t *)&d[1];\n+\tuint32_t *obj = (uint32_t *)obj_table;\n+\tif (likely(idx + n <= size)) {\n+\t\tfor (i = 0; i < (n & ~0x7); i += 8, idx += 8) {\n+\t\t\tobj[i] = deque[idx];\n+\t\t\tobj[i + 1] = deque[idx + 1];\n+\t\t\tobj[i + 2] = deque[idx + 2];\n+\t\t\tobj[i + 3] = deque[idx + 3];\n+\t\t\tobj[i + 4] = deque[idx + 4];\n+\t\t\tobj[i + 5] = deque[idx + 5];\n+\t\t\tobj[i + 6] = deque[idx + 6];\n+\t\t\tobj[i + 7] = deque[idx + 7];\n+\t\t}\n+\t\tswitch (n & 0x7) {\n+\t\tcase 7:\n+\t\t\tobj[i++] = deque[idx++]; /* fallthrough */\n+\t\tcase 6:\n+\t\t\tobj[i++] = deque[idx++]; /* fallthrough */\n+\t\tcase 5:\n+\t\t\tobj[i++] = deque[idx++]; /* fallthrough */\n+\t\tcase 4:\n+\t\t\tobj[i++] = deque[idx++]; /* fallthrough */\n+\t\tcase 3:\n+\t\t\tobj[i++] = deque[idx++]; /* fallthrough */\n+\t\tcase 2:\n+\t\t\tobj[i++] = deque[idx++]; /* fallthrough */\n+\t\tcase 1:\n+\t\t\tobj[i++] = deque[idx++]; /* fallthrough */\n+\t\t}\n+\t} else {\n+\t\tfor (i = 0; idx < size; i++, idx++)\n+\t\t\tobj[i] = deque[idx];\n+\t\t/* Start at the beginning */\n+\t\tfor (idx = 0; i < n; i++, idx++)\n+\t\t\tobj[i] = deque[idx];\n+\t}\n+}\n+\n+static __rte_always_inline void\n+__rte_deque_dequeue_elems_64(struct rte_deque *d, void *obj_table,\n+\t\t\tunsigned int n)\n+{\n+\tunsigned int i;\n+\tconst uint32_t size = d->size;\n+\tuint32_t idx = (d->tail & d->mask);\n+\tconst uint64_t *deque = (const uint64_t *)&d[1];\n+\tunaligned_uint64_t *obj = (unaligned_uint64_t *)obj_table;\n+\tif (likely(idx + n <= size)) {\n+\t\tfor (i = 0; i < (n & ~0x3); i += 4, idx += 4) {\n+\t\t\tobj[i] = deque[idx];\n+\t\t\tobj[i + 1] = deque[idx + 1];\n+\t\t\tobj[i + 2] = deque[idx + 2];\n+\t\t\tobj[i + 3] = deque[idx + 3];\n+\t\t}\n+\t\tswitch (n & 0x3) {\n+\t\tcase 3:\n+\t\t\tobj[i++] = deque[idx++]; /* fallthrough */\n+\t\tcase 2:\n+\t\t\tobj[i++] = deque[idx++]; /* fallthrough */\n+\t\tcase 1:\n+\t\t\tobj[i++] = deque[idx++]; /* fallthrough */\n+\t\t}\n+\t} else {\n+\t\tfor (i = 0; idx < size; i++, idx++)\n+\t\t\tobj[i] = deque[idx];\n+\t\t/* Start at the beginning */\n+\t\tfor (idx = 0; i < n; i++, idx++)\n+\t\t\tobj[i] = deque[idx];\n+\t}\n+}\n+\n+static __rte_always_inline void\n+__rte_deque_dequeue_elems_128(struct rte_deque *d,\n+\t\t\tvoid *obj_table,\n+\t\t\tunsigned int n)\n+{\n+\tunsigned int i;\n+\tconst uint32_t size = d->size;\n+\tuint32_t idx = (d->tail & d->mask);\n+\tconst rte_int128_t *deque = (const rte_int128_t *)&d[1];\n+\trte_int128_t *obj = (rte_int128_t *)obj_table;\n+\tif (likely(idx + n <= size)) {\n+\t\tfor (i = 0; i < (n & ~0x1); i += 2, idx += 2)\n+\t\t\tmemcpy((void *)(obj + i),\n+\t\t\t\t(const void *)(deque + idx), 32);\n+\t\tswitch (n & 0x1) {\n+\t\tcase 1:\n+\t\t\tmemcpy((void *)(obj + i),\n+\t\t\t\t(const void *)(deque + idx), 16);\n+\t\t}\n+\t} else {\n+\t\tfor (i = 0; idx < size; i++, idx++)\n+\t\t\tmemcpy((void *)(obj + i),\n+\t\t\t\t(const void *)(deque + idx), 16);\n+\t\t/* Start at the beginning */\n+\t\tfor (idx = 0; i < n; i++, idx++)\n+\t\t\tmemcpy((void *)(obj + i),\n+\t\t\t\t(const void *)(deque + idx), 16);\n+\t}\n+}\n+\n+static __rte_always_inline unsigned int\n+__rte_deque_dequeue_at_tail(struct rte_deque *d,\n+\t\t\tvoid *obj_table,\n+\t\t\tunsigned int esize,\n+\t\t\tunsigned int n)\n+{\n+\t/* 8B and 16B copies implemented individually because on some platforms\n+\t * there are 64 bit and 128 bit registers available for direct copying.\n+\t */\n+\tif (esize == 8)\n+\t\t__rte_deque_dequeue_elems_64(d, obj_table, n);\n+\telse if (esize == 16)\n+\t\t__rte_deque_dequeue_elems_128(d, obj_table, n);\n+\telse {\n+\t\tuint32_t idx, scale, nd_idx, nd_num, nd_size;\n+\n+\t\t/* Normalize to uint32_t */\n+\t\tscale = esize / sizeof(uint32_t);\n+\t\tnd_num = n * scale;\n+\t\tidx = d->tail & d->mask;\n+\t\tnd_idx = idx * scale;\n+\t\tnd_size = d->size * scale;\n+\t\t__rte_deque_dequeue_elems_32(d, nd_size, nd_idx,\n+\t\t\t\t\tobj_table, nd_num);\n+\t}\n+\td->tail = (d->tail + n) & d->mask;\n+\treturn n;\n+}\n+\n+static __rte_always_inline void\n+__rte_deque_dequeue_elems_head_32(struct rte_deque *d,\n+\t\t\t\tconst unsigned int mask,\n+\t\t\t\tuint32_t idx,\n+\t\t\t\tvoid *obj_table,\n+\t\t\t\tunsigned int n,\n+\t\t\t\tconst unsigned int scale,\n+\t\t\t\tconst unsigned int elem_size)\n+{\n+\tunsigned int i;\n+\tconst uint32_t *deque = (uint32_t *)&d[1];\n+\tuint32_t *obj = (uint32_t *)obj_table;\n+\n+\tif (likely(idx >= n)) {\n+\t\tfor (i = 0; i < n; idx -= scale, i += scale)\n+\t\t\tmemcpy(&obj[i], &deque[idx], elem_size);\n+\t} else {\n+\t\tfor (i = 0; (int32_t)idx >= 0; idx -= scale, i += scale)\n+\t\t\tmemcpy(&obj[i], &deque[idx], elem_size);\n+\t\t/* Start at the ending */\n+\t\tidx = mask;\n+\t\tfor (; i < n; idx -= scale, i += scale)\n+\t\t\tmemcpy(&obj[i], &deque[idx], elem_size);\n+\t}\n+}\n+\n+static __rte_always_inline void\n+__rte_deque_dequeue_elems_head_64(struct rte_deque *d,\n+\t\t\t\tvoid *obj_table,\n+\t\t\t\tunsigned int n)\n+{\n+\tunsigned int i;\n+\tuint32_t idx = (d->head & d->mask);\n+\tconst uint64_t *deque = (uint64_t *)&d[1];\n+\tunaligned_uint64_t *obj = (unaligned_uint64_t *)obj_table;\n+\tif (likely((int32_t)(idx - n) >= 0)) {\n+\t\tfor (i = 0; i < (n & ~0x3); i += 4, idx -= 4) {\n+\t\t\tobj[i] = deque[idx];\n+\t\t\tobj[i + 1] = deque[idx - 1];\n+\t\t\tobj[i + 2] = deque[idx - 2];\n+\t\t\tobj[i + 3] = deque[idx - 3];\n+\t\t}\n+\t\tswitch (n & 0x3) {\n+\t\tcase 3:\n+\t\t\tobj[i++] = deque[idx--];  /* fallthrough */\n+\t\tcase 2:\n+\t\t\tobj[i++] = deque[idx--]; /* fallthrough */\n+\t\tcase 1:\n+\t\t\tobj[i++] = deque[idx--]; /* fallthrough */\n+\t\t}\n+\t} else {\n+\t\tfor (i = 0; (int32_t)idx >= 0; i++, idx--)\n+\t\t\tobj[i] = deque[idx];\n+\t\t/* Start at the ending */\n+\t\tfor (idx = d->mask; i < n; i++, idx--)\n+\t\t\tobj[i] = deque[idx];\n+\t}\n+}\n+\n+static __rte_always_inline void\n+__rte_deque_dequeue_elems_head_128(struct rte_deque *d,\n+\t\t\t\tvoid *obj_table,\n+\t\t\t\tunsigned int n)\n+{\n+\tunsigned int i;\n+\tuint32_t idx = (d->head & d->mask);\n+\tconst rte_int128_t *deque = (rte_int128_t *)&d[1];\n+\trte_int128_t *obj = (rte_int128_t *)obj_table;\n+\tif (likely((int32_t)(idx - n) >= 0)) {\n+\t\tfor (i = 0; i < (n & ~0x1); i += 2, idx -= 2) {\n+\t\t\tobj[i] = deque[idx];\n+\t\t\tobj[i + 1] = deque[idx - 1];\n+\t\t}\n+\t\tswitch (n & 0x1) {\n+\t\tcase 1:\n+\t\t\tmemcpy((void *)(obj + i),\n+\t\t\t\t(const void *)(deque + idx), 16);\n+\t\t}\n+\t} else {\n+\t\tfor (i = 0; (int32_t)idx >= 0; i++, idx--)\n+\t\t\tmemcpy((void *)(obj + i),\n+\t\t\t\t(const void *)(deque + idx), 16);\n+\t\t/* Start at the ending */\n+\t\tfor (idx = d->mask; i < n; i++, idx--)\n+\t\t\tmemcpy((void *)(obj + i),\n+\t\t\t\t(const void *)(deque + idx), 16);\n+\t}\n+}\n+\n+static __rte_always_inline unsigned int\n+__rte_deque_dequeue_at_head(struct rte_deque *d,\n+\t\t\tvoid *obj_table,\n+\t\t\tunsigned int esize,\n+\t\t\tunsigned int n)\n+{\n+\t/* The head must point at an empty cell when dequeueing */\n+\td->head--;\n+\n+\t/* 8B and 16B copies implemented individually because on some platforms\n+\t * there are 64 bit and 128 bit registers available for direct copying.\n+\t */\n+\tif (esize == 8)\n+\t\t__rte_deque_dequeue_elems_head_64(d, obj_table, n);\n+\telse if (esize == 16)\n+\t\t__rte_deque_dequeue_elems_head_128(d, obj_table, n);\n+\telse {\n+\t\tuint32_t idx, scale, nd_idx, nd_num, nd_mask;\n+\n+\t\t/* Normalize to uint32_t */\n+\t\tscale = esize / sizeof(uint32_t);\n+\t\tnd_num = n * scale;\n+\t\tidx = d->head & d->mask;\n+\t\tnd_idx = idx * scale;\n+\t\tnd_mask = d->mask * scale;\n+\t\t__rte_deque_dequeue_elems_head_32(d, nd_mask, nd_idx, obj_table,\n+\t\t\t\t\t\tnd_num, scale, esize);\n+\t}\n+\n+\t/* The +1 is because the head needs to point at a\n+\t * empty memory location after the dequeueing operation.\n+\t */\n+\td->head = (d->head - n + 1) & d->mask;\n+\treturn n;\n+}\n+#endif /* _RTE_DEQUEU_PVT_H_ */\ndiff --git a/lib/deque/rte_deque_zc.h b/lib/deque/rte_deque_zc.h\nnew file mode 100644\nindex 0000000000..75a7e6fddb\n--- /dev/null\n+++ b/lib/deque/rte_deque_zc.h\n@@ -0,0 +1,430 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2024 Arm Limited\n+ */\n+#ifndef _RTE_DEQUE_ZC_H_\n+#define _RTE_DEQUE_ZC_H_\n+\n+/**\n+ * @file\n+ * This file should not be included directly, include rte_deque.h instead.\n+ *\n+ * Deque Zero Copy APIs\n+ * These APIs make it possible to split public enqueue/dequeue API\n+ * into 3 parts:\n+ * - enqueue/dequeue start\n+ * - copy data to/from the deque\n+ * - enqueue/dequeue finish\n+ * These APIs provide the ability to avoid copying of the data to temporary area.\n+ *\n+ */\n+\n+#ifdef __cplusplus\n+extern \"C\" {\n+#endif\n+\n+/**\n+ * Deque zero-copy information structure.\n+ *\n+ * This structure contains the pointers and length of the space\n+ * reserved on the Deque storage.\n+ */\n+struct __rte_cache_aligned rte_deque_zc_data {\n+\t/* Pointer to the first space in the deque */\n+\tvoid *ptr1;\n+\t/* Pointer to the second space in the deque if there is wrap-around.\n+\t * It contains valid value only if wrap-around happens.\n+\t */\n+\tvoid *ptr2;\n+\t/* Number of elements in the first pointer. If this is equal to\n+\t * the number of elements requested, then ptr2 is NULL.\n+\t * Otherwise, subtracting n1 from number of elements requested\n+\t * will give the number of elements available at ptr2.\n+\t */\n+\tunsigned int n1;\n+};\n+\n+static __rte_always_inline void\n+__rte_deque_get_elem_addr(struct rte_deque *d, uint32_t pos,\n+\tuint32_t esize, uint32_t num, void **dst1, uint32_t *n1, void **dst2,\n+\tbool low_to_high)\n+{\n+\tuint32_t idx, scale, nr_idx;\n+\tuint32_t *deque = (uint32_t *)&d[1];\n+\n+\t/* Normalize to uint32_t */\n+\tscale = esize / sizeof(uint32_t);\n+\tidx = pos & d->mask;\n+\tnr_idx = idx * scale;\n+\n+\t*dst1 = deque + nr_idx;\n+\t*n1 = num;\n+\n+\tif (low_to_high) {\n+\t\tif (idx + num > d->size) {\n+\t\t\t*n1 = d->size - idx;\n+\t\t\t*dst2 = deque;\n+\t\t} else\n+\t\t\t*dst2 = NULL;\n+\t} else {\n+\t\tif ((int32_t)(idx - num) < 0) {\n+\t\t\t*n1 = idx + 1;\n+\t\t\t*dst2 = (void *)&deque[(-1 & d->mask) * scale];\n+\t\t} else\n+\t\t\t*dst2 = NULL;\n+\t}\n+}\n+\n+/**\n+ * Start to enqueue several objects on the deque.\n+ * Note that no actual objects are put in the deque by this function,\n+ * it just reserves space for the user on the deque.\n+ * User has to copy objects into the deque using the returned pointers.\n+ * User should call rte_deque_enqueue_zc_elem_finish to complete the\n+ * enqueue operation.\n+ *\n+ * @param d\n+ *   A pointer to the deque structure.\n+ * @param esize\n+ *   The size of deque element, in bytes. It must be a multiple of 4.\n+ * @param n\n+ *   The number of objects to add in the deque.\n+ * @param zcd\n+ *   Structure containing the pointers and length of the space\n+ *   reserved on the deque storage.\n+ * @param free_space\n+ *   Returns the amount of space in the deque after the reservation operation\n+ *   has finished.\n+ * @return\n+ *   The number of objects that can be enqueued, either 0 or n\n+ */\n+__rte_experimental\n+static __rte_always_inline unsigned int\n+rte_deque_enqueue_zc_bulk_elem_start(struct rte_deque *d, unsigned int esize,\n+\tunsigned int n, struct rte_deque_zc_data *zcd, unsigned int *free_space)\n+{\n+\n+\t*free_space = __RTE_DEQUE_FREE_SPACE(d);\n+\tif (unlikely(*free_space < n))\n+\t\treturn 0;\n+\t__rte_deque_get_elem_addr(d, d->head, esize, n, &zcd->ptr1,\n+\t\t\t\t\t\t\t&zcd->n1, &zcd->ptr2, true);\n+\n+\t*free_space -= n;\n+\treturn n;\n+}\n+\n+/**\n+ * Complete enqueuing several pointers to objects on the deque.\n+ * Note that number of objects to enqueue should not exceed previous\n+ * enqueue_start return value.\n+ *\n+ * @param d\n+ *   A pointer to the deque structure.\n+ * @param n\n+ *   The number of pointers to objects to add to the deque.\n+ */\n+__rte_experimental\n+static __rte_always_inline void\n+rte_deque_enqueue_zc_elem_finish(struct rte_deque *d, unsigned int n)\n+{\n+\td->head = (d->head + n) & d->mask;\n+}\n+\n+/**\n+ * Start to enqueue several objects on the deque.\n+ * Note that no actual objects are put in the queue by this function,\n+ * it just reserves space for the user on the deque.\n+ * User has to copy objects into the queue using the returned pointers.\n+ * User should call rte_deque_enqueue_zc_elem_finish to complete the\n+ * enqueue operation.\n+ *\n+ * @param d\n+ *   A pointer to the deque structure.\n+ * @param esize\n+ *   The size of deque element, in bytes. It must be a multiple of 4.\n+ * @param n\n+ *   The number of objects to add in the deque.\n+ * @param zcd\n+ *   Structure containing the pointers and length of the space\n+ *   reserved on the deque storage.\n+ * @param free_space\n+ *   Returns the amount of space in the deque after the reservation operation\n+ *   has finished.\n+ * @return\n+ *   The number of objects that can be enqueued, either 0 or n\n+ */\n+__rte_experimental\n+static __rte_always_inline unsigned int\n+rte_deque_enqueue_zc_burst_elem_start(struct rte_deque *d, unsigned int esize,\n+\tunsigned int n, struct rte_deque_zc_data *zcd, unsigned int *free_space)\n+{\n+\t*free_space = __RTE_DEQUE_FREE_SPACE(d);\n+\tn = n > *free_space ? *free_space : n;\n+\treturn rte_deque_enqueue_zc_bulk_elem_start(d, esize, n, zcd, free_space);\n+}\n+\n+/**\n+ * Start to enqueue several objects on the deque.\n+ * Note that no actual objects are put in the deque by this function,\n+ * it just reserves space for the user on the deque.\n+ * User has to copy objects into the deque using the returned pointers.\n+ * User should call rte_deque_enqueue_zc_elem_finish to complete the\n+ * enqueue operation.\n+ *\n+ * @param d\n+ *   A pointer to the deque structure.\n+ * @param esize\n+ *   The size of deque element, in bytes. It must be a multiple of 4.\n+ * @param n\n+ *   The number of objects to add in the deque.\n+ * @param zcd\n+ *   Structure containing the pointers and length of the space\n+ *   reserved on the deque storage.\n+ * @param free_space\n+ *   Returns the amount of space in the deque after the reservation operation\n+ *   has finished.\n+ * @return\n+ *   The number of objects that can be enqueued, either 0 or n\n+ */\n+__rte_experimental\n+static __rte_always_inline unsigned int\n+rte_deque_enqueue_zc_bulk_elem_tail_start(struct rte_deque *d, unsigned int esize,\n+\tunsigned int n, struct rte_deque_zc_data *zcd, unsigned int *free_space)\n+{\n+\t*free_space = __RTE_DEQUE_FREE_SPACE(d);\n+\tif (unlikely(*free_space < n))\n+\t\treturn 0;\n+\t__rte_deque_get_elem_addr(d, d->tail - 1, esize, n, &zcd->ptr1,\n+\t\t\t\t\t\t\t  &zcd->n1, &zcd->ptr2, false);\n+\n+\t*free_space -= n;\n+\treturn n;\n+}\n+\n+/**\n+ * Complete enqueuing several pointers to objects on the deque.\n+ * Note that number of objects to enqueue should not exceed previous\n+ * enqueue_start return value.\n+ *\n+ * @param d\n+ *   A pointer to the deque structure.\n+ * @param n\n+ *   The number of pointers to objects to add to the deque.\n+ */\n+__rte_experimental\n+static __rte_always_inline void\n+rte_deque_enqueue_zc_elem_tail_finish(struct rte_deque *d, unsigned int n)\n+{\n+\td->tail = (d->tail - n) & d->mask;\n+}\n+\n+/**\n+ * Start to enqueue several objects on the deque.\n+ * Note that no actual objects are put in the queue by this function,\n+ * it just reserves space for the user on the deque.\n+ * User has to copy objects into the queue using the returned pointers.\n+ * User should call rte_deque_enqueue_zc_elem_finish to complete the\n+ * enqueue operation.\n+ *\n+ * @param d\n+ *   A pointer to the deque structure.\n+ * @param esize\n+ *   The size of deque element, in bytes. It must be a multiple of 4.\n+ * @param n\n+ *   The number of objects to add in the deque.@param r\n+ * @param zcd\n+ *   Structure containing the pointers and length of the space\n+ *   reserved on the deque storage.\n+ * @param free_space\n+ *   Returns the amount of space in the deque after the reservation operation\n+ *   has finished.\n+ * @return\n+ *   The number of objects that can be enqueued, either 0 or n\n+ */\n+__rte_experimental\n+static __rte_always_inline unsigned int\n+rte_deque_enqueue_zc_burst_elem_tail_start(struct rte_deque *d, unsigned int esize,\n+\tunsigned int n, struct rte_deque_zc_data *zcd, unsigned int *free_space)\n+{\n+\t*free_space = __RTE_DEQUE_FREE_SPACE(d);\n+\tn = n > *free_space ? *free_space : n;\n+\treturn rte_deque_enqueue_zc_bulk_elem_tail_start(d, esize, n, zcd, free_space);\n+}\n+\n+/**\n+ * Start to dequeue several objects from the deque.\n+ * Note that no actual objects are copied from the queue by this function.\n+ * User has to copy objects from the queue using the returned pointers.\n+ * User should call rte_deque_dequeue_zc_elem_finish to complete the\n+ * dequeue operation.\n+ *\n+ * @param d\n+ *   A pointer to the deque structure.\n+ * @param esize\n+ *   The size of deque element, in bytes. It must be a multiple of 4.\n+ * @param n\n+ *   The number of objects to remove from the deque.\n+ * @param zcd\n+ *   Structure containing the pointers and length of the space\n+ *   reserved on the deque storage.\n+ * @param available\n+ *   Returns the number of remaining deque entries after the dequeue has\n+ *   finished.\n+ * @return\n+ *   The number of objects that can be dequeued, either 0 or n.\n+ */\n+__rte_experimental\n+static __rte_always_inline unsigned int\n+rte_deque_dequeue_zc_bulk_elem_start(struct rte_deque *d, unsigned int esize,\n+\tunsigned int n, struct rte_deque_zc_data *zcd, unsigned int *available)\n+{\n+\t*available = __RTE_DEQUE_COUNT(d);\n+\tif (unlikely(*available < n))\n+\t\treturn 0;\n+\t__rte_deque_get_elem_addr(d, d->tail, esize, n, &zcd->ptr1,\n+\t\t\t\t\t\t\t&zcd->n1, &zcd->ptr2, true);\n+\n+\t*available -= n;\n+\treturn n;\n+}\n+\n+/**\n+ * Complete dequeuing several objects from the deque.\n+ * Note that number of objects to dequeued should not exceed previous\n+ * dequeue_start return value.\n+ *\n+ * @param d\n+ *   A pointer to the deque structure.\n+ * @param n\n+ *   The number of objects to remove from the deque.\n+ */\n+__rte_experimental\n+static __rte_always_inline void\n+rte_deque_dequeue_zc_elem_finish(struct rte_deque *d, unsigned int n)\n+{\n+\td->tail = (d->tail + n) & d->mask;\n+}\n+\n+/**\n+ * Start to dequeue several objects from the deque.\n+ * Note that no actual objects are copied from the queue by this function.\n+ * User has to copy objects from the queue using the returned pointers.\n+ * User should call rte_deque_dequeue_zc_elem_finish to complete the\n+ * dequeue operation.\n+ *\n+ * @param d\n+ *   A pointer to the deque structure.\n+ * @param esize\n+ *   The size of deque element, in bytes. It must be a multiple of 4.\n+ * @param n\n+ *   The number of objects to remove from the deque.\n+ * @param zcd\n+ *   Structure containing the pointers and length of the space\n+ *   reserved on the deque storage.\n+ * @param available\n+ *   Returns the number of remaining deque entries after the dequeue has\n+ *   finished.\n+ * @return\n+ *   The number of objects that can be dequeued, either 0 or n.\n+ */\n+__rte_experimental\n+static __rte_always_inline unsigned int\n+rte_deque_dequeue_zc_burst_elem_start(struct rte_deque *d, unsigned int esize,\n+\tunsigned int n, struct rte_deque_zc_data *zcd, unsigned int *available)\n+{\n+\t*available = __RTE_DEQUE_COUNT(d);\n+\tn = n > *available ? *available : n;\n+\treturn rte_deque_dequeue_zc_bulk_elem_start(d, esize, n, zcd, available);\n+}\n+\n+/**\n+ * Start to dequeue several objects from the deque.\n+ * Note that no actual objects are copied from the queue by this function.\n+ * User has to copy objects from the queue using the returned pointers.\n+ * User should call rte_deque_dequeue_zc_elem_finish to complete the\n+ * dequeue operation.\n+ *\n+ * @param d\n+ *   A pointer to the deque structure.\n+ * @param esize\n+ *   The size of deque element, in bytes. It must be a multiple of 4.\n+ * @param n\n+ *   The number of objects to remove from the deque.\n+ * @param zcd\n+ *   Structure containing the pointers and length of the space\n+ *   reserved on the deque storage.\n+ * @param available\n+ *   Returns the number of remaining deque entries after the dequeue has\n+ *   finished.\n+ * @return\n+ *   The number of objects that can be dequeued, either 0 or n.\n+ */\n+__rte_experimental\n+static __rte_always_inline unsigned int\n+rte_deque_dequeue_zc_bulk_elem_head_start(struct rte_deque *d, unsigned int esize,\n+\tunsigned int n, struct rte_deque_zc_data *zcd, unsigned int *available)\n+{\n+\t*available = __RTE_DEQUE_COUNT(d);\n+\tif (unlikely(*available < n))\n+\t\treturn 0;\n+\t__rte_deque_get_elem_addr(d, d->head - 1, esize, n, &zcd->ptr1,\n+\t\t\t\t\t\t\t&zcd->n1, &zcd->ptr2, false);\n+\n+\t*available -= n;\n+\treturn n;\n+}\n+\n+/**\n+ * Complete dequeuing several objects from the deque.\n+ * Note that number of objects to dequeued should not exceed previous\n+ * dequeue_start return value.\n+ *\n+ * @param d\n+ *   A pointer to the deque structure.\n+ * @param n\n+ *   The number of objects to remove from the deque.\n+ */\n+__rte_experimental\n+static __rte_always_inline void\n+rte_deque_dequeue_zc_elem_head_finish(struct rte_deque *d, unsigned int n)\n+{\n+\td->head = (d->head - n) & d->mask;\n+}\n+\n+/**\n+ * Start to dequeue several objects from the deque.\n+ * Note that no actual objects are copied from the queue by this function.\n+ * User has to copy objects from the queue using the returned pointers.\n+ * User should call rte_deque_dequeue_zc_elem_finish to complete the\n+ * dequeue operation.\n+ *\n+ * @param d\n+ *   A pointer to the deque structure.\n+ * @param esize\n+ *   The size of deque element, in bytes. It must be a multiple of 4.\n+ * @param n\n+ *   The number of objects to remove from the deque.\n+ * @param zcd\n+ *   Structure containing the pointers and length of the space\n+ *   reserved on the deque storage.\n+ * @param available\n+ *   Returns the number of remaining deque entries after the dequeue has\n+ *   finished.\n+ * @return\n+ *   The number of objects that can be dequeued, either 0 or n.\n+ */\n+__rte_experimental\n+static __rte_always_inline unsigned int\n+rte_deque_dequeue_zc_burst_elem_head_start(struct rte_deque *d, unsigned int esize,\n+\tunsigned int n, struct rte_deque_zc_data *zcd, unsigned int *available)\n+{\n+\t*available = __RTE_DEQUE_COUNT(d);\n+\tn = n > *available ? *available : n;\n+\treturn rte_deque_dequeue_zc_bulk_elem_head_start(d, esize, n, zcd, available);\n+}\n+\n+#ifdef __cplusplus\n+}\n+#endif\n+\n+#endif /* _RTE_DEQUE_ZC_H_ */\ndiff --git a/lib/deque/version.map b/lib/deque/version.map\nnew file mode 100644\nindex 0000000000..103fd3b512\n--- /dev/null\n+++ b/lib/deque/version.map\n@@ -0,0 +1,14 @@\n+EXPERIMENTAL {\n+\tglobal:\n+\n+\t# added in 24.07\n+\trte_deque_log_type;\n+\trte_deque_create;\n+\trte_deque_dump;\n+\trte_deque_free;\n+\trte_deque_get_memsize_elem;\n+\trte_deque_init;\n+\trte_deque_reset;\n+\n+\tlocal: *;\n+};\ndiff --git a/lib/meson.build b/lib/meson.build\nindex 179a272932..8c8c1e98e2 100644\n--- a/lib/meson.build\n+++ b/lib/meson.build\n@@ -14,6 +14,7 @@ libraries = [\n         'argparse',\n         'telemetry', # basic info querying\n         'eal', # everything depends on eal\n+        'deque',\n         'ring',\n         'rcu', # rcu depends on ring\n         'mempool',\n",
    "prefixes": [
        "v1",
        "1/2"
    ]
}