get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 64568,
    "url": "http://patches.dpdk.org/api/patches/64568/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20200113172518.37815-3-honnappa.nagarahalli@arm.com/",
    "project": {
        "id": 1,
        "url": "http://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": "<20200113172518.37815-3-honnappa.nagarahalli@arm.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20200113172518.37815-3-honnappa.nagarahalli@arm.com",
    "date": "2020-01-13T17:25:14",
    "name": "[v8,2/6] lib/ring: apis to support configurable element size",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "ad2f0fae127e7c592a1ffe39efdfb0b9bbca4673",
    "submitter": {
        "id": 1045,
        "url": "http://patches.dpdk.org/api/people/1045/?format=api",
        "name": "Honnappa Nagarahalli",
        "email": "honnappa.nagarahalli@arm.com"
    },
    "delegate": {
        "id": 24651,
        "url": "http://patches.dpdk.org/api/users/24651/?format=api",
        "username": "dmarchand",
        "first_name": "David",
        "last_name": "Marchand",
        "email": "david.marchand@redhat.com"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20200113172518.37815-3-honnappa.nagarahalli@arm.com/mbox/",
    "series": [
        {
            "id": 8086,
            "url": "http://patches.dpdk.org/api/series/8086/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=8086",
            "date": "2020-01-13T17:25:12",
            "name": "lib/ring: APIs to support custom element size",
            "version": 8,
            "mbox": "http://patches.dpdk.org/series/8086/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/64568/comments/",
    "check": "fail",
    "checks": "http://patches.dpdk.org/api/patches/64568/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 dpdk.org (dpdk.org [92.243.14.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id B2F22A04F1;\n\tMon, 13 Jan 2020 18:25:53 +0100 (CET)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 567461D176;\n\tMon, 13 Jan 2020 18:25:44 +0100 (CET)",
            "from foss.arm.com (foss.arm.com [217.140.110.172])\n by dpdk.org (Postfix) with ESMTP id 21F901D16F\n for <dev@dpdk.org>; Mon, 13 Jan 2020 18:25:40 +0100 (CET)",
            "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 93D611424;\n Mon, 13 Jan 2020 09:25:39 -0800 (PST)",
            "from qc2400f-1.austin.arm.com (qc2400f-1.austin.arm.com\n [10.118.14.48])\n by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 7D3B03F85E;\n Mon, 13 Jan 2020 09:25:39 -0800 (PST)"
        ],
        "From": "Honnappa Nagarahalli <honnappa.nagarahalli@arm.com>",
        "To": "olivier.matz@6wind.com, sthemmin@microsoft.com, jerinj@marvell.com,\n bruce.richardson@intel.com, david.marchand@redhat.com,\n pbhagavatula@marvell.com, konstantin.ananyev@intel.com,\n honnappa.nagarahalli@arm.com",
        "Cc": "dev@dpdk.org, dharmik.thakkar@arm.com, ruifeng.wang@arm.com,\n gavin.hu@arm.com, nd@arm.com",
        "Date": "Mon, 13 Jan 2020 11:25:14 -0600",
        "Message-Id": "<20200113172518.37815-3-honnappa.nagarahalli@arm.com>",
        "X-Mailer": "git-send-email 2.17.1",
        "In-Reply-To": "<20200113172518.37815-1-honnappa.nagarahalli@arm.com>",
        "References": "<20190906190510.11146-1-honnappa.nagarahalli@arm.com>\n <20200113172518.37815-1-honnappa.nagarahalli@arm.com>",
        "Subject": "[dpdk-dev] [PATCH v8 2/6] lib/ring: apis to support configurable\n\telement size",
        "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>,\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",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "Current APIs assume ring elements to be pointers. However, in many\nuse cases, the size can be different. Add new APIs to support\nconfigurable ring element sizes.\n\nSigned-off-by: Honnappa Nagarahalli <honnappa.nagarahalli@arm.com>\nReviewed-by: Dharmik Thakkar <dharmik.thakkar@arm.com>\nReviewed-by: Gavin Hu <gavin.hu@arm.com>\nReviewed-by: Ruifeng Wang <ruifeng.wang@arm.com>\n---\n lib/librte_ring/Makefile             |    3 +-\n lib/librte_ring/meson.build          |    4 +\n lib/librte_ring/rte_ring.c           |   41 +-\n lib/librte_ring/rte_ring.h           |    1 +\n lib/librte_ring/rte_ring_elem.h      | 1003 ++++++++++++++++++++++++++\n lib/librte_ring/rte_ring_version.map |    2 +\n 6 files changed, 1045 insertions(+), 9 deletions(-)\n create mode 100644 lib/librte_ring/rte_ring_elem.h",
    "diff": "diff --git a/lib/librte_ring/Makefile b/lib/librte_ring/Makefile\nindex 22454b084..917c560ad 100644\n--- a/lib/librte_ring/Makefile\n+++ b/lib/librte_ring/Makefile\n@@ -6,7 +6,7 @@ include $(RTE_SDK)/mk/rte.vars.mk\n # library name\n LIB = librte_ring.a\n \n-CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3\n+CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3 -DALLOW_EXPERIMENTAL_API\n LDLIBS += -lrte_eal\n \n EXPORT_MAP := rte_ring_version.map\n@@ -16,6 +16,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_RING) := rte_ring.c\n \n # install includes\n SYMLINK-$(CONFIG_RTE_LIBRTE_RING)-include := rte_ring.h \\\n+\t\t\t\t\trte_ring_elem.h \\\n \t\t\t\t\trte_ring_generic.h \\\n \t\t\t\t\trte_ring_c11_mem.h\n \ndiff --git a/lib/librte_ring/meson.build b/lib/librte_ring/meson.build\nindex ca8a435e9..f2f3ccc88 100644\n--- a/lib/librte_ring/meson.build\n+++ b/lib/librte_ring/meson.build\n@@ -3,5 +3,9 @@\n \n sources = files('rte_ring.c')\n headers = files('rte_ring.h',\n+\t\t'rte_ring_elem.h',\n \t\t'rte_ring_c11_mem.h',\n \t\t'rte_ring_generic.h')\n+\n+# rte_ring_create_elem and rte_ring_get_memsize_elem are experimental\n+allow_experimental_apis = true\ndiff --git a/lib/librte_ring/rte_ring.c b/lib/librte_ring/rte_ring.c\nindex d9b308036..3e15dc398 100644\n--- a/lib/librte_ring/rte_ring.c\n+++ b/lib/librte_ring/rte_ring.c\n@@ -33,6 +33,7 @@\n #include <rte_tailq.h>\n \n #include \"rte_ring.h\"\n+#include \"rte_ring_elem.h\"\n \n TAILQ_HEAD(rte_ring_list, rte_tailq_entry);\n \n@@ -46,23 +47,38 @@ EAL_REGISTER_TAILQ(rte_ring_tailq)\n \n /* return the size of memory occupied by a ring */\n ssize_t\n-rte_ring_get_memsize(unsigned count)\n+rte_ring_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(ERR, RING, \"element size is not a multiple of 4\\n\");\n+\n+\t\treturn -EINVAL;\n+\t}\n+\n \t/* count must be a power of 2 */\n \tif ((!POWEROF2(count)) || (count > RTE_RING_SZ_MASK )) {\n \t\tRTE_LOG(ERR, RING,\n-\t\t\t\"Requested size is invalid, must be power of 2, and \"\n-\t\t\t\"do not exceed the size limit %u\\n\", RTE_RING_SZ_MASK);\n+\t\t\t\"Requested number of elements is invalid, must be power of 2, and not exceed %u\\n\",\n+\t\t\tRTE_RING_SZ_MASK);\n+\n \t\treturn -EINVAL;\n \t}\n \n-\tsz = sizeof(struct rte_ring) + count * sizeof(void *);\n+\tsz = sizeof(struct rte_ring) + count * esize;\n \tsz = RTE_ALIGN(sz, RTE_CACHE_LINE_SIZE);\n \treturn sz;\n }\n \n+/* return the size of memory occupied by a ring */\n+ssize_t\n+rte_ring_get_memsize(unsigned count)\n+{\n+\treturn rte_ring_get_memsize_elem(sizeof(void *), count);\n+}\n+\n void\n rte_ring_reset(struct rte_ring *r)\n {\n@@ -114,10 +130,10 @@ rte_ring_init(struct rte_ring *r, const char *name, unsigned count,\n \treturn 0;\n }\n \n-/* create the ring */\n+/* create the ring for a given element size */\n struct rte_ring *\n-rte_ring_create(const char *name, unsigned count, int socket_id,\n-\t\tunsigned flags)\n+rte_ring_create_elem(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_ring *r;\n@@ -135,7 +151,7 @@ rte_ring_create(const char *name, unsigned count, int socket_id,\n \tif (flags & RING_F_EXACT_SZ)\n \t\tcount = rte_align32pow2(count + 1);\n \n-\tring_size = rte_ring_get_memsize(count);\n+\tring_size = rte_ring_get_memsize_elem(esize, count);\n \tif (ring_size < 0) {\n \t\trte_errno = ring_size;\n \t\treturn NULL;\n@@ -182,6 +198,15 @@ rte_ring_create(const char *name, unsigned count, int socket_id,\n \treturn r;\n }\n \n+/* create the ring */\n+struct rte_ring *\n+rte_ring_create(const char *name, unsigned count, int socket_id,\n+\t\tunsigned flags)\n+{\n+\treturn rte_ring_create_elem(name, sizeof(void *), count, socket_id,\n+\t\tflags);\n+}\n+\n /* free the ring */\n void\n rte_ring_free(struct rte_ring *r)\ndiff --git a/lib/librte_ring/rte_ring.h b/lib/librte_ring/rte_ring.h\nindex 2a9f768a1..18fc5d845 100644\n--- a/lib/librte_ring/rte_ring.h\n+++ b/lib/librte_ring/rte_ring.h\n@@ -216,6 +216,7 @@ int rte_ring_init(struct rte_ring *r, const char *name, unsigned count,\n  */\n struct rte_ring *rte_ring_create(const char *name, unsigned count,\n \t\t\t\t int socket_id, unsigned flags);\n+\n /**\n  * De-allocate all memory used by the ring.\n  *\ndiff --git a/lib/librte_ring/rte_ring_elem.h b/lib/librte_ring/rte_ring_elem.h\nnew file mode 100644\nindex 000000000..15d79bf2a\n--- /dev/null\n+++ b/lib/librte_ring/rte_ring_elem.h\n@@ -0,0 +1,1003 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ *\n+ * Copyright (c) 2019 Arm Limited\n+ * Copyright (c) 2010-2017 Intel Corporation\n+ * Copyright (c) 2007-2009 Kip Macy kmacy@freebsd.org\n+ * All rights reserved.\n+ * Derived from FreeBSD's bufring.h\n+ * Used as BSD-3 Licensed with permission from Kip Macy.\n+ */\n+\n+#ifndef _RTE_RING_ELEM_H_\n+#define _RTE_RING_ELEM_H_\n+\n+/**\n+ * @file\n+ * RTE Ring with user defined element size\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 <sys/queue.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+\n+#include \"rte_ring.h\"\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ * Calculate the memory size needed for a ring with given element size\n+ *\n+ * This function returns the number of bytes needed for a ring, given\n+ * the number of elements in it and the size of the element. This value\n+ * is the sum of the size of the structure rte_ring and the size of the\n+ * memory needed for storing the elements. The value is aligned to a cache\n+ * line size.\n+ *\n+ * @param esize\n+ *   The size of ring element, in bytes. It must be a multiple of 4.\n+ * @param count\n+ *   The number of elements in the ring (must be a power of 2).\n+ * @return\n+ *   - The memory size needed for the ring on success.\n+ *   - -EINVAL - esize is not a multiple of 4 or count provided is not a\n+ *\t\t power of 2.\n+ */\n+__rte_experimental\n+ssize_t rte_ring_get_memsize_elem(unsigned int esize, unsigned int count);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ * Create a new ring named *name* that stores elements with given size.\n+ *\n+ * This function uses ``memzone_reserve()`` to allocate memory. Then it\n+ * calls rte_ring_init() to initialize an empty ring.\n+ *\n+ * The new ring size is set to *count*, which must be a power of\n+ * two. Water marking is disabled by default. The real usable ring size\n+ * is *count-1* instead of *count* to differentiate a free ring from an\n+ * empty ring.\n+ *\n+ * The ring is added in RTE_TAILQ_RING list.\n+ *\n+ * @param name\n+ *   The name of the ring.\n+ * @param esize\n+ *   The size of ring element, in bytes. It must be a multiple of 4.\n+ * @param count\n+ *   The number of elements in the ring (must be a power of 2).\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+ *   An OR of the following:\n+ *    - RING_F_SP_ENQ: If this flag is set, the default behavior when\n+ *      using ``rte_ring_enqueue()`` or ``rte_ring_enqueue_bulk()``\n+ *      is \"single-producer\". Otherwise, it is \"multi-producers\".\n+ *    - RING_F_SC_DEQ: If this flag is set, the default behavior when\n+ *      using ``rte_ring_dequeue()`` or ``rte_ring_dequeue_bulk()``\n+ *      is \"single-consumer\". Otherwise, it is \"multi-consumers\".\n+ * @return\n+ *   On success, the pointer to the new allocated ring. 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+ *    - E_RTE_SECONDARY - function was called from a secondary process instance\n+ *    - EINVAL - esize is not a multiple of 4 or count provided is not a\n+ *\t\t 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_ring *rte_ring_create_elem(const char *name, unsigned int esize,\n+\t\t\tunsigned int count, int socket_id, unsigned int flags);\n+\n+static __rte_always_inline void\n+enqueue_elems_32(struct rte_ring *r, const uint32_t size, uint32_t idx,\n+\t\tconst void *obj_table, uint32_t n)\n+{\n+\tunsigned int i;\n+\tuint32_t *ring = (uint32_t *)&r[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\tring[idx] = obj[i];\n+\t\t\tring[idx + 1] = obj[i + 1];\n+\t\t\tring[idx + 2] = obj[i + 2];\n+\t\t\tring[idx + 3] = obj[i + 3];\n+\t\t\tring[idx + 4] = obj[i + 4];\n+\t\t\tring[idx + 5] = obj[i + 5];\n+\t\t\tring[idx + 6] = obj[i + 6];\n+\t\t\tring[idx + 7] = obj[i + 7];\n+\t\t}\n+\t\tswitch (n & 0x7) {\n+\t\tcase 7:\n+\t\t\tring[idx++] = obj[i++]; /* fallthrough */\n+\t\tcase 6:\n+\t\t\tring[idx++] = obj[i++]; /* fallthrough */\n+\t\tcase 5:\n+\t\t\tring[idx++] = obj[i++]; /* fallthrough */\n+\t\tcase 4:\n+\t\t\tring[idx++] = obj[i++]; /* fallthrough */\n+\t\tcase 3:\n+\t\t\tring[idx++] = obj[i++]; /* fallthrough */\n+\t\tcase 2:\n+\t\t\tring[idx++] = obj[i++]; /* fallthrough */\n+\t\tcase 1:\n+\t\t\tring[idx++] = obj[i++]; /* fallthrough */\n+\t\t}\n+\t} else {\n+\t\tfor (i = 0; idx < size; i++, idx++)\n+\t\t\tring[idx] = obj[i];\n+\t\t/* Start at the beginning */\n+\t\tfor (idx = 0; i < n; i++, idx++)\n+\t\t\tring[idx] = obj[i];\n+\t}\n+}\n+\n+static __rte_always_inline void\n+enqueue_elems_64(struct rte_ring *r, uint32_t prod_head,\n+\t\tconst void *obj_table, uint32_t n)\n+{\n+\tunsigned int i;\n+\tconst uint32_t size = r->size;\n+\tuint32_t idx = prod_head & r->mask;\n+\tuint64_t *ring = (uint64_t *)&r[1];\n+\tconst uint64_t *obj = (const 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\tring[idx] = obj[i];\n+\t\t\tring[idx + 1] = obj[i + 1];\n+\t\t\tring[idx + 2] = obj[i + 2];\n+\t\t\tring[idx + 3] = obj[i + 3];\n+\t\t}\n+\t\tswitch (n & 0x3) {\n+\t\tcase 3:\n+\t\t\tring[idx++] = obj[i++]; /* fallthrough */\n+\t\tcase 2:\n+\t\t\tring[idx++] = obj[i++]; /* fallthrough */\n+\t\tcase 1:\n+\t\t\tring[idx++] = obj[i++];\n+\t\t}\n+\t} else {\n+\t\tfor (i = 0; idx < size; i++, idx++)\n+\t\t\tring[idx] = obj[i];\n+\t\t/* Start at the beginning */\n+\t\tfor (idx = 0; i < n; i++, idx++)\n+\t\t\tring[idx] = obj[i];\n+\t}\n+}\n+\n+static __rte_always_inline void\n+enqueue_elems_128(struct rte_ring *r, uint32_t prod_head,\n+\t\tconst void *obj_table, uint32_t n)\n+{\n+\tunsigned int i;\n+\tconst uint32_t size = r->size;\n+\tuint32_t idx = prod_head & r->mask;\n+\trte_int128_t *ring = (rte_int128_t *)&r[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 *)(ring + 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 *)(ring + 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 *)(ring + 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 *)(ring + idx),\n+\t\t\t\t(const void *)(obj + i), 16);\n+\t}\n+}\n+\n+/* the actual enqueue of elements on the ring.\n+ * Placed here since identical code needed in both\n+ * single and multi producer enqueue functions.\n+ */\n+static __rte_always_inline void\n+enqueue_elems(struct rte_ring *r, uint32_t prod_head, const void *obj_table,\n+\t\tuint32_t esize, uint32_t num)\n+{\n+\t/* 8B and 16B copies implemented individually to retain\n+\t * the current performance.\n+\t */\n+\tif (esize == 8)\n+\t\tenqueue_elems_64(r, prod_head, obj_table, num);\n+\telse if (esize == 16)\n+\t\tenqueue_elems_128(r, prod_head, obj_table, num);\n+\telse {\n+\t\tuint32_t idx, scale, nr_idx, nr_num, nr_size;\n+\n+\t\t/* Normalize to uint32_t */\n+\t\tscale = esize / sizeof(uint32_t);\n+\t\tnr_num = num * scale;\n+\t\tidx = prod_head & r->mask;\n+\t\tnr_idx = idx * scale;\n+\t\tnr_size = r->size * scale;\n+\t\tenqueue_elems_32(r, nr_size, nr_idx, obj_table, nr_num);\n+\t}\n+}\n+\n+static __rte_always_inline void\n+dequeue_elems_32(struct rte_ring *r, const uint32_t size, uint32_t idx,\n+\t\tvoid *obj_table, uint32_t n)\n+{\n+\tunsigned int i;\n+\tuint32_t *ring = (uint32_t *)&r[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] = ring[idx];\n+\t\t\tobj[i + 1] = ring[idx + 1];\n+\t\t\tobj[i + 2] = ring[idx + 2];\n+\t\t\tobj[i + 3] = ring[idx + 3];\n+\t\t\tobj[i + 4] = ring[idx + 4];\n+\t\t\tobj[i + 5] = ring[idx + 5];\n+\t\t\tobj[i + 6] = ring[idx + 6];\n+\t\t\tobj[i + 7] = ring[idx + 7];\n+\t\t}\n+\t\tswitch (n & 0x7) {\n+\t\tcase 7:\n+\t\t\tobj[i++] = ring[idx++]; /* fallthrough */\n+\t\tcase 6:\n+\t\t\tobj[i++] = ring[idx++]; /* fallthrough */\n+\t\tcase 5:\n+\t\t\tobj[i++] = ring[idx++]; /* fallthrough */\n+\t\tcase 4:\n+\t\t\tobj[i++] = ring[idx++]; /* fallthrough */\n+\t\tcase 3:\n+\t\t\tobj[i++] = ring[idx++]; /* fallthrough */\n+\t\tcase 2:\n+\t\t\tobj[i++] = ring[idx++]; /* fallthrough */\n+\t\tcase 1:\n+\t\t\tobj[i++] = ring[idx++]; /* fallthrough */\n+\t\t}\n+\t} else {\n+\t\tfor (i = 0; idx < size; i++, idx++)\n+\t\t\tobj[i] = ring[idx];\n+\t\t/* Start at the beginning */\n+\t\tfor (idx = 0; i < n; i++, idx++)\n+\t\t\tobj[i] = ring[idx];\n+\t}\n+}\n+\n+static __rte_always_inline void\n+dequeue_elems_64(struct rte_ring *r, uint32_t prod_head,\n+\t\tvoid *obj_table, uint32_t n)\n+{\n+\tunsigned int i;\n+\tconst uint32_t size = r->size;\n+\tuint32_t idx = prod_head & r->mask;\n+\tuint64_t *ring = (uint64_t *)&r[1];\n+\tuint64_t *obj = (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] = ring[idx];\n+\t\t\tobj[i + 1] = ring[idx + 1];\n+\t\t\tobj[i + 2] = ring[idx + 2];\n+\t\t\tobj[i + 3] = ring[idx + 3];\n+\t\t}\n+\t\tswitch (n & 0x3) {\n+\t\tcase 3:\n+\t\t\tobj[i++] = ring[idx++]; /* fallthrough */\n+\t\tcase 2:\n+\t\t\tobj[i++] = ring[idx++]; /* fallthrough */\n+\t\tcase 1:\n+\t\t\tobj[i++] = ring[idx++]; /* fallthrough */\n+\t\t}\n+\t} else {\n+\t\tfor (i = 0; idx < size; i++, idx++)\n+\t\t\tobj[i] = ring[idx];\n+\t\t/* Start at the beginning */\n+\t\tfor (idx = 0; i < n; i++, idx++)\n+\t\t\tobj[i] = ring[idx];\n+\t}\n+}\n+\n+static __rte_always_inline void\n+dequeue_elems_128(struct rte_ring *r, uint32_t prod_head,\n+\t\tvoid *obj_table, uint32_t n)\n+{\n+\tunsigned int i;\n+\tconst uint32_t size = r->size;\n+\tuint32_t idx = prod_head & r->mask;\n+\trte_int128_t *ring = (rte_int128_t *)&r[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), (void *)(ring + idx), 32);\n+\t\tswitch (n & 0x1) {\n+\t\tcase 1:\n+\t\t\tmemcpy((void *)(obj + i), (void *)(ring + idx), 16);\n+\t\t}\n+\t} else {\n+\t\tfor (i = 0; idx < size; i++, idx++)\n+\t\t\tmemcpy((void *)(obj + i), (void *)(ring + 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), (void *)(ring + idx), 16);\n+\t}\n+}\n+\n+/* the actual dequeue of elements from the ring.\n+ * Placed here since identical code needed in both\n+ * single and multi producer enqueue functions.\n+ */\n+static __rte_always_inline void\n+dequeue_elems(struct rte_ring *r, uint32_t cons_head, void *obj_table,\n+\t\tuint32_t esize, uint32_t num)\n+{\n+\t/* 8B and 16B copies implemented individually to retain\n+\t * the current performance.\n+\t */\n+\tif (esize == 8)\n+\t\tdequeue_elems_64(r, cons_head, obj_table, num);\n+\telse if (esize == 16)\n+\t\tdequeue_elems_128(r, cons_head, obj_table, num);\n+\telse {\n+\t\tuint32_t idx, scale, nr_idx, nr_num, nr_size;\n+\n+\t\t/* Normalize to uint32_t */\n+\t\tscale = esize / sizeof(uint32_t);\n+\t\tnr_num = num * scale;\n+\t\tidx = cons_head & r->mask;\n+\t\tnr_idx = idx * scale;\n+\t\tnr_size = r->size * scale;\n+\t\tdequeue_elems_32(r, nr_size, nr_idx, obj_table, nr_num);\n+\t}\n+}\n+\n+/* Between load and load. there might be cpu reorder in weak model\n+ * (powerpc/arm).\n+ * There are 2 choices for the users\n+ * 1.use rmb() memory barrier\n+ * 2.use one-direction load_acquire/store_release barrier,defined by\n+ * CONFIG_RTE_USE_C11_MEM_MODEL=y\n+ * It depends on performance test results.\n+ * By default, move common functions to rte_ring_generic.h\n+ */\n+#ifdef RTE_USE_C11_MEM_MODEL\n+#include \"rte_ring_c11_mem.h\"\n+#else\n+#include \"rte_ring_generic.h\"\n+#endif\n+\n+/**\n+ * @internal Enqueue several objects on the ring\n+ *\n+ * @param r\n+ *   A pointer to the ring structure.\n+ * @param obj_table\n+ *   A pointer to a table of void * pointers (objects).\n+ * @param esize\n+ *   The size of ring element, in bytes. It must be a multiple of 4.\n+ *   This must be the same value used while creating the ring. Otherwise\n+ *   the results are undefined.\n+ * @param n\n+ *   The number of objects to add in the ring from the obj_table.\n+ * @param behavior\n+ *   RTE_RING_QUEUE_FIXED:    Enqueue a fixed number of items from a ring\n+ *   RTE_RING_QUEUE_VARIABLE: Enqueue as many items as possible from ring\n+ * @param is_sp\n+ *   Indicates whether to use single producer or multi-producer head update\n+ * @param free_space\n+ *   returns the amount of space after the enqueue operation has finished\n+ * @return\n+ *   Actual number of objects enqueued.\n+ *   If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.\n+ */\n+static __rte_always_inline unsigned int\n+__rte_ring_do_enqueue_elem(struct rte_ring *r, const void *obj_table,\n+\t\tunsigned int esize, unsigned int n,\n+\t\tenum rte_ring_queue_behavior behavior, unsigned int is_sp,\n+\t\tunsigned int *free_space)\n+{\n+\tuint32_t prod_head, prod_next;\n+\tuint32_t free_entries;\n+\n+\tn = __rte_ring_move_prod_head(r, is_sp, n, behavior,\n+\t\t\t&prod_head, &prod_next, &free_entries);\n+\tif (n == 0)\n+\t\tgoto end;\n+\n+\tenqueue_elems(r, prod_head, obj_table, esize, n);\n+\n+\tupdate_tail(&r->prod, prod_head, prod_next, is_sp, 1);\n+end:\n+\tif (free_space != NULL)\n+\t\t*free_space = free_entries - n;\n+\treturn n;\n+}\n+\n+/**\n+ * @internal Dequeue several objects from the ring\n+ *\n+ * @param r\n+ *   A pointer to the ring structure.\n+ * @param obj_table\n+ *   A pointer to a table of void * pointers (objects).\n+ * @param esize\n+ *   The size of ring element, in bytes. It must be a multiple of 4.\n+ *   This must be the same value used while creating the ring. Otherwise\n+ *   the results are undefined.\n+ * @param n\n+ *   The number of objects to pull from the ring.\n+ * @param behavior\n+ *   RTE_RING_QUEUE_FIXED:    Dequeue a fixed number of items from a ring\n+ *   RTE_RING_QUEUE_VARIABLE: Dequeue as many items as possible from ring\n+ * @param is_sc\n+ *   Indicates whether to use single consumer or multi-consumer head update\n+ * @param available\n+ *   returns the number of remaining ring entries after the dequeue has finished\n+ * @return\n+ *   - Actual number of objects dequeued.\n+ *     If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.\n+ */\n+static __rte_always_inline unsigned int\n+__rte_ring_do_dequeue_elem(struct rte_ring *r, void *obj_table,\n+\t\tunsigned int esize, unsigned int n,\n+\t\tenum rte_ring_queue_behavior behavior, unsigned int is_sc,\n+\t\tunsigned int *available)\n+{\n+\tuint32_t cons_head, cons_next;\n+\tuint32_t entries;\n+\n+\tn = __rte_ring_move_cons_head(r, (int)is_sc, n, behavior,\n+\t\t\t&cons_head, &cons_next, &entries);\n+\tif (n == 0)\n+\t\tgoto end;\n+\n+\tdequeue_elems(r, cons_head, obj_table, esize, n);\n+\n+\tupdate_tail(&r->cons, cons_head, cons_next, is_sc, 0);\n+\n+end:\n+\tif (available != NULL)\n+\t\t*available = entries - n;\n+\treturn n;\n+}\n+\n+/**\n+ * Enqueue several objects on the ring (multi-producers safe).\n+ *\n+ * This function uses a \"compare and set\" instruction to move the\n+ * producer index atomically.\n+ *\n+ * @param r\n+ *   A pointer to the ring structure.\n+ * @param obj_table\n+ *   A pointer to a table of void * pointers (objects).\n+ * @param esize\n+ *   The size of ring element, in bytes. It must be a multiple of 4.\n+ *   This must be the same value used while creating the ring. Otherwise\n+ *   the results are undefined.\n+ * @param n\n+ *   The number of objects to add in the ring from the obj_table.\n+ * @param free_space\n+ *   if non-NULL, returns the amount of space in the ring after the\n+ *   enqueue operation has finished.\n+ * @return\n+ *   The number of objects enqueued, either 0 or n\n+ */\n+static __rte_always_inline unsigned int\n+rte_ring_mp_enqueue_bulk_elem(struct rte_ring *r, const void *obj_table,\n+\t\tunsigned int esize, unsigned int n, unsigned int *free_space)\n+{\n+\treturn __rte_ring_do_enqueue_elem(r, obj_table, esize, n,\n+\t\t\tRTE_RING_QUEUE_FIXED, __IS_MP, free_space);\n+}\n+\n+/**\n+ * Enqueue several objects on a ring\n+ *\n+ * @warning This API is NOT multi-producers safe\n+ *\n+ * @param r\n+ *   A pointer to the ring structure.\n+ * @param obj_table\n+ *   A pointer to a table of void * pointers (objects).\n+ * @param esize\n+ *   The size of ring element, in bytes. It must be a multiple of 4.\n+ *   This must be the same value used while creating the ring. Otherwise\n+ *   the results are undefined.\n+ * @param n\n+ *   The number of objects to add in the ring from the obj_table.\n+ * @param free_space\n+ *   if non-NULL, returns the amount of space in the ring after the\n+ *   enqueue operation has finished.\n+ * @return\n+ *   The number of objects enqueued, either 0 or n\n+ */\n+static __rte_always_inline unsigned int\n+rte_ring_sp_enqueue_bulk_elem(struct rte_ring *r, const void *obj_table,\n+\t\tunsigned int esize, unsigned int n, unsigned int *free_space)\n+{\n+\treturn __rte_ring_do_enqueue_elem(r, obj_table, esize, n,\n+\t\t\tRTE_RING_QUEUE_FIXED, __IS_SP, free_space);\n+}\n+\n+/**\n+ * Enqueue several objects on a ring.\n+ *\n+ * This function calls the multi-producer or the single-producer\n+ * version depending on the default behavior that was specified at\n+ * ring creation time (see flags).\n+ *\n+ * @param r\n+ *   A pointer to the ring structure.\n+ * @param obj_table\n+ *   A pointer to a table of void * pointers (objects).\n+ * @param esize\n+ *   The size of ring element, in bytes. It must be a multiple of 4.\n+ *   This must be the same value used while creating the ring. Otherwise\n+ *   the results are undefined.\n+ * @param n\n+ *   The number of objects to add in the ring from the obj_table.\n+ * @param free_space\n+ *   if non-NULL, returns the amount of space in the ring after the\n+ *   enqueue operation has finished.\n+ * @return\n+ *   The number of objects enqueued, either 0 or n\n+ */\n+static __rte_always_inline unsigned int\n+rte_ring_enqueue_bulk_elem(struct rte_ring *r, const void *obj_table,\n+\t\tunsigned int esize, unsigned int n, unsigned int *free_space)\n+{\n+\treturn __rte_ring_do_enqueue_elem(r, obj_table, esize, n,\n+\t\t\tRTE_RING_QUEUE_FIXED, r->prod.single, free_space);\n+}\n+\n+/**\n+ * Enqueue one object on a ring (multi-producers safe).\n+ *\n+ * This function uses a \"compare and set\" instruction to move the\n+ * producer index atomically.\n+ *\n+ * @param r\n+ *   A pointer to the ring structure.\n+ * @param obj\n+ *   A pointer to the object to be added.\n+ * @param esize\n+ *   The size of ring element, in bytes. It must be a multiple of 4.\n+ *   This must be the same value used while creating the ring. Otherwise\n+ *   the results are undefined.\n+ * @return\n+ *   - 0: Success; objects enqueued.\n+ *   - -ENOBUFS: Not enough room in the ring to enqueue; no object is enqueued.\n+ */\n+static __rte_always_inline int\n+rte_ring_mp_enqueue_elem(struct rte_ring *r, void *obj, unsigned int esize)\n+{\n+\treturn rte_ring_mp_enqueue_bulk_elem(r, obj, esize, 1, NULL) ? 0 :\n+\t\t\t\t\t\t\t\t-ENOBUFS;\n+}\n+\n+/**\n+ * Enqueue one object on a ring\n+ *\n+ * @warning This API is NOT multi-producers safe\n+ *\n+ * @param r\n+ *   A pointer to the ring structure.\n+ * @param obj\n+ *   A pointer to the object to be added.\n+ * @param esize\n+ *   The size of ring element, in bytes. It must be a multiple of 4.\n+ *   This must be the same value used while creating the ring. Otherwise\n+ *   the results are undefined.\n+ * @return\n+ *   - 0: Success; objects enqueued.\n+ *   - -ENOBUFS: Not enough room in the ring to enqueue; no object is enqueued.\n+ */\n+static __rte_always_inline int\n+rte_ring_sp_enqueue_elem(struct rte_ring *r, void *obj, unsigned int esize)\n+{\n+\treturn rte_ring_sp_enqueue_bulk_elem(r, obj, esize, 1, NULL) ? 0 :\n+\t\t\t\t\t\t\t\t-ENOBUFS;\n+}\n+\n+/**\n+ * Enqueue one object on a ring.\n+ *\n+ * This function calls the multi-producer or the single-producer\n+ * version, depending on the default behaviour that was specified at\n+ * ring creation time (see flags).\n+ *\n+ * @param r\n+ *   A pointer to the ring structure.\n+ * @param obj\n+ *   A pointer to the object to be added.\n+ * @param esize\n+ *   The size of ring element, in bytes. It must be a multiple of 4.\n+ *   This must be the same value used while creating the ring. Otherwise\n+ *   the results are undefined.\n+ * @return\n+ *   - 0: Success; objects enqueued.\n+ *   - -ENOBUFS: Not enough room in the ring to enqueue; no object is enqueued.\n+ */\n+static __rte_always_inline int\n+rte_ring_enqueue_elem(struct rte_ring *r, void *obj, unsigned int esize)\n+{\n+\treturn rte_ring_enqueue_bulk_elem(r, obj, esize, 1, NULL) ? 0 :\n+\t\t\t\t\t\t\t\t-ENOBUFS;\n+}\n+\n+/**\n+ * Dequeue several objects from a ring (multi-consumers safe).\n+ *\n+ * This function uses a \"compare and set\" instruction to move the\n+ * consumer index atomically.\n+ *\n+ * @param r\n+ *   A pointer to the ring structure.\n+ * @param obj_table\n+ *   A pointer to a table of void * pointers (objects) that will be filled.\n+ * @param esize\n+ *   The size of ring element, in bytes. It must be a multiple of 4.\n+ *   This must be the same value used while creating the ring. Otherwise\n+ *   the results are undefined.\n+ * @param n\n+ *   The number of objects to dequeue from the ring to the obj_table.\n+ * @param available\n+ *   If non-NULL, returns the number of remaining ring entries after the\n+ *   dequeue has finished.\n+ * @return\n+ *   The number of objects dequeued, either 0 or n\n+ */\n+static __rte_always_inline unsigned int\n+rte_ring_mc_dequeue_bulk_elem(struct rte_ring *r, void *obj_table,\n+\t\tunsigned int esize, unsigned int n, unsigned int *available)\n+{\n+\treturn __rte_ring_do_dequeue_elem(r, obj_table, esize, n,\n+\t\t\t\tRTE_RING_QUEUE_FIXED, __IS_MC, available);\n+}\n+\n+/**\n+ * Dequeue several objects from a ring (NOT multi-consumers safe).\n+ *\n+ * @param r\n+ *   A pointer to the ring structure.\n+ * @param obj_table\n+ *   A pointer to a table of void * pointers (objects) that will be filled.\n+ * @param esize\n+ *   The size of ring element, in bytes. It must be a multiple of 4.\n+ *   This must be the same value used while creating the ring. Otherwise\n+ *   the results are undefined.\n+ * @param n\n+ *   The number of objects to dequeue from the ring to the obj_table,\n+ *   must be strictly positive.\n+ * @param available\n+ *   If non-NULL, returns the number of remaining ring entries after the\n+ *   dequeue has finished.\n+ * @return\n+ *   The number of objects dequeued, either 0 or n\n+ */\n+static __rte_always_inline unsigned int\n+rte_ring_sc_dequeue_bulk_elem(struct rte_ring *r, void *obj_table,\n+\t\tunsigned int esize, unsigned int n, unsigned int *available)\n+{\n+\treturn __rte_ring_do_dequeue_elem(r, obj_table, esize, n,\n+\t\t\tRTE_RING_QUEUE_FIXED, __IS_SC, available);\n+}\n+\n+/**\n+ * Dequeue several objects from a ring.\n+ *\n+ * This function calls the multi-consumers or the single-consumer\n+ * version, depending on the default behaviour that was specified at\n+ * ring creation time (see flags).\n+ *\n+ * @param r\n+ *   A pointer to the ring structure.\n+ * @param obj_table\n+ *   A pointer to a table of void * pointers (objects) that will be filled.\n+ * @param esize\n+ *   The size of ring element, in bytes. It must be a multiple of 4.\n+ *   This must be the same value used while creating the ring. Otherwise\n+ *   the results are undefined.\n+ * @param n\n+ *   The number of objects to dequeue from the ring to the obj_table.\n+ * @param available\n+ *   If non-NULL, returns the number of remaining ring entries after the\n+ *   dequeue has finished.\n+ * @return\n+ *   The number of objects dequeued, either 0 or n\n+ */\n+static __rte_always_inline unsigned int\n+rte_ring_dequeue_bulk_elem(struct rte_ring *r, void *obj_table,\n+\t\tunsigned int esize, unsigned int n, unsigned int *available)\n+{\n+\treturn __rte_ring_do_dequeue_elem(r, obj_table, esize, n,\n+\t\t\tRTE_RING_QUEUE_FIXED, r->cons.single, available);\n+}\n+\n+/**\n+ * Dequeue one object from a ring (multi-consumers safe).\n+ *\n+ * This function uses a \"compare and set\" instruction to move the\n+ * consumer index atomically.\n+ *\n+ * @param r\n+ *   A pointer to the ring structure.\n+ * @param obj_p\n+ *   A pointer to a void * pointer (object) that will be filled.\n+ * @param esize\n+ *   The size of ring element, in bytes. It must be a multiple of 4.\n+ *   This must be the same value used while creating the ring. Otherwise\n+ *   the results are undefined.\n+ * @return\n+ *   - 0: Success; objects dequeued.\n+ *   - -ENOENT: Not enough entries in the ring to dequeue; no object is\n+ *     dequeued.\n+ */\n+static __rte_always_inline int\n+rte_ring_mc_dequeue_elem(struct rte_ring *r, void *obj_p,\n+\t\t\t\tunsigned int esize)\n+{\n+\treturn rte_ring_mc_dequeue_bulk_elem(r, obj_p, esize, 1, NULL)  ? 0 :\n+\t\t\t\t\t\t\t\t-ENOENT;\n+}\n+\n+/**\n+ * Dequeue one object from a ring (NOT multi-consumers safe).\n+ *\n+ * @param r\n+ *   A pointer to the ring structure.\n+ * @param obj_p\n+ *   A pointer to a void * pointer (object) that will be filled.\n+ * @param esize\n+ *   The size of ring element, in bytes. It must be a multiple of 4.\n+ *   This must be the same value used while creating the ring. Otherwise\n+ *   the results are undefined.\n+ * @return\n+ *   - 0: Success; objects dequeued.\n+ *   - -ENOENT: Not enough entries in the ring to dequeue, no object is\n+ *     dequeued.\n+ */\n+static __rte_always_inline int\n+rte_ring_sc_dequeue_elem(struct rte_ring *r, void *obj_p,\n+\t\t\t\tunsigned int esize)\n+{\n+\treturn rte_ring_sc_dequeue_bulk_elem(r, obj_p, esize, 1, NULL) ? 0 :\n+\t\t\t\t\t\t\t\t-ENOENT;\n+}\n+\n+/**\n+ * Dequeue one object from a ring.\n+ *\n+ * This function calls the multi-consumers or the single-consumer\n+ * version depending on the default behaviour that was specified at\n+ * ring creation time (see flags).\n+ *\n+ * @param r\n+ *   A pointer to the ring structure.\n+ * @param obj_p\n+ *   A pointer to a void * pointer (object) that will be filled.\n+ * @param esize\n+ *   The size of ring element, in bytes. It must be a multiple of 4.\n+ *   This must be the same value used while creating the ring. Otherwise\n+ *   the results are undefined.\n+ * @return\n+ *   - 0: Success, objects dequeued.\n+ *   - -ENOENT: Not enough entries in the ring to dequeue, no object is\n+ *     dequeued.\n+ */\n+static __rte_always_inline int\n+rte_ring_dequeue_elem(struct rte_ring *r, void *obj_p, unsigned int esize)\n+{\n+\treturn rte_ring_dequeue_bulk_elem(r, obj_p, esize, 1, NULL) ? 0 :\n+\t\t\t\t\t\t\t\t-ENOENT;\n+}\n+\n+/**\n+ * Enqueue several objects on the ring (multi-producers safe).\n+ *\n+ * This function uses a \"compare and set\" instruction to move the\n+ * producer index atomically.\n+ *\n+ * @param r\n+ *   A pointer to the ring structure.\n+ * @param obj_table\n+ *   A pointer to a table of void * pointers (objects).\n+ * @param esize\n+ *   The size of ring element, in bytes. It must be a multiple of 4.\n+ *   This must be the same value used while creating the ring. Otherwise\n+ *   the results are undefined.\n+ * @param n\n+ *   The number of objects to add in the ring from the obj_table.\n+ * @param free_space\n+ *   if non-NULL, returns the amount of space in the ring after the\n+ *   enqueue operation has finished.\n+ * @return\n+ *   - n: Actual number of objects enqueued.\n+ */\n+static __rte_always_inline unsigned\n+rte_ring_mp_enqueue_burst_elem(struct rte_ring *r, const void *obj_table,\n+\t\tunsigned int esize, unsigned int n, unsigned int *free_space)\n+{\n+\treturn __rte_ring_do_enqueue_elem(r, obj_table, esize, n,\n+\t\t\tRTE_RING_QUEUE_VARIABLE, __IS_MP, free_space);\n+}\n+\n+/**\n+ * Enqueue several objects on a ring\n+ *\n+ * @warning This API is NOT multi-producers safe\n+ *\n+ * @param r\n+ *   A pointer to the ring structure.\n+ * @param obj_table\n+ *   A pointer to a table of void * pointers (objects).\n+ * @param esize\n+ *   The size of ring element, in bytes. It must be a multiple of 4.\n+ *   This must be the same value used while creating the ring. Otherwise\n+ *   the results are undefined.\n+ * @param n\n+ *   The number of objects to add in the ring from the obj_table.\n+ * @param free_space\n+ *   if non-NULL, returns the amount of space in the ring after the\n+ *   enqueue operation has finished.\n+ * @return\n+ *   - n: Actual number of objects enqueued.\n+ */\n+static __rte_always_inline unsigned\n+rte_ring_sp_enqueue_burst_elem(struct rte_ring *r, const void *obj_table,\n+\t\tunsigned int esize, unsigned int n, unsigned int *free_space)\n+{\n+\treturn __rte_ring_do_enqueue_elem(r, obj_table, esize, n,\n+\t\t\tRTE_RING_QUEUE_VARIABLE, __IS_SP, free_space);\n+}\n+\n+/**\n+ * Enqueue several objects on a ring.\n+ *\n+ * This function calls the multi-producer or the single-producer\n+ * version depending on the default behavior that was specified at\n+ * ring creation time (see flags).\n+ *\n+ * @param r\n+ *   A pointer to the ring structure.\n+ * @param obj_table\n+ *   A pointer to a table of void * pointers (objects).\n+ * @param esize\n+ *   The size of ring element, in bytes. It must be a multiple of 4.\n+ *   This must be the same value used while creating the ring. Otherwise\n+ *   the results are undefined.\n+ * @param n\n+ *   The number of objects to add in the ring from the obj_table.\n+ * @param free_space\n+ *   if non-NULL, returns the amount of space in the ring after the\n+ *   enqueue operation has finished.\n+ * @return\n+ *   - n: Actual number of objects enqueued.\n+ */\n+static __rte_always_inline unsigned\n+rte_ring_enqueue_burst_elem(struct rte_ring *r, const void *obj_table,\n+\t\tunsigned int esize, unsigned int n, unsigned int *free_space)\n+{\n+\treturn __rte_ring_do_enqueue_elem(r, obj_table, esize, n,\n+\t\t\tRTE_RING_QUEUE_VARIABLE, r->prod.single, free_space);\n+}\n+\n+/**\n+ * Dequeue several objects from a ring (multi-consumers safe). When the request\n+ * objects are more than the available objects, only dequeue the actual number\n+ * of objects\n+ *\n+ * This function uses a \"compare and set\" instruction to move the\n+ * consumer index atomically.\n+ *\n+ * @param r\n+ *   A pointer to the ring structure.\n+ * @param obj_table\n+ *   A pointer to a table of void * pointers (objects) that will be filled.\n+ * @param esize\n+ *   The size of ring element, in bytes. It must be a multiple of 4.\n+ *   This must be the same value used while creating the ring. Otherwise\n+ *   the results are undefined.\n+ * @param n\n+ *   The number of objects to dequeue from the ring to the obj_table.\n+ * @param available\n+ *   If non-NULL, returns the number of remaining ring entries after the\n+ *   dequeue has finished.\n+ * @return\n+ *   - n: Actual number of objects dequeued, 0 if ring is empty\n+ */\n+static __rte_always_inline unsigned\n+rte_ring_mc_dequeue_burst_elem(struct rte_ring *r, void *obj_table,\n+\t\tunsigned int esize, unsigned int n, unsigned int *available)\n+{\n+\treturn __rte_ring_do_dequeue_elem(r, obj_table, esize, n,\n+\t\t\tRTE_RING_QUEUE_VARIABLE, __IS_MC, available);\n+}\n+\n+/**\n+ * Dequeue several objects from a ring (NOT multi-consumers safe).When the\n+ * request objects are more than the available objects, only dequeue the\n+ * actual number of objects\n+ *\n+ * @param r\n+ *   A pointer to the ring structure.\n+ * @param obj_table\n+ *   A pointer to a table of void * pointers (objects) that will be filled.\n+ * @param esize\n+ *   The size of ring element, in bytes. It must be a multiple of 4.\n+ *   This must be the same value used while creating the ring. Otherwise\n+ *   the results are undefined.\n+ * @param n\n+ *   The number of objects to dequeue from the ring to the obj_table.\n+ * @param available\n+ *   If non-NULL, returns the number of remaining ring entries after the\n+ *   dequeue has finished.\n+ * @return\n+ *   - n: Actual number of objects dequeued, 0 if ring is empty\n+ */\n+static __rte_always_inline unsigned\n+rte_ring_sc_dequeue_burst_elem(struct rte_ring *r, void *obj_table,\n+\t\tunsigned int esize, unsigned int n, unsigned int *available)\n+{\n+\treturn __rte_ring_do_dequeue_elem(r, obj_table, esize, n,\n+\t\t\tRTE_RING_QUEUE_VARIABLE, __IS_SC, available);\n+}\n+\n+/**\n+ * Dequeue multiple objects from a ring up to a maximum number.\n+ *\n+ * This function calls the multi-consumers or the single-consumer\n+ * version, depending on the default behaviour that was specified at\n+ * ring creation time (see flags).\n+ *\n+ * @param r\n+ *   A pointer to the ring structure.\n+ * @param obj_table\n+ *   A pointer to a table of void * pointers (objects) that will be filled.\n+ * @param esize\n+ *   The size of ring element, in bytes. It must be a multiple of 4.\n+ *   This must be the same value used while creating the ring. Otherwise\n+ *   the results are undefined.\n+ * @param n\n+ *   The number of objects to dequeue from the ring to the obj_table.\n+ * @param available\n+ *   If non-NULL, returns the number of remaining ring entries after the\n+ *   dequeue has finished.\n+ * @return\n+ *   - Number of objects dequeued\n+ */\n+static __rte_always_inline unsigned int\n+rte_ring_dequeue_burst_elem(struct rte_ring *r, void *obj_table,\n+\t\tunsigned int esize, unsigned int n, unsigned int *available)\n+{\n+\treturn __rte_ring_do_dequeue_elem(r, obj_table, esize, n,\n+\t\t\t\tRTE_RING_QUEUE_VARIABLE,\n+\t\t\t\tr->cons.single, available);\n+}\n+\n+#ifdef __cplusplus\n+}\n+#endif\n+\n+#endif /* _RTE_RING_ELEM_H_ */\ndiff --git a/lib/librte_ring/rte_ring_version.map b/lib/librte_ring/rte_ring_version.map\nindex 89d84bcf4..7a5328dd5 100644\n--- a/lib/librte_ring/rte_ring_version.map\n+++ b/lib/librte_ring/rte_ring_version.map\n@@ -15,6 +15,8 @@ DPDK_20.0 {\n EXPERIMENTAL {\n \tglobal:\n \n+\trte_ring_create_elem;\n+\trte_ring_get_memsize_elem;\n \trte_ring_reset;\n \n };\n",
    "prefixes": [
        "v8",
        "2/6"
    ]
}