get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 49251,
    "url": "https://patches.dpdk.org/api/patches/49251/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/20181222021420.5114-3-honnappa.nagarahalli@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": "<20181222021420.5114-3-honnappa.nagarahalli@arm.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20181222021420.5114-3-honnappa.nagarahalli@arm.com",
    "date": "2018-12-22T02:14:20",
    "name": "[RFC,v2,2/2] test/rcu_qsbr: add API and functional tests",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "daa4110879875a770199eb7b85409fb050773f66",
    "submitter": {
        "id": 1045,
        "url": "https://patches.dpdk.org/api/people/1045/?format=api",
        "name": "Honnappa Nagarahalli",
        "email": "honnappa.nagarahalli@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/20181222021420.5114-3-honnappa.nagarahalli@arm.com/mbox/",
    "series": [
        {
            "id": 2932,
            "url": "https://patches.dpdk.org/api/series/2932/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=2932",
            "date": "2018-12-22T02:14:18",
            "name": "rcu: add RCU library supporting QSBR mechanism",
            "version": 2,
            "mbox": "https://patches.dpdk.org/series/2932/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/49251/comments/",
    "check": "warning",
    "checks": "https://patches.dpdk.org/api/patches/49251/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id D82DE1BE60;\n\tSat, 22 Dec 2018 03:15:09 +0100 (CET)",
            "from foss.arm.com (usa-sjc-mx-foss1.foss.arm.com [217.140.101.70])\n\tby dpdk.org (Postfix) with ESMTP id A86D91BE7A\n\tfor <dev@dpdk.org>; Sat, 22 Dec 2018 03:15:07 +0100 (CET)",
            "from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249])\n\tby usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 1FEF2EBD;\n\tFri, 21 Dec 2018 18:15:07 -0800 (PST)",
            "from qc2400f-1.austin.arm.com (qc2400f-1.austin.arm.com\n\t[10.118.12.24])\n\tby usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id\n\t77A1E3F575; Fri, 21 Dec 2018 18:15:06 -0800 (PST)"
        ],
        "From": "Honnappa Nagarahalli <honnappa.nagarahalli@arm.com>",
        "To": "dev@dpdk.org, konstantin.ananyev@intel.com, stephen@networkplumber.org, \n\tpaulmck@linux.ibm.com, honnappa.nagarahalli@arm.com",
        "Cc": "gavin.hu@arm.com, dharmik.thakkar@arm.com, nd@arm.com,\n\tMalvika Gupta <malvika.gupta@arm.com>",
        "Date": "Fri, 21 Dec 2018 20:14:20 -0600",
        "Message-Id": "<20181222021420.5114-3-honnappa.nagarahalli@arm.com>",
        "X-Mailer": "git-send-email 2.17.1",
        "In-Reply-To": "<20181222021420.5114-1-honnappa.nagarahalli@arm.com>",
        "References": "<20181122033055.3431-1-honnappa.nagarahalli@arm.com>\n\t<20181222021420.5114-1-honnappa.nagarahalli@arm.com>",
        "Subject": "[dpdk-dev] [RFC v2 2/2] test/rcu_qsbr: add API and functional tests",
        "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\t<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\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "From: Dharmik Thakkar <dharmik.thakkar@arm.com>\n\nAdd API positive/negative test cases and functional tests.\n\nSigned-off-by: Malvika Gupta <malvika.gupta@arm.com>\nSigned-off-by: Dharmik Thakkar <dharmik.thakkar@arm.com>\nSigned-off-by: Honnappa Nagarahalli <honnappa.nagarahalli@arm.com>\nReviewed-by: Gavin Hu <gavin.hu@arm.com>\n---\n test/test/Makefile         |   2 +\n test/test/autotest_data.py |   6 +\n test/test/meson.build      |   5 +-\n test/test/test_rcu_qsbr.c  | 801 +++++++++++++++++++++++++++++++++++++\n 4 files changed, 813 insertions(+), 1 deletion(-)\n create mode 100644 test/test/test_rcu_qsbr.c",
    "diff": "diff --git a/test/test/Makefile b/test/test/Makefile\nindex ab4fec34a..dfc0325e4 100644\n--- a/test/test/Makefile\n+++ b/test/test/Makefile\n@@ -207,6 +207,8 @@ SRCS-$(CONFIG_RTE_LIBRTE_KVARGS) += test_kvargs.c\n \n SRCS-$(CONFIG_RTE_LIBRTE_BPF) += test_bpf.c\n \n+SRCS-$(CONFIG_RTE_LIBRTE_RCU) += test_rcu_qsbr.c\n+\n CFLAGS += -DALLOW_EXPERIMENTAL_API\n \n CFLAGS += -O3\ndiff --git a/test/test/autotest_data.py b/test/test/autotest_data.py\nindex 0fb7866db..cbd1f94ad 100644\n--- a/test/test/autotest_data.py\n+++ b/test/test/autotest_data.py\n@@ -676,6 +676,12 @@\n         \"Func\":    default_autotest,\n         \"Report\":  None,\n     },\n+    {\n+        \"Name\":    \"RCU QSBR autotest\",\n+        \"Command\": \"rcu_qsbr_autotest\",\n+        \"Func\":    default_autotest,\n+        \"Report\":  None,\n+    },\n     #\n     # Please always make sure that ring_perf is the last test!\n     #\ndiff --git a/test/test/meson.build b/test/test/meson.build\nindex 554e9945f..3be21be27 100644\n--- a/test/test/meson.build\n+++ b/test/test/meson.build\n@@ -100,6 +100,7 @@ test_sources = files('commands.c',\n \t'test_timer.c',\n \t'test_timer_perf.c',\n \t'test_timer_racecond.c',\n+\t'test_rcu_qsbr.c',\n \t'test_version.c',\n \t'virtual_pmd.c'\n )\n@@ -122,7 +123,8 @@ test_deps = ['acl',\n \t'port',\n \t'reorder',\n \t'ring',\n-\t'timer'\n+\t'timer',\n+\t'rcu'\n ]\n \n test_names = [\n@@ -228,6 +230,7 @@ test_names = [\n \t'timer_autotest',\n \t'timer_perf__autotest',\n \t'timer_racecond_autotest',\n+\t'rcu_qsbr_autotest',\n \t'user_delay_us',\n \t'version_autotest',\n ]\ndiff --git a/test/test/test_rcu_qsbr.c b/test/test/test_rcu_qsbr.c\nnew file mode 100644\nindex 000000000..c9efd3e21\n--- /dev/null\n+++ b/test/test/test_rcu_qsbr.c\n@@ -0,0 +1,801 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright (c) 2018 Arm Limited\n+ */\n+\n+#include <stdio.h>\n+#include <stdbool.h>\n+#include <rte_pause.h>\n+#include <rte_rcu_qsbr.h>\n+#include <rte_hash.h>\n+#include <rte_hash_crc.h>\n+#include <rte_malloc.h>\n+#include <rte_cycles.h>\n+\n+#include \"test.h\"\n+\n+/* Check condition and return an error if true. */\n+#define RCU_QSBR_RETURN_IF_ERROR(cond, str, ...) do { \\\n+\tif (cond) { \\\n+\t\tprintf(\"ERROR file %s, line %d: \" str \"\\n\", __FILE__, \\\n+\t\t\t__LINE__, ##__VA_ARGS__); \\\n+\t\treturn -1; \\\n+\t} \\\n+} while (0)\n+\n+#define RTE_RCU_MAX_LCORE 64\n+uint16_t enabled_core_ids[RTE_RCU_MAX_LCORE];\n+uint8_t num_cores;\n+uint16_t num_1qs = 1; /* Number of quiescent states = 1 */\n+uint16_t num_2qs = 2; /* Number of quiescent states = 2 */\n+uint16_t num_3qs = 3; /* Number of quiescent states = 3 */\n+\n+static uint32_t *keys;\n+#define TOTAL_ENTRY (1024 * 8)\n+#define COUNTER_VALUE 4096\n+uint32_t *hash_data[RTE_RCU_MAX_LCORE][TOTAL_ENTRY];\n+uint8_t writer_done;\n+\n+struct rte_rcu_qsbr t[RTE_RCU_MAX_LCORE];\n+struct rte_hash *h[RTE_RCU_MAX_LCORE];\n+char hash_name[RTE_RCU_MAX_LCORE][8];\n+\n+static inline int\n+get_enabled_cores_mask(void)\n+{\n+\tuint16_t core_id;\n+\tuint32_t max_cores = rte_lcore_count();\n+\tif (max_cores > RTE_RCU_MAX_LCORE) {\n+\t\tprintf(\"Number of cores exceed %d\\n\", RTE_RCU_MAX_LCORE);\n+\t\treturn -1;\n+\t}\n+\n+\tcore_id = 0;\n+\tnum_cores = 0;\n+\tRTE_LCORE_FOREACH_SLAVE(core_id) {\n+\t\tenabled_core_ids[num_cores] = core_id;\n+\t\tnum_cores++;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/*\n+ * rte_rcu_qsbr_register_thread: Add a reader thread, to the list of threads\n+ * reporting their quiescent state on a QS variable.\n+ */\n+static int\n+test_rcu_qsbr_register_thread(void)\n+{\n+\tprintf(\"\\nTest rte_rcu_qsbr_register_thread()\\n\");\n+\n+\trte_rcu_qsbr_init(&t[0]);\n+\n+\trte_rcu_qsbr_register_thread(&t[0], enabled_core_ids[0]);\n+\treturn 0;\n+}\n+\n+/*\n+ * rte_rcu_qsbr_unregister_thread: Remove a reader thread, from the list of\n+ * threads reporting their quiescent state on a QS variable.\n+ */\n+static int\n+test_rcu_qsbr_unregister_thread(void)\n+{\n+\tint i, j, ret;\n+\tuint64_t token;\n+\tuint8_t num_threads[3] = {1, RTE_RCU_MAX_THREADS, 1};\n+\n+\tprintf(\"\\nTest rte_rcu_qsbr_unregister_thread()\\n\");\n+\n+\trte_rcu_qsbr_init(&t[0]);\n+\n+\trte_rcu_qsbr_register_thread(&t[0], enabled_core_ids[0]);\n+\n+\t/* Find first disabled core */\n+\tfor (i = 0; i < RTE_RCU_MAX_LCORE; i++) {\n+\t\tif (enabled_core_ids[i] == 0)\n+\t\t\tbreak;\n+\t}\n+\t/* Test with disabled lcore */\n+\trte_rcu_qsbr_unregister_thread(&t[0], i);\n+\n+\t/* Test with enabled lcore */\n+\trte_rcu_qsbr_unregister_thread(&t[0], enabled_core_ids[0]);\n+\n+\t/*\n+\t * Test with different thread_ids:\n+\t * 1 - thread_id = 0\n+\t * 2 - All possible thread_ids, from 0 to RTE_RCU_MAX_THREADS\n+\t * 3 - thread_id = RTE_RCU_MAX_THREADS - 1\n+\t */\n+\tfor (j = 0; j < 3; j++) {\n+\t\trte_rcu_qsbr_init(&t[0]);\n+\n+\t\tfor (i = 0; i < num_threads[j]; i++)\n+\t\t\trte_rcu_qsbr_register_thread(&t[0],\n+\t\t\t\t(j == 2) ? (RTE_RCU_MAX_THREADS - 1) : i);\n+\n+\t\trte_rcu_qsbr_start(&t[0], 1, &token);\n+\t\tRCU_QSBR_RETURN_IF_ERROR((token != 1), \"QSBR Start\");\n+\t\t/* Update quiescent state counter */\n+\t\tfor (i = 0; i < num_threads[j]; i++) {\n+\t\t\t/* Skip one update */\n+\t\t\tif (i == 72)\n+\t\t\t\tcontinue;\n+\t\t\trte_rcu_qsbr_update(&t[0],\n+\t\t\t\t(j == 2) ? (RTE_RCU_MAX_THREADS - 1) : i);\n+\t\t}\n+\n+\t\tif (j == 1) {\n+\t\t\t/* Validate the updates */\n+\t\t\tret = rte_rcu_qsbr_check(&t[0], token, false);\n+\t\t\tRCU_QSBR_RETURN_IF_ERROR((ret == 1), \"Non-blocking QSBR check\");\n+\t\t\t/* Update the previously skipped thread */\n+\t\t\trte_rcu_qsbr_update(&t[0], 72);\n+\t\t}\n+\n+\t\t/* Validate the updates */\n+\t\tret = rte_rcu_qsbr_check(&t[0], token, false);\n+\t\tRCU_QSBR_RETURN_IF_ERROR((ret == 0), \"Non-blocking QSBR check\");\n+\n+\t\tfor (i = 0; i < num_threads[j]; i++)\n+\t\t\trte_rcu_qsbr_unregister_thread(&t[0],\n+\t\t\t\t(j == 2) ? (RTE_RCU_MAX_THREADS - 1) : i);\n+\n+\t\t/* Check with no thread registered */\n+\t\tret = rte_rcu_qsbr_check(&t[0], token, true);\n+\t\tRCU_QSBR_RETURN_IF_ERROR((ret == 0), \"Blocking QSBR check\");\n+\t}\n+\treturn 0;\n+}\n+\n+/*\n+ * rte_rcu_qsbr_start: Trigger the worker threads to report the quiescent state\n+ * status.\n+ */\n+static int\n+test_rcu_qsbr_start(void)\n+{\n+\tuint64_t token;\n+\tint i;\n+\n+\tprintf(\"\\nTest rte_rcu_qsbr_start()\\n\");\n+\n+\trte_rcu_qsbr_init(&t[0]);\n+\n+\tfor (i = 0; i < 3; i++)\n+\t\trte_rcu_qsbr_register_thread(&t[0], enabled_core_ids[i]);\n+\n+\trte_rcu_qsbr_start(&t[0], 1, &token);\n+\tRCU_QSBR_RETURN_IF_ERROR((token != 1), \"QSBR Start\");\n+\treturn 0;\n+}\n+\n+/*\n+ * rte_rcu_qsbr_check: Checks if all the worker threads have entered the queis-\n+ * cent state 'n' number of times. 'n' is provided in rte_rcu_qsbr_start API.\n+ */\n+static int\n+test_rcu_qsbr_check(void)\n+{\n+\tint i, ret;\n+\tuint64_t token;\n+\n+\tprintf(\"\\nTest rte_rcu_qsbr_check()\\n\");\n+\n+\trte_rcu_qsbr_init(&t[0]);\n+\n+\trte_rcu_qsbr_start(&t[0], 1, &token);\n+\tRCU_QSBR_RETURN_IF_ERROR((token != 1), \"QSBR Start\");\n+\n+\tret = rte_rcu_qsbr_check(&t[0], 0, true);\n+\tRCU_QSBR_RETURN_IF_ERROR((ret == 0), \"Token = 0\");\n+\n+\tret = rte_rcu_qsbr_check(&t[0], token, true);\n+\tRCU_QSBR_RETURN_IF_ERROR((ret == 0), \"Blocking QSBR check\");\n+\n+\tfor (i = 0; i < 3; i++)\n+\t\trte_rcu_qsbr_register_thread(&t[0], enabled_core_ids[i]);\n+\n+\tret = rte_rcu_qsbr_check(&t[0], token, false);\n+\tRCU_QSBR_RETURN_IF_ERROR((ret == 0), \"Non-blocking QSBR check\");\n+\n+\trte_rcu_qsbr_start(&t[0], 1, &token);\n+\tRCU_QSBR_RETURN_IF_ERROR((token != 2), \"QSBR Start\");\n+\n+\tret = rte_rcu_qsbr_check(&t[0], token, false);\n+\tRCU_QSBR_RETURN_IF_ERROR((ret == 1), \"Non-blocking QSBR check\");\n+\n+\tfor (i = 0; i < 3; i++)\n+\t\trte_rcu_qsbr_unregister_thread(&t[0], enabled_core_ids[i]);\n+\n+\tret = rte_rcu_qsbr_check(&t[0], token, true);\n+\tRCU_QSBR_RETURN_IF_ERROR((ret == 0), \"Blocking QSBR check\");\n+\n+\treturn 0;\n+}\n+\n+/*\n+ * rte_rcu_qsbr_dump: Dump status of a single QS variable to a file\n+ */\n+static int\n+test_rcu_qsbr_dump(void)\n+{\n+\tint i;\n+\n+\tprintf(\"\\nTest rte_rcu_qsbr_dump()\\n\");\n+\n+\trte_rcu_qsbr_init(&t[0]);\n+\trte_rcu_qsbr_init(&t[1]);\n+\n+\t/* QS variable with 0 core mask */\n+\trte_rcu_qsbr_dump(stdout, &t[0]);\n+\n+\trte_rcu_qsbr_register_thread(&t[0], enabled_core_ids[0]);\n+\n+\tfor (i = 1; i < 3; i++)\n+\t\trte_rcu_qsbr_register_thread(&t[1], enabled_core_ids[i]);\n+\n+\trte_rcu_qsbr_dump(stdout, &t[0]);\n+\trte_rcu_qsbr_dump(stdout, &t[1]);\n+\tprintf(\"\\n\");\n+\treturn 0;\n+}\n+\n+static int\n+test_rcu_qsbr_reader(void *arg)\n+{\n+\tstruct rte_rcu_qsbr *temp;\n+\tstruct rte_hash *hash = NULL;\n+\tint i;\n+\tuint32_t lcore_id = rte_lcore_id();\n+\tuint8_t read_type = (uint8_t)((uintptr_t)arg);\n+\tuint32_t *pdata;\n+\n+\ttemp = &t[read_type];\n+\thash = h[read_type];\n+\n+\tdo {\n+\t\trte_rcu_qsbr_register_thread(temp, lcore_id);\n+\t\tfor (i = 0; i < TOTAL_ENTRY; i++) {\n+\t\t\tif (rte_hash_lookup_data(hash, keys+i,\n+\t\t\t\t\t(void **)&pdata) != -ENOENT) {\n+\t\t\t\t*pdata = 0;\n+\t\t\t\twhile (*pdata < COUNTER_VALUE)\n+\t\t\t\t\t++*pdata;\n+\t\t\t}\n+\t\t}\n+\t\t/* Update quiescent state counter */\n+\t\trte_rcu_qsbr_update(temp, lcore_id);\n+\t\trte_rcu_qsbr_unregister_thread(temp, lcore_id);\n+\t} while (!writer_done);\n+\n+\treturn 0;\n+}\n+\n+static int\n+test_rcu_qsbr_writer(void *arg)\n+{\n+\tuint64_t token;\n+\tint32_t pos;\n+\tstruct rte_rcu_qsbr *temp;\n+\tstruct rte_hash *hash = NULL;\n+\tuint8_t writer_type = (uint8_t)((uintptr_t)arg);\n+\n+\ttemp = &t[(writer_type/2) % RTE_RCU_MAX_LCORE];\n+\thash = h[(writer_type/2) % RTE_RCU_MAX_LCORE];\n+\n+\t/* Delete element from the shared data structure */\n+\tpos = rte_hash_del_key(hash, keys + (writer_type % TOTAL_ENTRY));\n+\tif (pos < 0) {\n+\t\tprintf(\"Delete key failed #%d\\n\",\n+\t\t       keys[writer_type % TOTAL_ENTRY]);\n+\t\treturn -1;\n+\t}\n+\t/*\n+\t * Start the quiescent state query process\n+\t * Note: Expected Quiescent states kept greater than 1 for test only\n+\t */\n+\trte_rcu_qsbr_start(temp, writer_type + 1, &token);\n+\t/* Check the quiescent state status */\n+\trte_rcu_qsbr_check(temp, token, true);\n+\tif (*hash_data[(writer_type/2) % RTE_RCU_MAX_LCORE]\n+\t    [writer_type % TOTAL_ENTRY] != COUNTER_VALUE &&\n+\t    *hash_data[(writer_type/2) % RTE_RCU_MAX_LCORE]\n+\t    [writer_type % TOTAL_ENTRY] != 0) {\n+\t\tprintf(\"Reader did not complete #%d = %d\\t\", writer_type,\n+\t\t\t*hash_data[(writer_type/2) % RTE_RCU_MAX_LCORE]\n+\t\t\t\t[writer_type % TOTAL_ENTRY]);\n+\t\treturn -1;\n+\t}\n+\n+\tif (rte_hash_free_key_with_position(hash, pos) < 0) {\n+\t\tprintf(\"Failed to free the key #%d\\n\",\n+\t\t       keys[writer_type % TOTAL_ENTRY]);\n+\t\treturn -1;\n+\t}\n+\trte_free(hash_data[(writer_type/2) % RTE_RCU_MAX_LCORE]\n+\t\t\t\t[writer_type % TOTAL_ENTRY]);\n+\thash_data[(writer_type/2) % RTE_RCU_MAX_LCORE]\n+\t\t\t[writer_type % TOTAL_ENTRY] = NULL;\n+\n+\treturn 0;\n+}\n+\n+static struct rte_hash *\n+init_hash(int hash_id)\n+{\n+\tint i;\n+\tstruct rte_hash *h = NULL;\n+\tsprintf(hash_name[hash_id], \"hash%d\", hash_id);\n+\tstruct rte_hash_parameters hash_params = {\n+\t\t.entries = TOTAL_ENTRY,\n+\t\t.key_len = sizeof(uint32_t),\n+\t\t.hash_func_init_val = 0,\n+\t\t.socket_id = rte_socket_id(),\n+\t\t.hash_func = rte_hash_crc,\n+\t\t.extra_flag =\n+\t\t\tRTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF,\n+\t\t.name = hash_name[hash_id],\n+\t};\n+\n+\th = rte_hash_create(&hash_params);\n+\tif (h == NULL) {\n+\t\tprintf(\"Hash create Failed\\n\");\n+\t\treturn NULL;\n+\t}\n+\n+\tfor (i = 0; i < TOTAL_ENTRY; i++) {\n+\t\thash_data[hash_id][i] = rte_zmalloc(NULL, sizeof(uint32_t), 0);\n+\t\tif (hash_data[hash_id][i] == NULL) {\n+\t\t\tprintf(\"No memory\\n\");\n+\t\t\treturn NULL;\n+\t\t}\n+\t}\n+\tkeys = rte_malloc(NULL, sizeof(uint32_t) * TOTAL_ENTRY, 0);\n+\tif (keys == NULL) {\n+\t\tprintf(\"No memory\\n\");\n+\t\treturn NULL;\n+\t}\n+\n+\tfor (i = 0; i < TOTAL_ENTRY; i++)\n+\t\tkeys[i] = i;\n+\n+\tfor (i = 0; i < TOTAL_ENTRY; i++) {\n+\t\tif (rte_hash_add_key_data(h, keys + i,\n+\t\t\t\t(void *)((uintptr_t)hash_data[hash_id][i]))\n+\t\t\t\t< 0) {\n+\t\t\tprintf(\"Hash key add Failed #%d\\n\", i);\n+\t\t\treturn NULL;\n+\t\t}\n+\t}\n+\treturn h;\n+}\n+\n+/*\n+ * Functional test:\n+ * Single writer, Single QS variable Single QSBR query, Blocking rcu_qsbr_check\n+ */\n+static int\n+test_rcu_qsbr_sw_sv_1qs(void)\n+{\n+\tuint64_t token;\n+\tint i;\n+\tint32_t pos;\n+\twriter_done = 0;\n+\n+\tprintf(\"\\nTest: 1 writer, 1 QSBR variable, 1 QSBR Query, \"\n+\t       \"Blocking QSBR Check\\n\");\n+\n+\t/* QS variable is initialized */\n+\trte_rcu_qsbr_init(&t[0]);\n+\n+\t/* Register worker threads on 4 cores */\n+\tfor (i = 0; i < 4; i++)\n+\t\trte_rcu_qsbr_register_thread(&t[0], enabled_core_ids[i]);\n+\n+\t/* Shared data structure created */\n+\th[0] = init_hash(0);\n+\tif (h[0] == NULL) {\n+\t\tprintf(\"Hash init failed\\n\");\n+\t\tgoto error;\n+\t}\n+\n+\t/* Reader threads are launched */\n+\tfor (i = 0; i < 4; i++)\n+\t\trte_eal_remote_launch(test_rcu_qsbr_reader, NULL,\n+\t\t\t\t\tenabled_core_ids[i]);\n+\n+\tfor (i = 0; i < TOTAL_ENTRY; i++) {\n+\t\t/* Delete elements from the shared data structure */\n+\t\tpos = rte_hash_del_key(h[0], keys + i);\n+\t\tif (pos < 0) {\n+\t\t\tprintf(\"Delete key failed #%d\\n\", keys[i]);\n+\t\t\tgoto error;\n+\t\t}\n+\t\t/* Start the quiescent state query process */\n+\t\trte_rcu_qsbr_start(&t[0], num_1qs, &token);\n+\n+\t\t/* Check the quiescent state status */\n+\t\trte_rcu_qsbr_check(&t[0], token, true);\n+\t\tif (*hash_data[0][i] != COUNTER_VALUE &&\n+\t\t\t*hash_data[0][i] != 0) {\n+\t\t\tprintf(\"Reader did not complete #%d =  %d\\n\", i,\n+\t\t\t\t\t\t\t*hash_data[0][i]);\n+\t\t\tgoto error;\n+\t\t}\n+\n+\t\tif (rte_hash_free_key_with_position(h[0], pos) < 0) {\n+\t\t\tprintf(\"Failed to free the key #%d\\n\", keys[i]);\n+\t\t\tgoto error;\n+\t\t}\n+\t\trte_free(hash_data[0][i]);\n+\t\thash_data[0][i] = NULL;\n+\t}\n+\twriter_done = 1;\n+\t/* Wait until all readers have exited */\n+\trte_eal_mp_wait_lcore();\n+\t/* Check return value from threads */\n+\tfor (i = 0; i < 4; i++)\n+\t\tif (lcore_config[enabled_core_ids[i]].ret < 0)\n+\t\t\tgoto error;\n+\trte_hash_free(h[0]);\n+\trte_free(keys);\n+\n+\treturn 0;\n+\n+error:\n+\twriter_done = 1;\n+\t/* Wait until all readers have exited */\n+\trte_eal_mp_wait_lcore();\n+\n+\trte_hash_free(h[0]);\n+\trte_free(keys);\n+\tfor (i = 0; i < TOTAL_ENTRY; i++)\n+\t\trte_free(hash_data[0][i]);\n+\n+\treturn -1;\n+}\n+\n+/*\n+ * Functional test:\n+ * Single writer, Single QS variable, Single QSBR query,\n+ * Non-blocking rcu_qsbr_check\n+ */\n+static int\n+test_rcu_qsbr_sw_sv_1qs_non_blocking(void)\n+{\n+\tuint64_t token;\n+\tint i, ret;\n+\tint32_t pos;\n+\twriter_done = 0;\n+\n+\tprintf(\"Test: 1 writer, 1 QSBR variable, 1 QSBR Query, \"\n+\t       \"Non-Blocking QSBR check\\n\");\n+\n+\trte_rcu_qsbr_init(&t[0]);\n+\t/* Register worker threads on 4 cores */\n+\tfor (i = 0; i < 4; i++)\n+\t\trte_rcu_qsbr_register_thread(&t[0], enabled_core_ids[i]);\n+\n+\t/* Shared data structure created */\n+\th[0] = init_hash(0);\n+\tif (h[0] == NULL) {\n+\t\tprintf(\"Hash init failed\\n\");\n+\t\tgoto error;\n+\t}\n+\n+\t/* Reader threads are launched */\n+\tfor (i = 0; i < 4; i++)\n+\t\trte_eal_remote_launch(test_rcu_qsbr_reader, NULL,\n+\t\t\t\t\tenabled_core_ids[i]);\n+\n+\tfor (i = 0; i < TOTAL_ENTRY; i++) {\n+\t\t/* Delete elements from the shared data structure */\n+\t\tpos = rte_hash_del_key(h[0], keys + i);\n+\t\tif (pos < 0) {\n+\t\t\tprintf(\"Delete key failed #%d\\n\", keys[i]);\n+\t\t\tgoto error;\n+\t\t}\n+\t\t/* Start the quiescent state query process */\n+\t\trte_rcu_qsbr_start(&t[0], num_1qs, &token);\n+\n+\t\t/* Check the quiescent state status */\n+\t\tdo {\n+\t\t\tret = rte_rcu_qsbr_check(&t[0], token, false);\n+\t\t} while (ret == 0);\n+\t\tif (*hash_data[0][i] != COUNTER_VALUE &&\n+\t\t\t*hash_data[0][i] != 0) {\n+\t\t\tprintf(\"Reader did not complete  #%d = %d\\n\", i,\n+\t\t\t\t\t\t\t*hash_data[0][i]);\n+\t\t\tgoto error;\n+\t\t}\n+\n+\t\tif (rte_hash_free_key_with_position(h[0], pos) < 0) {\n+\t\t\tprintf(\"Failed to free the key #%d\\n\", keys[i]);\n+\t\t\tgoto error;\n+\t\t}\n+\t\trte_free(hash_data[0][i]);\n+\t\thash_data[0][i] = NULL;\n+\t}\n+\twriter_done = 1;\n+\t/* Wait until all readers have exited */\n+\trte_eal_mp_wait_lcore();\n+\t/* Check return value from threads */\n+\tfor (i = 0; i < 4; i++)\n+\t\tif (lcore_config[enabled_core_ids[i]].ret < 0)\n+\t\t\tgoto error;\n+\trte_hash_free(h[0]);\n+\trte_free(keys);\n+\n+\treturn 0;\n+\n+error:\n+\twriter_done = 1;\n+\t/* Wait until all readers have exited */\n+\trte_eal_mp_wait_lcore();\n+\n+\trte_hash_free(h[0]);\n+\trte_free(keys);\n+\tfor (i = 0; i < TOTAL_ENTRY; i++)\n+\t\trte_free(hash_data[0][i]);\n+\n+\treturn -1;\n+}\n+\n+/*\n+ * Functional test:\n+ * Single writer, Single QS variable, simultaneous QSBR Queries\n+ */\n+static int\n+test_rcu_qsbr_sw_sv_3qs(void)\n+{\n+\tuint64_t token[3];\n+\tint i;\n+\tint32_t pos[3];\n+\twriter_done = 0;\n+\n+\tprintf(\"Test: 1 writer, 1 QSBR variable, simultaneous QSBR queries\\n\");\n+\n+\trte_rcu_qsbr_init(&t[0]);\n+\n+\t/* Register worker threads on 4 cores */\n+\tfor (i = 0; i < 4; i++)\n+\t\trte_rcu_qsbr_register_thread(&t[0], enabled_core_ids[i]);\n+\n+\t/* Shared data structure created */\n+\th[0] = init_hash(0);\n+\tif (h[0] == NULL) {\n+\t\tprintf(\"Hash init failed\\n\");\n+\t\tgoto error;\n+\t}\n+\n+\t/* Reader threads are launched */\n+\tfor (i = 0; i < 4; i++)\n+\t\trte_eal_remote_launch(test_rcu_qsbr_reader, NULL,\n+\t\t\t\t\tenabled_core_ids[i]);\n+\n+\t/* Delete element from the shared data structure */\n+\tpos[0] = rte_hash_del_key(h[0], keys + 0);\n+\tif (pos[0] < 0) {\n+\t\tprintf(\"Delete key failed #%d\\n\", keys[0]);\n+\t\tgoto error;\n+\t}\n+\t/* Start the quiescent state query process */\n+\trte_rcu_qsbr_start(&t[0], num_1qs, &token[0]);\n+\n+\t/* Delete element from the shared data structure */\n+\tpos[1] = rte_hash_del_key(h[0], keys + 3);\n+\tif (pos[1] < 0) {\n+\t\tprintf(\"Delete key failed #%d\\n\", keys[3]);\n+\t\tgoto error;\n+\t}\n+\t/*\n+\t * Start the quiescent state query process\n+\t * Note: num_2qs kept greater than 1 for test only\n+\t */\n+\trte_rcu_qsbr_start(&t[0], num_2qs, &token[1]);\n+\n+\t/* Delete element from the shared data structure */\n+\tpos[2] = rte_hash_del_key(h[0], keys + 6);\n+\tif (pos[2] < 0) {\n+\t\tprintf(\"Delete key failed #%d\\n\", keys[6]);\n+\t\tgoto error;\n+\t}\n+\t/*\n+\t * Start the quiescent state query process\n+\t * Note: num_3qs kept greater than 1 for test only\n+\t */\n+\trte_rcu_qsbr_start(&t[0], num_3qs, &token[2]);\n+\n+\t/* Check the quiescent state status */\n+\trte_rcu_qsbr_check(&t[0], token[0], true);\n+\tif (*hash_data[0][0] != COUNTER_VALUE && *hash_data[0][0] != 0) {\n+\t\tprintf(\"Reader did not complete #0 = %d\\n\", *hash_data[0][0]);\n+\t\tgoto error;\n+\t}\n+\n+\tif (rte_hash_free_key_with_position(h[0], pos[0]) < 0) {\n+\t\tprintf(\"Failed to free the key #%d\\n\", keys[0]);\n+\t\tgoto error;\n+\t}\n+\trte_free(hash_data[0][0]);\n+\thash_data[0][0] = NULL;\n+\n+\t/* Check the quiescent state status */\n+\trte_rcu_qsbr_check(&t[0], token[1], true);\n+\tif (*hash_data[0][3] != COUNTER_VALUE && *hash_data[0][3] != 0) {\n+\t\tprintf(\"Reader did not complete #3 = %d\\n\", *hash_data[0][3]);\n+\t\tgoto error;\n+\t}\n+\n+\tif (rte_hash_free_key_with_position(h[0], pos[1]) < 0) {\n+\t\tprintf(\"Failed to free the key #%d\\n\", keys[3]);\n+\t\tgoto error;\n+\t}\n+\trte_free(hash_data[0][3]);\n+\thash_data[0][3] = NULL;\n+\n+\t/* Check the quiescent state status */\n+\trte_rcu_qsbr_check(&t[0], token[2], true);\n+\tif (*hash_data[0][6] != COUNTER_VALUE && *hash_data[0][6] != 0) {\n+\t\tprintf(\"Reader did not complete #6 = %d\\n\", *hash_data[0][6]);\n+\t\tgoto error;\n+\t}\n+\n+\tif (rte_hash_free_key_with_position(h[0], pos[2]) < 0) {\n+\t\tprintf(\"Failed to free the key #%d\\n\", keys[6]);\n+\t\tgoto error;\n+\t}\n+\trte_free(hash_data[0][6]);\n+\thash_data[0][6] = NULL;\n+\n+\twriter_done = 1;\n+\t/* Wait until all readers have exited */\n+\trte_eal_mp_wait_lcore();\n+\t/* Check return value from threads */\n+\tfor (i = 0; i < 4; i++)\n+\t\tif (lcore_config[enabled_core_ids[i]].ret < 0)\n+\t\t\tgoto error;\n+\trte_hash_free(h[0]);\n+\trte_free(keys);\n+\n+\treturn 0;\n+\n+error:\n+\twriter_done = 1;\n+\t/* Wait until all readers have exited */\n+\trte_eal_mp_wait_lcore();\n+\n+\trte_hash_free(h[0]);\n+\trte_free(keys);\n+\tfor (i = 0; i < TOTAL_ENTRY; i++)\n+\t\trte_free(hash_data[0][i]);\n+\n+\treturn -1;\n+}\n+\n+/*\n+ * Multi writer, Multiple QS variable, simultaneous QSBR queries\n+ */\n+static int\n+test_rcu_qsbr_mw_mv_mqs(void)\n+{\n+\tint i, j;\n+\twriter_done = 0;\n+\tuint8_t test_cores;\n+\ttest_cores = num_cores / 4;\n+\ttest_cores = test_cores * 4;\n+\n+\tprintf(\"Test: %d writers, %d QSBR variable, Simultaneous QSBR queries\\n\"\n+\t       , test_cores / 2, test_cores / 4);\n+\n+\tfor (i = 0; i < num_cores / 4; i++) {\n+\t\trte_rcu_qsbr_init(&t[i]);\n+\t\th[i] = init_hash(i);\n+\t\tif (h[i] == NULL) {\n+\t\t\tprintf(\"Hash init failed\\n\");\n+\t\t\tgoto error;\n+\t\t}\n+\t}\n+\n+\t/* Register worker threads on 2 cores */\n+\tfor (i = 0; i < test_cores / 2; i += 2) {\n+\t\trte_rcu_qsbr_register_thread(&t[i / 2], enabled_core_ids[i]);\n+\t\trte_rcu_qsbr_register_thread(&t[i / 2],\n+\t\t\t\t\t     enabled_core_ids[i + 1]);\n+\t}\n+\n+\t/* Reader threads are launched */\n+\tfor (i = 0; i < test_cores / 2; i++)\n+\t\trte_eal_remote_launch(test_rcu_qsbr_reader,\n+\t\t\t\t      (void *)(uintptr_t)(i / 2),\n+\t\t\t\t\tenabled_core_ids[i]);\n+\n+\t/* Writer threads are launched */\n+\tfor (; i < test_cores; i++)\n+\t\trte_eal_remote_launch(test_rcu_qsbr_writer,\n+\t\t\t\t      (void *)(uintptr_t)(i - (test_cores / 2)),\n+\t\t\t\t\tenabled_core_ids[i]);\n+\t/* Wait for writers to complete */\n+\tfor (i = test_cores / 2; i < test_cores;  i++)\n+\t\trte_eal_wait_lcore(enabled_core_ids[i]);\n+\n+\twriter_done = 1;\n+\t/* Wait for readers to complete */\n+\trte_eal_mp_wait_lcore();\n+\n+\t/* Check return value from threads */\n+\tfor (i = 0; i < test_cores; i++)\n+\t\tif (lcore_config[enabled_core_ids[i]].ret < 0)\n+\t\t\tgoto error;\n+\n+\tfor (i = 0; i < num_cores / 4; i++)\n+\t\trte_hash_free(h[i]);\n+\n+\trte_free(keys);\n+\n+\treturn 0;\n+\n+error:\n+\twriter_done = 1;\n+\t/* Wait until all readers have exited */\n+\trte_eal_mp_wait_lcore();\n+\n+\tfor (i = 0; i < num_cores / 4; i++)\n+\t\trte_hash_free(h[i]);\n+\trte_free(keys);\n+\tfor (j = 0; j < RTE_RCU_MAX_LCORE; j++)\n+\t\tfor (i = 0; i < TOTAL_ENTRY; i++)\n+\t\t\trte_free(hash_data[j][i]);\n+\n+\treturn -1;\n+}\n+\n+static int\n+test_rcu_qsbr_main(void)\n+{\n+\tif (get_enabled_cores_mask() != 0)\n+\t\treturn -1;\n+\n+\t/* Error-checking test cases */\n+\tif (test_rcu_qsbr_register_thread() < 0)\n+\t\tgoto test_fail;\n+\n+\tif (test_rcu_qsbr_unregister_thread() < 0)\n+\t\tgoto test_fail;\n+\n+\tif (test_rcu_qsbr_start() < 0)\n+\t\tgoto test_fail;\n+\n+\tif (test_rcu_qsbr_check() < 0)\n+\t\tgoto test_fail;\n+\n+\tif (test_rcu_qsbr_dump() < 0)\n+\t\tgoto test_fail;\n+\n+\t/* Functional test cases */\n+\tif (num_cores < 4) {\n+\t\tprintf(\"Test failed! Need 4 or more cores\\n\");\n+\t\tgoto test_fail;\n+\t}\n+\tif (test_rcu_qsbr_sw_sv_1qs() < 0)\n+\t\tgoto test_fail;\n+\n+\tif (test_rcu_qsbr_sw_sv_1qs_non_blocking() < 0)\n+\t\tgoto test_fail;\n+\n+\tif (test_rcu_qsbr_sw_sv_3qs() < 0)\n+\t\tgoto test_fail;\n+\n+\tif (test_rcu_qsbr_mw_mv_mqs() < 0)\n+\t\tgoto test_fail;\n+\n+\tprintf(\"\\n\");\n+\treturn 0;\n+\n+test_fail:\n+\treturn -1;\n+}\n+\n+REGISTER_TEST_COMMAND(rcu_qsbr_autotest, test_rcu_qsbr_main);\n",
    "prefixes": [
        "RFC",
        "v2",
        "2/2"
    ]
}