get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 127151,
    "url": "http://patches.dpdk.org/api/patches/127151/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20230522091628.96236-2-mattias.ronnblom@ericsson.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": "<20230522091628.96236-2-mattias.ronnblom@ericsson.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20230522091628.96236-2-mattias.ronnblom@ericsson.com",
    "date": "2023-05-22T09:16:26",
    "name": "[RFC,v3,1/3] eventdev: introduce event dispatcher",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "c12961fd6ddf64e70d37750cf72c6a25b0561e7e",
    "submitter": {
        "id": 1077,
        "url": "http://patches.dpdk.org/api/people/1077/?format=api",
        "name": "Mattias Rönnblom",
        "email": "mattias.ronnblom@ericsson.com"
    },
    "delegate": {
        "id": 310,
        "url": "http://patches.dpdk.org/api/users/310/?format=api",
        "username": "jerin",
        "first_name": "Jerin",
        "last_name": "Jacob",
        "email": "jerinj@marvell.com"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20230522091628.96236-2-mattias.ronnblom@ericsson.com/mbox/",
    "series": [
        {
            "id": 28106,
            "url": "http://patches.dpdk.org/api/series/28106/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=28106",
            "date": "2023-05-22T09:16:26",
            "name": "Add event dispatcher",
            "version": 3,
            "mbox": "http://patches.dpdk.org/series/28106/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/127151/comments/",
    "check": "warning",
    "checks": "http://patches.dpdk.org/api/patches/127151/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 8E73242B6F;\n\tMon, 22 May 2023 11:23:10 +0200 (CEST)",
            "from mails.dpdk.org (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 122E242D35;\n\tMon, 22 May 2023 11:23:08 +0200 (CEST)",
            "from EUR05-DB8-obe.outbound.protection.outlook.com\n (mail-db8eur05on2042.outbound.protection.outlook.com [40.107.20.42])\n by mails.dpdk.org (Postfix) with ESMTP id A37894282D\n for <dev@dpdk.org>; Mon, 22 May 2023 11:23:06 +0200 (CEST)",
            "from AM5PR1001CA0060.EURPRD10.PROD.OUTLOOK.COM\n (2603:10a6:206:15::37) by AM8PR07MB7396.eurprd07.prod.outlook.com\n (2603:10a6:20b:24d::23) with Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6411.28; Mon, 22 May\n 2023 09:23:04 +0000",
            "from AM0EUR02FT016.eop-EUR02.prod.protection.outlook.com\n (2603:10a6:206:15:cafe::8e) by AM5PR1001CA0060.outlook.office365.com\n (2603:10a6:206:15::37) with Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6411.28 via Frontend\n Transport; Mon, 22 May 2023 09:23:04 +0000",
            "from oa.msg.ericsson.com (192.176.1.74) by\n AM0EUR02FT016.mail.protection.outlook.com (10.13.54.178) with Microsoft SMTP\n Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) id\n 15.20.6433.12 via Frontend Transport; Mon, 22 May 2023 09:23:04 +0000",
            "from ESESBMB502.ericsson.se (153.88.183.169) by\n ESESBMB505.ericsson.se (153.88.183.172) with Microsoft SMTP Server\n (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id\n 15.1.2507.23; Mon, 22 May 2023 11:23:03 +0200",
            "from seliicinfr00049.seli.gic.ericsson.se (153.88.183.153) by\n smtp.internal.ericsson.com (153.88.183.185) with Microsoft SMTP Server id\n 15.1.2507.23 via Frontend Transport; Mon, 22 May 2023 11:23:03 +0200",
            "from breslau.. (seliicwb00002.seli.gic.ericsson.se [10.156.25.100])\n by seliicinfr00049.seli.gic.ericsson.se (Postfix) with ESMTP id\n 8DD453800D4; Mon, 22 May 2023 11:23:03 +0200 (CEST)"
        ],
        "ARC-Seal": "i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none;\n b=Zo3UR2DmHzev0Aw1Aj626d9gj6qdgdIIjtoPKyEpEHSCSml9LjiY5tykjL20Q7mDlsEHtp1CwdhyxPK6kDfVQ4mEQlcl2BvUt1wDDwdKcbZBxvFWQ+5zLfYnKINL1qg+C5r3V6j6gYy+xxrJadezG+4DVVGLKigQjh66zV+uySlQaEgp0wVCUIcbfmloAN8Ldv5RuLHjI0ndhqv676eumN5EcAofhbckRpGn5pWGk9LLFiOeFl6DjtOlwv0ZijdFwyawgZGj0DhZaza7et8ybDFx0xXWdzWjFtli6mIrlxYU2/mYKMU0+IzOKwQO2uiqOM+irr0NRqgAkZmBsVtVTA==",
        "ARC-Message-Signature": "i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com;\n s=arcselector9901;\n h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1;\n bh=uQkHyqgxukKlIOcDMKO9YW4q2D3oofkAaVUAzTCR7ss=;\n b=Ovr4JpfOc4vPWCGBFB30s2Eh+b5yThqTvW9pc4z0I8yDpAS2tfM6GrlyxmdxjYkHTpI5gzxxTIh9Is/894SIr1lLbb/YD0nwJHx+s16RGTJuJX/gNl4siOydSiwlVHw/o3yqn6WfXv45GELB40m6JKUHSwdInY/YjwiFBnlIemjEiZeMYPpMOsUBf9D1kHEcptkOkM4Xao19aPjfz+GQMnR72Arz3hKfqdbVdJ+LBzfdij2pMTUOFmqfLJr75SS8AGgqGhJ7ZXYZihYdVkOhLRgKaIefXiHwlFSry3xkds0CaoWmQ9EwwfqXPedsnW0w3/+L+wP7LwHs5Jh0hGHLxw==",
        "ARC-Authentication-Results": "i=1; mx.microsoft.com 1; spf=pass (sender ip is\n 192.176.1.74) smtp.rcpttodomain=dpdk.org smtp.mailfrom=ericsson.com;\n dmarc=pass (p=reject sp=reject pct=100) action=none header.from=ericsson.com;\n dkim=none (message not signed); arc=none",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=ericsson.com;\n s=selector1;\n h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;\n bh=uQkHyqgxukKlIOcDMKO9YW4q2D3oofkAaVUAzTCR7ss=;\n b=DzD8F29CL6njjP03jHeVuTZxS1HFGH7NyAriNjfR9RXnR4lirgnE/gk9DkhBV40qq/6rjwPJTMdAw5ni28OqiP1h/aujGV9CRDYD9rH8qKkp2/y2btzOqe1L07cu/qRry6O5ltl+VNZlWA3WFGaPsFuJhhes+/u1+8gVWeK+wPo=",
        "X-MS-Exchange-Authentication-Results": "spf=pass (sender IP is 192.176.1.74)\n smtp.mailfrom=ericsson.com; dkim=none (message not signed)\n header.d=none;dmarc=pass action=none header.from=ericsson.com;",
        "Received-SPF": "Pass (protection.outlook.com: domain of ericsson.com designates\n 192.176.1.74 as permitted sender)\n receiver=protection.outlook.com;\n client-ip=192.176.1.74; helo=oa.msg.ericsson.com; pr=C",
        "From": "=?utf-8?q?Mattias_R=C3=B6nnblom?= <mattias.ronnblom@ericsson.com>",
        "To": "<jerinj@marvell.com>",
        "CC": "Jerin Jacob <jerinjacobk@gmail.com>, <hofors@lysator.liu.se>,\n <dev@dpdk.org>, Van@dpdk.org, Haaren@dpdk.org,\n Harry <harry.van.haaren@intel.com>,\n =?utf-8?q?Mattias_R=C3=B6nnblom?= <mattias.ronnblom@ericsson.com>",
        "Subject": "[RFC v3 1/3] eventdev: introduce event dispatcher",
        "Date": "Mon, 22 May 2023 11:16:26 +0200",
        "Message-ID": "<20230522091628.96236-2-mattias.ronnblom@ericsson.com>",
        "X-Mailer": "git-send-email 2.34.1",
        "In-Reply-To": "<20230522091628.96236-1-mattias.ronnblom@ericsson.com>",
        "References": "<20210409113223.65260-1-mattias.ronnblom@ericsson.com>\n <20230522091628.96236-1-mattias.ronnblom@ericsson.com>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=\"UTF-8\"",
        "Content-Transfer-Encoding": "8bit",
        "X-EOPAttributedMessage": "0",
        "X-MS-PublicTrafficType": "Email",
        "X-MS-TrafficTypeDiagnostic": "AM0EUR02FT016:EE_|AM8PR07MB7396:EE_",
        "X-MS-Office365-Filtering-Correlation-Id": "900a726c-4b76-4678-8231-08db5aa6258e",
        "X-MS-Exchange-SenderADCheck": "1",
        "X-MS-Exchange-AntiSpam-Relay": "0",
        "X-Microsoft-Antispam": "BCL:0;",
        "X-Microsoft-Antispam-Message-Info": "\n QnUhE/2uqlDmPYfVfeTOB1NfjrgnlDJVNpkEQ99wC0e28tzrXDnAUfUgEghckdZdIp4usRgvPuBSM7xW5pwSPXcOJ4hYRzW+ODNtYdd663akb9uemc96mG9oqOdTmi1f0TRAKJpiPr1DadhxhcJDFD5jeI9zB4V0xQE3JQn545eTzsyM3iGf7xWN3dWvoaCrDXI0qACJQy75+d11mgPTotG/cW1vgeFAEI18gEPMiAZL2cuJG+ei5sHjC+z9XSh5iYzzv+vJ6vXPSWsADDnkNwldJ565BCuRshUmw3iEz0Cpp4laiD5J2X4yWBYw9J71r9H/S3a1vRx5AYtj8BsssCoj+bH89uATAf3TyBo5q8wGBnEUH19rU2kESXwsIwQuDPx1PfqGggbt9tMggQoxdDg/1gPjvNTb2lQHBoiFHUC13fjgTYbThnIFEDN88arAx/HkphTdLlLq16Ybomvj56hO8W2jP0ZvsKBgOGAzQZ2e5fB6NLeG7uykpA/OuNM9kk/MXAeM3G42jjIelnru9WG3PNr3ko7q4Fx/LO9kFuJIjKUZoTvSDNtaNEK6O39/u4nKyHkoiEKsYosYqqof94/cuFqvGsItriAS2Q9fy+xSSecYW8jqyVZAgdyjewToRZLOnO+HGxtCrQLElt+T1+q4M4JXvgt/tm98Ztu68h8l8+6mG/3F9lq6gzzDpPPG5mm5gyvgES6zHsdRC1p/D/P2y++MfVW5MSo0whXpVve7gplDY4UHatvcbSH0F8MUtGNLDRfwExuOlBeEjPTA4NjvJOqYj0BH87gRSpijQJ8=",
        "X-Forefront-Antispam-Report": "CIP:192.176.1.74; CTRY:SE; LANG:en; SCL:1; SRV:;\n IPV:NLI; SFV:NSPM; H:oa.msg.ericsson.com; PTR:office365.se.ericsson.net;\n CAT:NONE;\n SFS:(13230028)(4636009)(346002)(136003)(39860400002)(396003)(376002)(451199021)(36840700001)(40470700004)(46966006)(82310400005)(2906002)(30864003)(6666004)(82960400001)(6916009)(70206006)(70586007)(54906003)(478600001)(2616005)(336012)(47076005)(40480700001)(66574015)(356005)(7636003)(8676002)(8936002)(36756003)(82740400003)(40460700003)(316002)(4326008)(41300700001)(5660300002)(86362001)(83380400001)(1076003)(26005)(6266002)(107886003)(186003)(36860700001);\n DIR:OUT; SFP:1101;",
        "X-OriginatorOrg": "ericsson.com",
        "X-MS-Exchange-CrossTenant-OriginalArrivalTime": "22 May 2023 09:23:04.3599 (UTC)",
        "X-MS-Exchange-CrossTenant-Network-Message-Id": "\n 900a726c-4b76-4678-8231-08db5aa6258e",
        "X-MS-Exchange-CrossTenant-Id": "92e84ceb-fbfd-47ab-be52-080c6b87953f",
        "X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp": "\n TenantId=92e84ceb-fbfd-47ab-be52-080c6b87953f; Ip=[192.176.1.74];\n Helo=[oa.msg.ericsson.com]",
        "X-MS-Exchange-CrossTenant-AuthSource": "\n AM0EUR02FT016.eop-EUR02.prod.protection.outlook.com",
        "X-MS-Exchange-CrossTenant-AuthAs": "Anonymous",
        "X-MS-Exchange-CrossTenant-FromEntityHeader": "HybridOnPrem",
        "X-MS-Exchange-Transport-CrossTenantHeadersStamped": "AM8PR07MB7396",
        "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": "The purpose of the event dispatcher is to help reduce coupling in an\nEventdev-based DPDK application.\n\nIn addition, the event dispatcher also provides a convenient and\nflexible way for the application to use service cores for\napplication-level processing.\n\nSigned-off-by: Mattias Rönnblom <mattias.ronnblom@ericsson.com>\n---\n lib/eventdev/meson.build            |   2 +\n lib/eventdev/rte_event_dispatcher.c | 670 ++++++++++++++++++++++++++++\n lib/eventdev/rte_event_dispatcher.h | 440 ++++++++++++++++++\n lib/eventdev/version.map            |  12 +\n 4 files changed, 1124 insertions(+)\n create mode 100644 lib/eventdev/rte_event_dispatcher.c\n create mode 100644 lib/eventdev/rte_event_dispatcher.h",
    "diff": "diff --git a/lib/eventdev/meson.build b/lib/eventdev/meson.build\nindex 6edf98dfa5..c0edc744fe 100644\n--- a/lib/eventdev/meson.build\n+++ b/lib/eventdev/meson.build\n@@ -19,6 +19,7 @@ sources = files(\n         'rte_event_crypto_adapter.c',\n         'rte_event_eth_rx_adapter.c',\n         'rte_event_eth_tx_adapter.c',\n+        'rte_event_dispatcher.c',\n         'rte_event_ring.c',\n         'rte_event_timer_adapter.c',\n         'rte_eventdev.c',\n@@ -27,6 +28,7 @@ headers = files(\n         'rte_event_crypto_adapter.h',\n         'rte_event_eth_rx_adapter.h',\n         'rte_event_eth_tx_adapter.h',\n+        'rte_event_dispatcher.h',\n         'rte_event_ring.h',\n         'rte_event_timer_adapter.h',\n         'rte_eventdev.h',\ndiff --git a/lib/eventdev/rte_event_dispatcher.c b/lib/eventdev/rte_event_dispatcher.c\nnew file mode 100644\nindex 0000000000..591efeef80\n--- /dev/null\n+++ b/lib/eventdev/rte_event_dispatcher.c\n@@ -0,0 +1,670 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2023 Ericsson AB\n+ */\n+\n+#include <stdbool.h>\n+#include <stdint.h>\n+\n+#include <rte_branch_prediction.h>\n+#include <rte_lcore.h>\n+#include <rte_service_component.h>\n+\n+#include \"eventdev_pmd.h\"\n+\n+#include <rte_event_dispatcher.h>\n+\n+#define RED_MAX_PORTS_PER_LCORE (4)\n+#define RED_MAX_HANDLERS (32)\n+#define RED_MAX_FINALIZERS (16)\n+\n+struct rte_event_dispatcher_lcore_port {\n+\tuint8_t port_id;\n+\tuint16_t batch_size;\n+\tuint64_t timeout;\n+};\n+\n+struct rte_event_dispatcher_lcore {\n+\tuint8_t num_ports;\n+\tstruct rte_event_dispatcher_lcore_port ports[RED_MAX_PORTS_PER_LCORE];\n+\tstruct rte_event_dispatcher_stats stats;\n+} __rte_cache_aligned;\n+\n+struct rte_event_dispatcher_handler {\n+\tint id;\n+\trte_event_dispatcher_match_t match_fun;\n+\tvoid *match_data;\n+\trte_event_dispatcher_process_t process_fun;\n+\tvoid *process_data;\n+};\n+\n+struct rte_event_dispatcher_finalizer {\n+\tint id;\n+\trte_event_dispatcher_finalize_t finalize_fun;\n+\tvoid *finalize_data;\n+};\n+\n+struct rte_event_dispatcher {\n+\tuint8_t id;\n+\tuint8_t event_dev_id;\n+\tint socket_id;\n+\tuint32_t service_id;\n+\tstruct rte_event_dispatcher_lcore lcores[RTE_MAX_LCORE];\n+\tuint16_t num_handlers;\n+\tuint16_t num_finalizers;\n+\tstruct rte_event_dispatcher_handler handlers[RED_MAX_HANDLERS];\n+\tstruct rte_event_dispatcher_finalizer finalizers[RED_MAX_FINALIZERS];\n+};\n+\n+static struct rte_event_dispatcher *dispatchers[UINT8_MAX];\n+\n+static bool\n+red_has_dispatcher(uint8_t id)\n+{\n+\treturn dispatchers[id] != NULL;\n+}\n+\n+static struct rte_event_dispatcher *\n+red_get_dispatcher(uint8_t id)\n+{\n+\treturn dispatchers[id];\n+}\n+\n+static void\n+red_set_dispatcher(uint8_t id, struct rte_event_dispatcher *dispatcher)\n+{\n+\tdispatchers[id] = dispatcher;\n+}\n+\n+#define RED_VALID_ID_OR_RET_EINVAL(id)\t\t\t\t\t\\\n+\tdo {\t\t\t\t\t\t\t\t\\\n+\t\tif (unlikely(!red_has_dispatcher(id))) {\t\t\\\n+\t\t\tRTE_EDEV_LOG_ERR(\"Invalid dispatcher id %d\\n\", id); \\\n+\t\t\treturn -EINVAL;\t\t\t\t\t\\\n+\t\t}\t\t\t\t\t\t\t\\\n+\t} while (0)\n+\n+static int\n+red_lookup_handler_idx(struct rte_event_dispatcher *dispatcher,\n+\t\t\tconst struct rte_event *event)\n+{\n+\tuint16_t i;\n+\n+\tfor (i = 0; i < dispatcher->num_handlers; i++) {\n+\t\tstruct rte_event_dispatcher_handler *handler =\n+\t\t\t&dispatcher->handlers[i];\n+\n+\t\tif (handler->match_fun(event, handler->match_data))\n+\t\t\treturn i;\n+\t}\n+\n+\treturn -1;\n+}\n+\n+static inline void\n+red_dispatch_events(struct rte_event_dispatcher *dispatcher,\n+\t\t    struct rte_event_dispatcher_lcore *lcore,\n+\t\t    struct rte_event_dispatcher_lcore_port *port,\n+\t\t    struct rte_event *events, uint16_t num_events)\n+{\n+\tint i;\n+\tstruct rte_event bursts[RED_MAX_HANDLERS][num_events];\n+\tuint16_t burst_lens[RED_MAX_HANDLERS] = { 0 };\n+\tuint16_t drop_count = 0;\n+\tuint16_t dispatch_count;\n+\n+\tfor (i = 0; i < num_events; i++) {\n+\t\tstruct rte_event *event = &events[i];\n+\t\tint handler_idx;\n+\n+\t\thandler_idx = red_lookup_handler_idx(dispatcher, event);\n+\n+\t\tif (unlikely(handler_idx < 0)) {\n+\t\t\tdrop_count++;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tbursts[handler_idx][burst_lens[handler_idx]] = *event;\n+\t\tburst_lens[handler_idx]++;\n+\t}\n+\n+\tfor (i = 0; i < dispatcher->num_handlers; i++) {\n+\t\tstruct rte_event_dispatcher_handler *handler =\n+\t\t\t&dispatcher->handlers[i];\n+\t\tuint16_t len = burst_lens[i];\n+\n+\t\tif (len == 0)\n+\t\t\tcontinue;\n+\n+\t\thandler->process_fun(dispatcher->event_dev_id, port->port_id,\n+\t\t\t\t      bursts[i], len, handler->process_data);\n+\t}\n+\n+\tdispatch_count = num_events - drop_count;\n+\n+\tlcore->stats.ev_dispatch_count += dispatch_count;\n+\tlcore->stats.ev_drop_count += drop_count;\n+\n+\tfor (i = 0; i < dispatcher->num_finalizers; i++) {\n+\t\tstruct rte_event_dispatcher_finalizer *finalizer =\n+\t\t\t&dispatcher->finalizers[i];\n+\n+\t\tfinalizer->finalize_fun(dispatcher->event_dev_id,\n+\t\t\t\t\tport->port_id,\n+\t\t\t\t\tfinalizer->finalize_data);\n+\t}\n+}\n+\n+static __rte_always_inline void\n+red_port_dequeue(struct rte_event_dispatcher *dispatcher,\n+\t\t struct rte_event_dispatcher_lcore *lcore,\n+\t\t struct rte_event_dispatcher_lcore_port *port)\n+{\n+\tuint16_t batch_size = port->batch_size;\n+\tstruct rte_event events[batch_size];\n+\tuint16_t n;\n+\n+\tn = rte_event_dequeue_burst(dispatcher->event_dev_id, port->port_id,\n+\t\t\t\t    events, batch_size, port->timeout);\n+\n+\tif (likely(n > 0))\n+\t\tred_dispatch_events(dispatcher, lcore, port, events, n);\n+\n+\tlcore->stats.poll_count++;\n+}\n+\n+static __rte_always_inline void\n+red_lcore_process(struct rte_event_dispatcher *dispatcher,\n+\t\t  struct rte_event_dispatcher_lcore *lcore)\n+{\n+\tuint16_t i;\n+\n+\tfor (i = 0; i < lcore->num_ports; i++) {\n+\t\tstruct rte_event_dispatcher_lcore_port *port =\n+\t\t\t&lcore->ports[i];\n+\n+\t\tred_port_dequeue(dispatcher, lcore, port);\n+\t}\n+}\n+\n+static int32_t\n+red_process(void *userdata)\n+{\n+\tstruct rte_event_dispatcher *dispatcher = userdata;\n+\tunsigned int lcore_id = rte_lcore_id();\n+\tstruct rte_event_dispatcher_lcore *lcore =\n+\t\t&dispatcher->lcores[lcore_id];\n+\n+\tint i;\n+\tfor (i = 0; i < 15; i++)\n+\t\tred_lcore_process(dispatcher, lcore);\n+\n+\treturn 0;\n+}\n+\n+static int\n+red_service_register(struct rte_event_dispatcher *dispatcher)\n+{\n+\tstruct rte_service_spec service = {\n+\t\t.callback = red_process,\n+\t\t.callback_userdata = dispatcher,\n+\t\t.capabilities = RTE_SERVICE_CAP_MT_SAFE,\n+\t\t.socket_id = dispatcher->socket_id\n+\t};\n+\tint rc;\n+\n+\tsnprintf(service.name, RTE_SERVICE_NAME_MAX - 1, \"red_%d\",\n+\t\t dispatcher->id);\n+\n+\trc = rte_service_component_register(&service, &dispatcher->service_id);\n+\n+\tif (rc)\n+\t\tRTE_EDEV_LOG_ERR(\"Registration of event dispatcher service \"\n+\t\t\t\t \"%s failed with error code %d\\n\",\n+\t\t\t\t service.name, rc);\n+\n+\treturn rc;\n+}\n+\n+static int\n+red_service_unregister(struct rte_event_dispatcher *dispatcher)\n+{\n+\tint rc;\n+\n+\trc = rte_service_component_unregister(dispatcher->service_id);\n+\n+\tif (rc)\n+\t\tRTE_EDEV_LOG_ERR(\"Unregistration of event dispatcher service \"\n+\t\t\t\t \"failed with error code %d\\n\", rc);\n+\n+\treturn rc;\n+}\n+\n+int\n+rte_event_dispatcher_create(uint8_t id, uint8_t event_dev_id)\n+{\n+\tint socket_id;\n+\tstruct rte_event_dispatcher *dispatcher;\n+\tint rc;\n+\n+\tif (red_has_dispatcher(id)) {\n+\t\tRTE_EDEV_LOG_ERR(\"Dispatcher with id %d already exists\\n\",\n+\t\t\t\t id);\n+\t\treturn -EEXIST;\n+\t}\n+\n+\tsocket_id = rte_event_dev_socket_id(event_dev_id);\n+\n+\tdispatcher =\n+\t\trte_malloc_socket(\"event dispatcher\",\n+\t\t\t\t  sizeof(struct rte_event_dispatcher),\n+\t\t\t\t  RTE_CACHE_LINE_SIZE, socket_id);\n+\n+\tif (dispatcher == NULL) {\n+\t\tRTE_EDEV_LOG_ERR(\"Unable to allocate memory for event \"\n+\t\t\t\t \"dispatcher\\n\");\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\t*dispatcher = (struct rte_event_dispatcher) {\n+\t\t.id = id,\n+\t\t.event_dev_id = event_dev_id,\n+\t\t.socket_id = socket_id\n+\t};\n+\n+\trc = red_service_register(dispatcher);\n+\n+\tif (rc < 0) {\n+\t\trte_free(dispatcher);\n+\t\treturn rc;\n+\t}\n+\n+\tred_set_dispatcher(id, dispatcher);\n+\n+\treturn 0;\n+}\n+\n+int\n+rte_event_dispatcher_free(uint8_t id)\n+{\n+\tstruct rte_event_dispatcher *dispatcher;\n+\tint rc;\n+\n+\tRED_VALID_ID_OR_RET_EINVAL(id);\n+\tdispatcher = red_get_dispatcher(id);\n+\n+\trc = red_service_unregister(dispatcher);\n+\n+\tif (rc)\n+\t\treturn rc;\n+\n+\tred_set_dispatcher(id, NULL);\n+\n+\trte_free(dispatcher);\n+\n+\treturn 0;\n+}\n+\n+int\n+rte_event_dispatcher_service_id_get(uint8_t id, uint32_t *service_id)\n+{\n+\tstruct rte_event_dispatcher *dispatcher;\n+\n+\tRED_VALID_ID_OR_RET_EINVAL(id);\n+\tdispatcher = red_get_dispatcher(id);\n+\n+\t*service_id = dispatcher->service_id;\n+\n+\treturn 0;\n+}\n+\n+static int\n+lcore_port_index(struct rte_event_dispatcher_lcore *lcore,\n+\t\t uint8_t event_port_id)\n+{\n+\tuint16_t i;\n+\n+\tfor (i = 0; i < lcore->num_ports; i++) {\n+\t\tstruct rte_event_dispatcher_lcore_port *port =\n+\t\t\t&lcore->ports[i];\n+\n+\t\tif (port->port_id == event_port_id)\n+\t\t\treturn i;\n+\t}\n+\n+\treturn -1;\n+}\n+\n+int\n+rte_event_dispatcher_bind_port_to_lcore(uint8_t id, uint8_t event_port_id,\n+\t\t\t\t\tuint16_t batch_size, uint64_t timeout,\n+\t\t\t\t\tunsigned int lcore_id)\n+{\n+\tstruct rte_event_dispatcher *dispatcher;\n+\tstruct rte_event_dispatcher_lcore *lcore;\n+\tstruct rte_event_dispatcher_lcore_port *port;\n+\n+\tRED_VALID_ID_OR_RET_EINVAL(id);\n+\tdispatcher = red_get_dispatcher(id);\n+\n+\tlcore =\t&dispatcher->lcores[lcore_id];\n+\n+\tif (lcore->num_ports == RED_MAX_PORTS_PER_LCORE)\n+\t\treturn -ENOMEM;\n+\n+\tif (lcore_port_index(lcore, event_port_id) >= 0)\n+\t\treturn -EEXIST;\n+\n+\tport = &lcore->ports[lcore->num_ports];\n+\n+\t*port = (struct rte_event_dispatcher_lcore_port) {\n+\t\t.port_id = event_port_id,\n+\t\t.batch_size = batch_size,\n+\t\t.timeout = timeout\n+\t};\n+\n+\tlcore->num_ports++;\n+\n+\treturn 0;\n+}\n+\n+int\n+rte_event_dispatcher_unbind_port_from_lcore(uint8_t id, uint8_t event_port_id,\n+\t\t\t\t\t    unsigned int lcore_id)\n+{\n+\tstruct rte_event_dispatcher *dispatcher;\n+\tstruct rte_event_dispatcher_lcore *lcore;\n+\tint port_idx;\n+\tstruct rte_event_dispatcher_lcore_port *port;\n+\tstruct rte_event_dispatcher_lcore_port *last;\n+\n+\tRED_VALID_ID_OR_RET_EINVAL(id);\n+\tdispatcher = red_get_dispatcher(id);\n+\n+\tlcore =\t&dispatcher->lcores[lcore_id];\n+\n+\tport_idx = lcore_port_index(lcore, event_port_id);\n+\n+\tif (port_idx < 0)\n+\t\treturn -ENOENT;\n+\n+\tport = &lcore->ports[port_idx];\n+\tlast = &lcore->ports[lcore->num_ports - 1];\n+\n+\tif (port != last)\n+\t\t*port = *last;\n+\n+\tlcore->num_ports--;\n+\n+\treturn 0;\n+}\n+\n+static struct rte_event_dispatcher_handler*\n+red_get_handler_by_id(struct rte_event_dispatcher *dispatcher,\n+\t\t       int handler_id)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < dispatcher->num_handlers; i++) {\n+\t\tstruct rte_event_dispatcher_handler *handler =\n+\t\t\t&dispatcher->handlers[i];\n+\n+\t\tif (handler->id == handler_id)\n+\t\t\treturn handler;\n+\t}\n+\n+\treturn NULL;\n+}\n+\n+static int\n+red_alloc_handler_id(struct rte_event_dispatcher *dispatcher)\n+{\n+\tint handler_id = 0;\n+\n+\twhile (red_get_handler_by_id(dispatcher, handler_id) != NULL)\n+\t\thandler_id++;\n+\n+\treturn handler_id;\n+}\n+\n+static struct rte_event_dispatcher_handler *\n+red_alloc_handler(struct rte_event_dispatcher *dispatcher)\n+{\n+\tint handler_idx;\n+\tstruct rte_event_dispatcher_handler *handler;\n+\n+\tif (dispatcher->num_handlers == RED_MAX_HANDLERS)\n+\t\treturn NULL;\n+\n+\thandler_idx = dispatcher->num_handlers;\n+\thandler = &dispatcher->handlers[handler_idx];\n+\n+\thandler->id = red_alloc_handler_id(dispatcher);\n+\n+\tdispatcher->num_handlers++;\n+\n+\treturn handler;\n+}\n+\n+int\n+rte_event_dispatcher_register(uint8_t id,\n+\t\t\t      rte_event_dispatcher_match_t match_fun,\n+\t\t\t      void *match_data,\n+\t\t\t      rte_event_dispatcher_process_t process_fun,\n+\t\t\t      void *process_data)\n+{\n+\tstruct rte_event_dispatcher *dispatcher;\n+\tstruct rte_event_dispatcher_handler *handler;\n+\n+\tRED_VALID_ID_OR_RET_EINVAL(id);\n+\tdispatcher = red_get_dispatcher(id);\n+\n+\thandler = red_alloc_handler(dispatcher);\n+\n+\tif (handler == NULL)\n+\t\treturn -ENOMEM;\n+\n+\thandler->match_fun = match_fun;\n+\thandler->match_data = match_data;\n+\thandler->process_fun = process_fun;\n+\thandler->process_data = process_data;\n+\n+\treturn handler->id;\n+}\n+\n+int\n+rte_event_dispatcher_unregister(uint8_t id, int handler_id)\n+{\n+\tstruct rte_event_dispatcher *dispatcher;\n+\tstruct rte_event_dispatcher_handler *unreg_handler;\n+\tint handler_idx;\n+\tuint16_t last_idx;\n+\n+\tRED_VALID_ID_OR_RET_EINVAL(id);\n+\tdispatcher = red_get_dispatcher(id);\n+\n+\tunreg_handler = red_get_handler_by_id(dispatcher, handler_id);\n+\n+\tif (unreg_handler == NULL)\n+\t\treturn -EINVAL;\n+\n+\thandler_idx = &dispatcher->handlers[0] - unreg_handler;\n+\n+\tlast_idx = dispatcher->num_handlers - 1;\n+\n+\tif (handler_idx != last_idx) {\n+\t\t/* move all handlers to maintain handler order */\n+\t\tint n = last_idx - handler_idx;\n+\t\tmemmove(unreg_handler, unreg_handler + 1,\n+\t\t\tsizeof(struct rte_event_dispatcher_handler) * n);\n+\t}\n+\n+\tdispatcher->num_handlers--;\n+\n+\treturn 0;\n+}\n+\n+static struct rte_event_dispatcher_finalizer*\n+red_get_finalizer_by_id(struct rte_event_dispatcher *dispatcher,\n+\t\t       int handler_id)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < dispatcher->num_finalizers; i++) {\n+\t\tstruct rte_event_dispatcher_finalizer *finalizer =\n+\t\t\t&dispatcher->finalizers[i];\n+\n+\t\tif (finalizer->id == handler_id)\n+\t\t\treturn finalizer;\n+\t}\n+\n+\treturn NULL;\n+}\n+\n+static int\n+red_alloc_finalizer_id(struct rte_event_dispatcher *dispatcher)\n+{\n+\tint finalizer_id = 0;\n+\n+\twhile (red_get_finalizer_by_id(dispatcher, finalizer_id) != NULL)\n+\t\tfinalizer_id++;\n+\n+\treturn finalizer_id;\n+}\n+\n+static struct rte_event_dispatcher_finalizer *\n+red_alloc_finalizer(struct rte_event_dispatcher *dispatcher)\n+{\n+\tint finalizer_idx;\n+\tstruct rte_event_dispatcher_finalizer *finalizer;\n+\n+\tif (dispatcher->num_finalizers == RED_MAX_FINALIZERS)\n+\t\treturn NULL;\n+\n+\tfinalizer_idx = dispatcher->num_finalizers;\n+\tfinalizer = &dispatcher->finalizers[finalizer_idx];\n+\n+\tfinalizer->id = red_alloc_finalizer_id(dispatcher);\n+\n+\tdispatcher->num_finalizers++;\n+\n+\treturn finalizer;\n+}\n+\n+int\n+rte_event_dispatcher_finalize_register(uint8_t id,\n+\t\t\t      rte_event_dispatcher_finalize_t finalize_fun,\n+\t\t\t      void *finalize_data)\n+{\n+\tstruct rte_event_dispatcher *dispatcher;\n+\tstruct rte_event_dispatcher_finalizer *finalizer;\n+\n+\tRED_VALID_ID_OR_RET_EINVAL(id);\n+\tdispatcher = red_get_dispatcher(id);\n+\n+\tfinalizer = red_alloc_finalizer(dispatcher);\n+\n+\tif (finalizer == NULL)\n+\t\treturn -ENOMEM;\n+\n+\tfinalizer->finalize_fun = finalize_fun;\n+\tfinalizer->finalize_data = finalize_data;\n+\n+\treturn finalizer->id;\n+}\n+\n+int\n+rte_event_dispatcher_finalize_unregister(uint8_t id, int handler_id)\n+{\n+\tstruct rte_event_dispatcher *dispatcher;\n+\tstruct rte_event_dispatcher_finalizer *unreg_finalizer;\n+\tint handler_idx;\n+\tuint16_t last_idx;\n+\n+\tRED_VALID_ID_OR_RET_EINVAL(id);\n+\tdispatcher = red_get_dispatcher(id);\n+\n+\tunreg_finalizer = red_get_finalizer_by_id(dispatcher, handler_id);\n+\n+\tif (unreg_finalizer == NULL)\n+\t\treturn -EINVAL;\n+\n+\thandler_idx = &dispatcher->finalizers[0] - unreg_finalizer;\n+\n+\tlast_idx = dispatcher->num_finalizers - 1;\n+\n+\tif (handler_idx != last_idx) {\n+\t\t/* move all finalizers to maintain finalizer order */\n+\t\tint n = last_idx - handler_idx;\n+\t\tmemmove(unreg_finalizer, unreg_finalizer + 1,\n+\t\t\tsizeof(struct rte_event_dispatcher_finalizer) * n);\n+\t}\n+\n+\tdispatcher->num_finalizers--;\n+\n+\treturn 0;\n+}\n+\n+static void\n+red_aggregate_stats(struct rte_event_dispatcher_stats *result,\n+\t\t    const struct rte_event_dispatcher_stats *part)\n+{\n+\tresult->poll_count += part->poll_count;\n+\tresult->ev_dispatch_count += part->ev_dispatch_count;\n+\tresult->ev_drop_count += part->ev_drop_count;\n+}\n+\n+int\n+rte_event_dispatcher_stats_get(uint8_t id,\n+\t\t\t       struct rte_event_dispatcher_stats *stats)\n+{\n+\tstruct rte_event_dispatcher *dispatcher;\n+\tunsigned int lcore_id;\n+\n+\tRED_VALID_ID_OR_RET_EINVAL(id);\n+\tdispatcher = red_get_dispatcher(id);\n+\n+\t*stats = (struct rte_event_dispatcher_stats) {};\n+\n+\tfor (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {\n+\t\tstruct rte_event_dispatcher_lcore *lcore =\n+\t\t\t&dispatcher->lcores[lcore_id];\n+\n+\t\tred_aggregate_stats(stats, &lcore->stats);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+red_set_service_runstate(uint8_t id, int state)\n+{\n+\tstruct rte_event_dispatcher *dispatcher;\n+\tint rc;\n+\n+\tRED_VALID_ID_OR_RET_EINVAL(id);\n+\tdispatcher = red_get_dispatcher(id);\n+\n+\trc = rte_service_component_runstate_set(dispatcher->service_id,\n+\t\t\t\t\t\tstate);\n+\n+\tif (rc != 0) {\n+\t\tRTE_EDEV_LOG_ERR(\"Unexpected error %d occurred while setting \"\n+\t\t\t\t \"service component run state to %d\\n\", rc,\n+\t\t\t\t state);\n+\t\tRTE_ASSERT(0);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int\n+rte_event_dispatcher_start(uint8_t id)\n+{\n+\treturn red_set_service_runstate(id, 1);\n+}\n+\n+int\n+rte_event_dispatcher_stop(uint8_t id)\n+{\n+\treturn red_set_service_runstate(id, 0);\n+}\ndiff --git a/lib/eventdev/rte_event_dispatcher.h b/lib/eventdev/rte_event_dispatcher.h\nnew file mode 100644\nindex 0000000000..5563660f31\n--- /dev/null\n+++ b/lib/eventdev/rte_event_dispatcher.h\n@@ -0,0 +1,440 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2023 Ericsson AB\n+ */\n+\n+#ifndef __RTE_EVENT_DISPATCHER_H__\n+#define __RTE_EVENT_DISPATCHER_H__\n+\n+/**\n+ * @file\n+ *\n+ * RTE Event Dispatcher\n+ *\n+ * The purpose of the event dispatcher is to decouple different parts\n+ * of an application (e.g., modules), sharing the same underlying\n+ * event device.\n+ */\n+\n+#ifdef __cplusplus\n+extern \"C\" {\n+#endif\n+\n+#include <rte_eventdev.h>\n+\n+/**\n+ * Function prototype for match callbacks.\n+ *\n+ * Match callbacks are used by an application to decide how to the\n+ * event dispatcher distributes events to different parts of the\n+ * application.\n+ *\n+ * The application is not expected to process the event at the point\n+ * of the match call. Such matters should be deferred to the process\n+ * callback invocation.\n+ *\n+ * The match callback may be used as an opportunity to prefetch data.\n+ *\n+ * @param event\n+ *  Pointer to event\n+ *\n+ * @param cb_data\n+ *  The pointer supplied by the application in\n+ *  rte_event_dispatcher_register().\n+ *\n+ * @return\n+ *   Returns true in case this events should be delivered (via\n+ *   the process callback), and false otherwise.\n+ */\n+typedef bool\n+(*rte_event_dispatcher_match_t)(const struct rte_event *event, void *cb_data);\n+\n+/**\n+ * Function prototype for process callbacks.\n+ *\n+ * The process callbacks are used by the event dispatcher to deliver\n+ * events for processing.\n+ *\n+ * @param event_dev_id\n+ *  The originating event device id.\n+ *\n+ * @param event_port_id\n+ *  The originating event port.\n+ *\n+ * @param events\n+ *  Pointer to an array of events.\n+ *\n+ * @param num\n+ *  The number of events in the @p events array.\n+ *\n+ * @param cb_data\n+ *  The pointer supplied by the application in\n+ *  rte_event_dispatcher_register().\n+ */\n+\n+typedef void\n+(*rte_event_dispatcher_process_t)(uint8_t event_dev_id, uint8_t event_port_id,\n+\t\t\t\t  const struct rte_event *events,\n+\t\t\t\t  uint16_t num, void *cb_data);\n+\n+/**\n+ * Function prototype for finalize callbacks.\n+ *\n+ * Using a finalize callback, the application may ask to be notified when a\n+ * complete batch of events have been delivered to the various process\n+ * callbacks.\n+ *\n+ * @param event_dev_id\n+ *  The originating event device id.\n+ *\n+ * @param event_port_id\n+ *  The originating event port.\n+ *\n+ * @param cb_data\n+ *  The pointer supplied by the application in\n+ *  rte_event_dispatcher_finalize_register().\n+ */\n+\n+typedef void\n+(*rte_event_dispatcher_finalize_t)(uint8_t event_dev_id, uint8_t event_port_id,\n+\t\t\t\t   void *cb_data);\n+\n+/**\n+ * Event dispatcher statistics\n+ */\n+struct rte_event_dispatcher_stats {\n+\tuint64_t poll_count;\n+\t/**< Number of event dequeue calls made toward the event device. */\n+\tuint64_t ev_dispatch_count;\n+\t/**< Number of events dispatched to a handler.*/\n+\tuint64_t ev_drop_count;\n+\t/**< Number of events dropped because no handler was found. */\n+};\n+\n+/**\n+ * Create an event dispatcher with the specified id.\n+ *\n+ * @param id\n+ *  An application-specified, unique (across all event dispatcher\n+ *  instances) identifier.\n+ *\n+ * @param event_dev_id\n+ *  The identifier of the event device from which this event dispatcher\n+ *  will dequeue events.\n+ *\n+ * @return\n+ *   - 0: Success\n+ *   - <0: Error code on failure\n+ */\n+__rte_experimental\n+int\n+rte_event_dispatcher_create(uint8_t id, uint8_t event_dev_id);\n+\n+/**\n+ * Free an event dispatcher.\n+ *\n+ * @param id\n+ *  The event dispatcher identifier.\n+ *\n+ * @return\n+ *  - 0: Success\n+ *  - <0: Error code on failure\n+ */\n+__rte_experimental\n+int\n+rte_event_dispatcher_free(uint8_t id);\n+\n+/**\n+ * Retrieve the service identifier of an event dispatcher.\n+ *\n+ * @param id\n+ *  The event dispatcher identifier.\n+ *\n+ * @param [out] service_id\n+ *  A pointer to a caller-supplied buffer where the event dispatcher's\n+ *  service id will be stored.\n+ *\n+ * @return\n+ *  - 0: Success\n+ *  - <0: Error code on failure.\n+ */\n+__rte_experimental\n+int\n+rte_event_dispatcher_service_id_get(uint8_t id, uint32_t *service_id);\n+\n+/**\n+ * Binds an event device port to a specific lcore on the specified\n+ * event dispatcher.\n+ *\n+ * This function configures the event port id to be used by the event\n+ * dispatcher service, if run on the specified lcore.\n+ *\n+ * Multiple event device ports may be bound to the same lcore. A\n+ * particular port must not be bound to more than one lcore.\n+ *\n+ * If the event dispatcher service is mapped (with\n+ * rte_service_map_lcore_set()) to a lcore for which no ports are\n+ * bound, the service function will be a no-operation.\n+ *\n+ * This function is not MT safe.\n+ *\n+ * @param id\n+ *  The event dispatcher identifier.\n+ *\n+ * @param event_port_id\n+ *  The event device port identifier.\n+ *\n+ * @param batch_size\n+ *  The batch size to use in rte_event_dequeue_burst(), for the\n+ *  configured event device port and lcore.\n+ *\n+ * @param timeout\n+ *  The timeout parameter to use in rte_event_dequeue_burst(), for the\n+ *  configured event device port and lcore.\n+ *\n+ * @param lcore_id\n+ *  The lcore by which this event port will be used.\n+ *\n+ * @return\n+ *  - 0: Success\n+ *  - -ENOMEM: Unable to allocate sufficient resources.\n+ *  - -EEXISTS: Event port is already configured.\n+ *  - -EINVAL: Invalid arguments.\n+ */\n+__rte_experimental\n+int\n+rte_event_dispatcher_bind_port_to_lcore(uint8_t id, uint8_t event_port_id,\n+\t\t\t\t\tuint16_t batch_size, uint64_t timeout,\n+\t\t\t\t\tunsigned int lcore_id);\n+\n+/**\n+ * Unbind an event device port from a specific lcore.\n+ *\n+ * This function is not MT safe.\n+ *\n+ * @param id\n+ *  The event dispatcher identifier.\n+ *\n+ * @param event_port_id\n+ *  The event device port identifier.\n+ *\n+ * @param lcore_id\n+ *  The lcore which was using this event port.\n+ *\n+ * @return\n+ *  - 0: Success\n+ *  - -EINVAL: Invalid @c id.\n+ *  - -ENOENT: Event port id not bound to this @c lcore_id.\n+ */\n+__rte_experimental\n+int\n+rte_event_dispatcher_unbind_port_from_lcore(uint8_t id, uint8_t event_port_id,\n+\t\t\t\t\t    unsigned int lcore_id);\n+\n+/**\n+ * Register an event handler.\n+ *\n+ * The match callback function is used to select if a particular event\n+ * should be delivered, using the corresponding process callback\n+ * function.\n+ *\n+ * The reason for having two distinct steps is to allow the dispatcher\n+ * to deliver all events as a batch. This in turn will cause\n+ * processing of a particular kind of events to happen in a\n+ * back-to-back manner, improving cache locality.\n+ *\n+ * The list of handler callback functions is shared among all lcores,\n+ * but will only be executed on lcores which has an eventdev port\n+ * bound to them, and which are running the dispatcher service.\n+ *\n+ * Ordering of events is not guaranteed to be maintained between\n+ * different deliver callbacks. For example, suppose there are two\n+ * callbacks registered, matching different subsets of events an\n+ * atomic queue. A batch of events [ev0, ev1, ev2] are dequeued on a\n+ * particular port, all pertaining to the same flow. The match\n+ * callback for registration A returns true for ev0 and ev2, and the\n+ * matching function for registration B for ev1. In that scenario, the\n+ * event dispatcher may choose to deliver first [ev0, ev2] using A's\n+ * deliver function, and then [ev1] to B - or vice versa.\n+ *\n+ * rte_event_dispatcher_register() is not MT safe.\n+ *\n+ * @param id\n+ *  The event dispatcher identifier.\n+ *\n+ * @param match_fun\n+ *  The match callback function.\n+ *\n+ * @param match_cb_data\n+ *  A pointer to some application-specific opaque data (or NULL),\n+ *  which is supplied back to the application when match_fun is\n+ *  called.\n+ *\n+ * @param process_fun\n+ *  The process callback function.\n+ *\n+ * @param process_cb_data\n+ *  A pointer to some application-specific opaque data (or NULL),\n+ *  which is supplied back to the application when process_fun is\n+ *  called.\n+ *\n+ * @return\n+ *  - >= 0: The identifier for this registration.\n+ *  - -ENOMEM: Unable to allocate sufficient resources.\n+ */\n+__rte_experimental\n+int\n+rte_event_dispatcher_register(uint8_t id,\n+\t\t\t      rte_event_dispatcher_match_t match_fun,\n+\t\t\t      void *match_cb_data,\n+\t\t\t      rte_event_dispatcher_process_t process_fun,\n+\t\t\t      void *process_cb_data);\n+\n+/**\n+ * Unregister an event handler.\n+ *\n+ * This function is not MT safe.\n+ *\n+ * @param id\n+ *  The event dispatcher identifier.\n+ *\n+ * @param handler_id\n+ *  The handler registration id returned by the original\n+ *  rte_event_dispatcher_register() call.\n+ *\n+ * @return\n+ *  - 0: Success\n+ *  - -EINVAL: The @c id and/or the @c handler_id parameter was invalid.\n+ */\n+__rte_experimental\n+int\n+rte_event_dispatcher_unregister(uint8_t id, int handler_id);\n+\n+/**\n+ * Registers a finalize callback function.\n+ *\n+ * An application may optionally install a finalize callback.\n+ *\n+ * The finalize callback is called when all event of a particular\n+ * batch of events (retrieve using rte_event_dequeue_burst()) have\n+ * been delivered (or dropped).\n+ *\n+ * The finalize callback is not tied to any particular handler.\n+ *\n+ * The finalize callback provides an opportunity for the application\n+ * to do per-batch processing. One case where this may be useful is if\n+ * an event output buffer is used, and is shared among several\n+ * handlers. In such a case, proper output buffer flushing may be\n+ * assured using a finalize callback.\n+ *\n+ * rte_event_dispatcher_finalize_register() is not MT safe.\n+ *\n+ * @param id\n+ *  The event dispatcher identifier.\n+ *\n+ * @param finalize_fun\n+ *  The function called after completing the processing of a\n+ *  dequeue batch.\n+ *\n+ * @param finalize_data\n+ *  A pointer to some application-specific opaque data (or NULL),\n+ *  which is supplied back to the application when @c finalize_fun is\n+ *  called.\n+ *\n+ * @return\n+ *  - >= 0: The identifier for this registration.\n+ *  - -ENOMEM: Unable to allocate sufficient resources.\n+ */\n+__rte_experimental\n+int\n+rte_event_dispatcher_finalize_register(uint8_t id,\n+\t\t\t    rte_event_dispatcher_finalize_t finalize_fun,\n+\t\t\t    void *finalize_data);\n+\n+/**\n+ * Unregister an event handler.\n+ *\n+ * This function is not MT safe.\n+ *\n+ * @param id\n+ *  The event dispatcher identifier.\n+ *\n+ * @param reg_id\n+ *  The finalize registration id returned by the original\n+ *  rte_event_dispatcher_finalize_register() call.\n+ *\n+ * @return\n+ *  - 0: Success\n+ *  - -EINVAL: The @c id and/or the @c reg_id parameter was invalid.\n+ */\n+__rte_experimental\n+int\n+rte_event_dispatcher_finalize_unregister(uint8_t id, int reg_id);\n+\n+/**\n+ * Start an event dispatcher instance.\n+ *\n+ * Enables the event dispatcher service.\n+ *\n+ * The underlying event device must have been started prior to calling\n+ * rte_event_dispatcher_start().\n+ *\n+ * For the event dispatcher to actually perform work (i.e., dispatch\n+ * events), its service must have been mapped to one or more service\n+ * lcores, and its service run state set to '1'. An event dispatcher's\n+ * service is retrieved using rte_event_dispatcher_service_id_get().\n+ *\n+ * Each service lcore to which the event dispatcher is mapped should\n+ * have at least one event port configured. Such configuration is\n+ * performed by calling rte_event_dispatcher_bind_port_to_lcore(),\n+ * prior to starting the event dispatcher.\n+ *\n+ * @param id\n+ *  The event dispatcher identifier.\n+ *\n+ * @return\n+ *  - 0: Success\n+ *  - -EINVAL: Invalid @c id.\n+ */\n+__rte_experimental\n+int\n+rte_event_dispatcher_start(uint8_t id);\n+\n+/**\n+ * Stop a running event dispatcher instance.\n+ *\n+ * Disables the event dispatcher service.\n+ *\n+ * @param id\n+ *  The event dispatcher identifier.\n+ *\n+ * @return\n+ *  - 0: Success\n+ *  - -EINVAL: Invalid @c id.\n+ */\n+__rte_experimental\n+int\n+rte_event_dispatcher_stop(uint8_t id);\n+\n+/**\n+ * Retrieve statistics for an event dispatcher instance.\n+ *\n+ * This function is MT safe and may be called from any thread\n+ * (including unregistered non-EAL threads).\n+ *\n+ * @param id\n+ *  The event dispatcher identifier.\n+ * @param[out] stats\n+ *   A pointer to a structure to fill with statistics.\n+ * @return\n+ *  - 0: Success\n+ *  - -EINVAL: The @c id parameter was invalid.\n+ */\n+int\n+rte_event_dispatcher_stats_get(uint8_t id,\n+\t\t\t       struct rte_event_dispatcher_stats *stats);\n+\n+#ifdef __cplusplus\n+}\n+#endif\n+\n+#endif /* __RTE_EVENT_DISPATCHER__ */\ndiff --git a/lib/eventdev/version.map b/lib/eventdev/version.map\nindex 89068a5713..36466e9f24 100644\n--- a/lib/eventdev/version.map\n+++ b/lib/eventdev/version.map\n@@ -131,6 +131,18 @@ EXPERIMENTAL {\n \trte_event_eth_tx_adapter_runtime_params_init;\n \trte_event_eth_tx_adapter_runtime_params_set;\n \trte_event_timer_remaining_ticks_get;\n+\n+\trte_event_dispatcher_create;\n+\trte_event_dispatcher_free;\n+\trte_event_dispatcher_service_id_get;\n+\trte_event_dispatcher_bind_port_to_lcore;\n+\trte_event_dispatcher_unbind_port_from_lcore;\n+\trte_event_dispatcher_register;\n+\trte_event_dispatcher_unregister;\n+\trte_event_dispatcher_finalize_register;\n+\trte_event_dispatcher_finalize_unregister;\n+\trte_event_dispatcher_start;\n+\trte_event_dispatcher_stop;\n };\n \n INTERNAL {\n",
    "prefixes": [
        "RFC",
        "v3",
        "1/3"
    ]
}