get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 132078,
    "url": "http://patches.dpdk.org/api/patches/132078/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20230928073056.359356-4-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": "<20230928073056.359356-4-mattias.ronnblom@ericsson.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20230928073056.359356-4-mattias.ronnblom@ericsson.com",
    "date": "2023-09-28T07:30:56",
    "name": "[v5,3/3] doc: add dispatcher programming guide",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "dc4808dc211e013453e044f030325fb3eeaf23d2",
    "submitter": {
        "id": 1077,
        "url": "http://patches.dpdk.org/api/people/1077/?format=api",
        "name": "Mattias Rönnblom",
        "email": "mattias.ronnblom@ericsson.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/20230928073056.359356-4-mattias.ronnblom@ericsson.com/mbox/",
    "series": [
        {
            "id": 29667,
            "url": "http://patches.dpdk.org/api/series/29667/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=29667",
            "date": "2023-09-28T07:30:53",
            "name": "Add dispatcher library",
            "version": 5,
            "mbox": "http://patches.dpdk.org/series/29667/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/132078/comments/",
    "check": "fail",
    "checks": "http://patches.dpdk.org/api/patches/132078/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 CEF3E4265D;\n\tThu, 28 Sep 2023 09:36:47 +0200 (CEST)",
            "from mails.dpdk.org (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 3055E406FF;\n\tThu, 28 Sep 2023 09:36:36 +0200 (CEST)",
            "from EUR03-AM7-obe.outbound.protection.outlook.com\n (mail-am7eur03on2053.outbound.protection.outlook.com [40.107.105.53])\n by mails.dpdk.org (Postfix) with ESMTP id 9AF0A402DE;\n Thu, 28 Sep 2023 09:36:29 +0200 (CEST)",
            "from AS9PR04CA0032.eurprd04.prod.outlook.com (2603:10a6:20b:46a::6)\n by DU2PR07MB9523.eurprd07.prod.outlook.com (2603:10a6:10:49c::19)\n with Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6813.28; Thu, 28 Sep\n 2023 07:36:27 +0000",
            "from AM4PEPF00027A6B.eurprd04.prod.outlook.com\n (2603:10a6:20b:46a:cafe::2) by AS9PR04CA0032.outlook.office365.com\n (2603:10a6:20b:46a::6) with Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6838.21 via Frontend\n Transport; Thu, 28 Sep 2023 07:36:27 +0000",
            "from oa.msg.ericsson.com (192.176.1.74) by\n AM4PEPF00027A6B.mail.protection.outlook.com (10.167.16.89) with Microsoft\n SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) id\n 15.20.6838.14 via Frontend Transport; Thu, 28 Sep 2023 07:36:27 +0000",
            "from ESESSMB503.ericsson.se (153.88.183.164) by\n ESESBMB504.ericsson.se (153.88.183.171) with Microsoft SMTP Server\n (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id\n 15.1.2507.32; Thu, 28 Sep 2023 09:36:26 +0200",
            "from seliicinfr00049.seli.gic.ericsson.se (153.88.183.153) by\n smtp.internal.ericsson.com (153.88.183.191) with Microsoft SMTP Server id\n 15.1.2507.32 via Frontend Transport; Thu, 28 Sep 2023 09:36:26 +0200",
            "from breslau.. (seliicwb00002.seli.gic.ericsson.se [10.156.25.100])\n by seliicinfr00049.seli.gic.ericsson.se (Postfix) with ESMTP id\n C7404380061; Thu, 28 Sep 2023 09:36:26 +0200 (CEST)"
        ],
        "ARC-Seal": "i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none;\n b=K71jPLVvCz94RJ+wIAUxt2JxjmTrlwoOZIDwFpDGOHsMbfCnpo2HUgD2vnYlC3iIIZ2BJYs5mWrhnWBCvy5TUnL2+Og0YH8Bivdh7pBKSNYNuHm85C3dp01fgqRh+9GdY9aocg7bF4Kpx1hgzcLbu/gi8pMWmtEJxG0BqasHE5BYiKJqpxW0o3olyOp5dwM7nQT12alYVfBogkScnQ29WWL80yiWIt2uVWe9pdDZUELexRXkYkgiTD0idOsc5U3sWtk7NpbcToAwG8hxRl82+m0Fa0FXaeR+Kp76kR38PHOqH+QqIQHqSkWxKz5WdeAcGTzaoCoMqFjrD8lsp+Fr3w==",
        "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=wxWpKHpVkyLOo5q7Xx/YK5pQQp6Kymgy+iyOOujXfj0=;\n b=iqkvf/jGUcpbJgwoWVlJfzB1W/fQmL+nvptj75F+vc01dqmSxNix3yOb+mvrvo5rE/fQufmlkUEY9H5y2xeNQzENBQeavQses1FdTqrv9dPXbuqKlH/74k22q+D9bFMs+ZSEOLiEGoLS0P7nxgTkZvw1YOUtEO5vlD2pa55WDThVU2NHiO7+r7Bs+Ik05/eWRK6i0SQq/XkBUTHAwx8Fc0TmOshNhY54x5z2RL5cmrshaxy6fWdBYo2+k0xsJBMbnr5dIQabZ+uIoyrcinKLJQBiZ1iQb63vfXmYhK8QJtXLyYJZN5nByfvitfXVAubs2/GnLaEYEIXttCRjxYwWEg==",
        "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=wxWpKHpVkyLOo5q7Xx/YK5pQQp6Kymgy+iyOOujXfj0=;\n b=SOMMmJHGQrPeh0sPREOLF7cH3afGh7xBCntpivMsWTzurwQmWh34nCK+4IuxzZqNG7CqdimAnYHoOfYsUA8I1SG+1f2PjnBrFc6HK00rRdTs8AXUFsqKuCEAHZTrBJSlnKVTboiqqXoV4bXgdX45WyLaUA8kAU/OfQxL1uo9Vfg=",
        "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": "<dev@dpdk.org>",
        "CC": "Jerin Jacob <jerinj@marvell.com>, <techboard@dpdk.org>,\n <harry.van.haaren@intel.com>, <hofors@lysator.liu.se>,\n Peter Nilsson <peter.j.nilsson@ericsson.com>,\n Heng Wang <heng.wang@ericsson.com>,\n \"Naga Harish K S V\" <s.v.naga.harish.k@intel.com>,\n Pavan Nikhilesh <pbhagavatula@marvell.com>,\n Gujjar Abhinandan S <abhinandan.gujjar@intel.com>,\n Erik Gabriel Carrillo <erik.g.carrillo@intel.com>,\n Shijith Thotton <sthotton@marvell.com>,\n \"Hemant Agrawal\" <hemant.agrawal@nxp.com>,\n Sachin Saxena <sachin.saxena@oss.nxp.com>,  Liang Ma <liangma@liangbit.com>,\n Peter Mccarthy <peter.mccarthy@intel.com>, Zhirun Yan <zhirun.yan@intel.com>,\n =?utf-8?q?Mattias_R=C3=B6nnblom?= <mattias.ronnblom@ericsson.com>",
        "Subject": "[PATCH v5 3/3] doc: add dispatcher programming guide",
        "Date": "Thu, 28 Sep 2023 09:30:56 +0200",
        "Message-ID": "<20230928073056.359356-4-mattias.ronnblom@ericsson.com>",
        "X-Mailer": "git-send-email 2.34.1",
        "In-Reply-To": "<20230928073056.359356-1-mattias.ronnblom@ericsson.com>",
        "References": "<20230922073825.351453-2-mattias.ronnblom@ericsson.com>\n <20230928073056.359356-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": "AM4PEPF00027A6B:EE_|DU2PR07MB9523:EE_",
        "X-MS-Office365-Filtering-Correlation-Id": "157918de-5d00-4e62-335d-08dbbff59ff5",
        "X-LD-Processed": "92e84ceb-fbfd-47ab-be52-080c6b87953f,ExtAddr",
        "X-MS-Exchange-SenderADCheck": "1",
        "X-MS-Exchange-AntiSpam-Relay": "0",
        "X-Microsoft-Antispam": "BCL:0;",
        "X-Microsoft-Antispam-Message-Info": "\n tOl1DKU/FTD8ZB7NYz5n34MOfVBzuwDoroZ1ZJm2fFFJdus3hNCg/xymg8NTXH9Sv00MBb5B5NS1gILCL/z071OORBxVGOdz5EuZdhB4oCYaackxJXfeJgwH9h3BWmPz7v4PMitxYji+rEap3mD9IL00br4AmBhWoFLFiZOud/Djl8jnlGCZfuHurK3RGV0wNkjKrYYXJY+Tu/qScEOPD4/wPuGaPvq7OZNV7m4TOfrEumsgNnEAd040RS6Nmt6o0FRe6LjjR5ltG3xL5xQW16sa16dZ10yZsTa/hrzl6mEeH0vH0g8/g04dXZWdK7EC8S+UYUkUGl8qmPNqQS3bbzVVq6CtCh2BrHPAd/p6wAXwaVs1H18npFpNlcJYkK/vouRc8NYngDyufLInTD6WicMM6xT+035XR1plhXdGhts+ltMdQF1W2UKemkHcWUQErQbri8FWCOjVmMl/gDaSPNKo6E2+m3UTzVMIpMiSmeliri3TTz2QZXEkFtT1vS+7WxS6sZ963w59LeKSqzv34LX9F1LD/gjNCFs7nwiNVqMG2EcCBcXtrV+QDo2byp39J1Se8OHfPaQcYJIN963rD+jSnPIrD4Z1frpy/Wgn+KANgYKYAWYgi39uCIkwiP9OboHzjQZ3SB8ryziaf18ifH8MZn4LGT1moKXhWreGlv548G26YLrmiNQpIriWkxG3U+3OMh6+H+lACtMgvWBjhp3O33mxilSRw5dBwGKb8ZYzOheCVQB70CXExcFsYbePh9+pupmg+Sd6CaEG2R/W873otnYzrRjaDOK9zOwvBsY=",
        "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:(13230031)(4636009)(39860400002)(396003)(346002)(376002)(136003)(230922051799003)(1800799009)(82310400011)(186009)(64100799003)(451199024)(36840700001)(40470700004)(46966006)(40460700003)(6666004)(66899024)(7636003)(83380400001)(86362001)(82960400001)(356005)(82740400003)(2616005)(36860700001)(66574015)(47076005)(6266002)(107886003)(1076003)(36756003)(26005)(40480700001)(2906002)(7416002)(41300700001)(316002)(70586007)(70206006)(6916009)(8936002)(478600001)(336012)(54906003)(4326008)(8676002)(5660300002)(30864003);\n DIR:OUT; SFP:1101;",
        "X-OriginatorOrg": "ericsson.com",
        "X-MS-Exchange-CrossTenant-OriginalArrivalTime": "28 Sep 2023 07:36:27.3971 (UTC)",
        "X-MS-Exchange-CrossTenant-Network-Message-Id": "\n 157918de-5d00-4e62-335d-08dbbff59ff5",
        "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 AM4PEPF00027A6B.eurprd04.prod.outlook.com",
        "X-MS-Exchange-CrossTenant-AuthAs": "Anonymous",
        "X-MS-Exchange-CrossTenant-FromEntityHeader": "HybridOnPrem",
        "X-MS-Exchange-Transport-CrossTenantHeadersStamped": "DU2PR07MB9523",
        "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": "Provide programming guide for the dispatcher library.\n\nSigned-off-by: Mattias Rönnblom <mattias.ronnblom@ericsson.com>\n\n--\nPATCH v5:\n o Update guide to match API changes related to dispatcher ids.\n\nPATCH v3:\n o Adapt guide to the dispatcher API name changes.\n\nPATCH:\n o Improve grammar and spelling.\n\nRFC v4:\n o Extend event matching section of the programming guide.\n o Improve grammar and spelling.\n---\n MAINTAINERS                              |   1 +\n doc/guides/prog_guide/dispatcher_lib.rst | 433 +++++++++++++++++++++++\n doc/guides/prog_guide/index.rst          |   1 +\n 3 files changed, 435 insertions(+)\n create mode 100644 doc/guides/prog_guide/dispatcher_lib.rst",
    "diff": "diff --git a/MAINTAINERS b/MAINTAINERS\nindex 43890cad0e..ab35498204 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -1730,6 +1730,7 @@ Dispatcher - EXPERIMENTAL\n M: Mattias Rönnblom <mattias.ronnblom@ericsson.com>\n F: lib/dispatcher/\n F: app/test/test_dispatcher.c\n+F: doc/guides/prog_guide/dispatcher_lib.rst\n \n Test Applications\n -----------------\ndiff --git a/doc/guides/prog_guide/dispatcher_lib.rst b/doc/guides/prog_guide/dispatcher_lib.rst\nnew file mode 100644\nindex 0000000000..951db06081\n--- /dev/null\n+++ b/doc/guides/prog_guide/dispatcher_lib.rst\n@@ -0,0 +1,433 @@\n+..  SPDX-License-Identifier: BSD-3-Clause\n+    Copyright(c) 2023 Ericsson AB.\n+\n+Dispatcher\n+==========\n+\n+Overview\n+--------\n+\n+The purpose of the dispatcher is to help reduce coupling in an\n+:doc:`Eventdev <eventdev>`-based DPDK application.\n+\n+In particular, the dispatcher addresses a scenario where an\n+application's modules share the same event device and event device\n+ports, and performs work on the same lcore threads.\n+\n+The dispatcher replaces the conditional logic that follows an event\n+device dequeue operation, where events are dispatched to different\n+parts of the application, typically based on fields in the\n+``rte_event``, such as the ``queue_id``, ``sub_event_type``, or\n+``sched_type``.\n+\n+Below is an excerpt from a fictitious application consisting of two\n+modules; A and B. In this example, event-to-module routing is based\n+purely on queue id, where module A expects all events to a certain\n+queue id, and module B two other queue ids. [#Mapping]_\n+\n+.. code-block:: c\n+\n+    for (;;) {\n+            struct rte_event events[MAX_BURST];\n+            unsigned int n;\n+    \n+            n = rte_event_dequeue_burst(dev_id, port_id, events,\n+\t                                MAX_BURST, 0);\n+    \n+            for (i = 0; i < n; i++) {\n+                    const struct rte_event *event = &events[i];\n+    \n+                    switch (event->queue_id) {\n+                    case MODULE_A_QUEUE_ID:\n+                            module_a_process(event);\n+                            break;\n+                    case MODULE_B_STAGE_0_QUEUE_ID:\n+                            module_b_process_stage_0(event);\n+                            break;\n+                    case MODULE_B_STAGE_1_QUEUE_ID:\n+                            module_b_process_stage_1(event);\n+                            break;\n+                    }\n+            }\n+    }\n+\n+The issue this example attempts to illustrate is that the centralized\n+conditional logic has knowledge of things that should be private to\n+the modules. In other words, this pattern leads to a violation of\n+module encapsulation.\n+\n+The shared conditional logic contains explicit knowledge about what\n+events should go where. In case, for example, the\n+``module_a_process()`` is broken into two processing stages — a\n+module-internal affair — the shared conditional code must be updated\n+to reflect this change.\n+\n+The centralized event routing code becomes an issue in larger\n+applications, where modules are developed by different organizations.\n+This pattern also makes module reuse across different application more\n+difficult. The part of the conditional logic relevant for a particular\n+application may need to be duplicated across many module\n+instantiations (e.g., applications and test setups).\n+\n+The dispatcher separates the mechanism (routing events to their\n+receiver) from the policy (which events should go where).\n+\n+The basic operation of the dispatcher is as follows:\n+\n+* Dequeue a batch of events from the event device.\n+* For each event determine which handler should receive the event, using\n+  a set of application-provided, per-handler event matching callback\n+  functions.\n+* Provide events matching a particular handler, to that handler, using\n+  its process callback.\n+\n+If the above application would have made use of the dispatcher, the\n+code relevant for its module A may have looked something like this:\n+\n+.. code-block:: c\n+\n+    static bool\n+    module_a_match(const struct rte_event *event, void *cb_data)\n+    {\n+           return event->queue_id == MODULE_A_QUEUE_ID;\n+    }\n+    \n+    static void\n+    module_a_process_events(uint8_t event_dev_id, uint8_t event_port_id,\n+                            const struct rte_event *events,\n+\t\t\t    uint16_t num, void *cb_data)\n+    {\n+            uint16_t i;\n+\n+            for (i = 0; i < num; i++)\n+                    module_a_process_event(&events[i]);\n+    }\n+    \n+    /* In the module's initialization code */\n+    rte_dispatcher_register(dispatcher, module_a_match, NULL,\n+\t\t\t    module_a_process_events, module_a_data);\n+\n+(Error handling is left out of this and future example code in this\n+chapter.)\n+\n+When the shared conditional logic is removed, a new question arise:\n+which part of the system actually runs the dispatching mechanism? Or\n+phrased differently, what is replacing the function hosting the shared\n+conditional logic (typically launched on all lcores using\n+``rte_eal_remote_launch()``)? To solve this issue, the dispatcher is a\n+run as a DPDK :doc:`Service <service_cores>`.\n+\n+The dispatcher is a layer between the application and the event device\n+in the receive direction. In the transmit (i.e., item of work\n+submission) direction, the application directly accesses the Eventdev\n+core API (e.g., ``rte_event_enqueue_burst()``) to submit new or\n+forwarded event to the event device.\n+\n+Dispatcher Creation\n+-------------------\n+\n+A dispatcher is created with using\n+``rte_dispatcher_create()``.\n+\n+The event device must be configured before the dispatcher is created.\n+\n+Usually, only one dispatcher is needed per event device. A dispatcher\n+handles exactly one event device.\n+\n+An dispatcher is freed using the ``rte_dispatcher_free()``\n+function. The dispatcher's service functions must not be running on\n+any lcore at the point of this call.\n+\n+Event Port Binding\n+------------------\n+\n+To be able to dequeue events, the dispatcher must know which event\n+ports are to be used, on all the lcores it uses. The application\n+provides this information using\n+``rte_dispatcher_bind_port_to_lcore()``.\n+\n+This call is typically made from the part of the application that\n+deals with deployment issues (e.g., iterating lcores and determining\n+which lcore does what), at the time of application initialization.\n+\n+The ``rte_dispatcher_unbind_port_from_lcore()`` is used to undo\n+this operation.\n+\n+Multiple lcore threads may not safely use the same event\n+port. [#Port-MT-Safety]\n+\n+Event ports cannot safely be bound or unbound while the dispatcher's\n+service function is running on any lcore.\n+\n+Event Handlers\n+--------------\n+\n+The dispatcher handler is an interface between the dispatcher and an\n+application module, used to route events to the appropriate part of\n+the application.\n+\n+Handler Registration\n+^^^^^^^^^^^^^^^^^^^^\n+\n+The event handler interface consists of two function pointers:\n+\n+* The ``rte_dispatcher_match_t`` callback, which job is to\n+  decide if this event is to be the property of this handler.\n+* The ``rte_dispatcher_process_t``, which is used by the\n+  dispatcher to deliver matched events.\n+\n+An event handler registration is valid on all lcores.\n+\n+The functions pointed to by the match and process callbacks resides in\n+the application's domain logic, with one or more handlers per\n+application module.\n+\n+A module may use more than one event handler, for convenience or to\n+further decouple sub-modules. However, the dispatcher may impose an\n+upper limit of the number handlers. In addition, installing a large\n+number of handlers increase dispatcher overhead, although this does\n+not nessarily translate to a system-level performance degradation. See\n+the section on :ref:`Event Clustering` for more information.\n+\n+Handler registration and unregistration cannot safely be done while\n+the dispatcher's service function is running on any lcore.\n+\n+Event Matching\n+^^^^^^^^^^^^^^\n+\n+A handler's match callback function decides if an event should be\n+delivered to this handler, or not.\n+\n+An event is routed to no more than one handler. Thus, if a match\n+function returns true, no further match functions will be invoked for\n+that event.\n+\n+Match functions must not depend on being invocated in any particular\n+order (e.g., in the handler registration order).\n+\n+Events failing to match any handler are dropped, and the\n+``ev_drop_count`` counter is updated accordingly.\n+\n+Event Delivery\n+^^^^^^^^^^^^^^\n+\n+The handler callbacks are invocated by the dispatcher's service\n+function, upon the arrival of events to the event ports bound to the\n+running service lcore.\n+\n+A particular event is delivery to at most one handler.\n+\n+The application must not depend on all match callback invocations for\n+a particular event batch being made prior to any process calls are\n+being made. For example, if the dispatcher dequeues two events from\n+the event device, it may choose to find out the destination for the\n+first event, and deliver it, and then continue to find out the\n+destination for the second, and then deliver that event as well. The\n+dispatcher may also choose a strategy where no event is delivered\n+until the destination handler for both events have been determined.\n+\n+The events provided in a single process call always belong to the same\n+event port dequeue burst.\n+\n+.. _Event Clustering:\n+\n+Event Clustering\n+^^^^^^^^^^^^^^^^\n+\n+The dispatcher maintains the order of events destined for the same\n+handler.\n+\n+*Order* here refers to the order in which the events were delivered\n+from the event device to the dispatcher (i.e., in the event array\n+populated by ``rte_event_dequeue_burst()``), in relation to the order\n+in which the dispatcher deliveres these events to the application.\n+\n+The dispatcher *does not* guarantee to maintain the order of events\n+delivered to *different* handlers.\n+\n+For example, assume that ``MODULE_A_QUEUE_ID`` expands to the value 0,\n+and ``MODULE_B_STAGE_0_QUEUE_ID`` expands to the value 1. Then\n+consider a scenario where the following events are dequeued from the\n+event device (qid is short for event queue id).\n+\n+.. code-block::\n+\n+    [e0: qid=1], [e1: qid=1], [e2: qid=0], [e3: qid=1]\n+\n+The dispatcher may deliver the events in the following manner:\n+\n+.. code-block::\n+\n+   module_b_stage_0_process([e0: qid=1], [e1: qid=1])\n+   module_a_process([e2: qid=0])\n+   module_b_stage_0_process([e2: qid=1])\n+\n+The dispatcher may also choose to cluster (group) all events destined\n+for ``module_b_stage_0_process()`` into one array:\n+\n+.. code-block::\n+\n+   module_b_stage_0_process([e0: qid=1], [e1: qid=1], [e3: qid=1])\n+   module_a_process([e2: qid=0])\n+\n+Here, the event ``e2`` is reordered and placed behind ``e3``, from a\n+delivery order point of view. This kind of reshuffling is allowed,\n+since the events are destined for different handlers.\n+\n+The dispatcher may also deliver ``e2`` before the three events\n+destined for module B.\n+\n+An example of what the dispatcher may not do, is to reorder event\n+``e1`` so, that it precedes ``e0`` in the array passed to the module\n+B's stage 0 process callback.\n+\n+Although clustering requires some extra work for the dispatcher, it\n+leads to fewer process function calls. In addition, and likely more\n+importantly, it improves temporal locality of memory accesses to\n+handler-specific data structures in the application, which in turn may\n+lead to fewer cache misses and improved overall performance.\n+\n+Finalize\n+--------\n+\n+The dispatcher may be configured to notify one or more parts of the\n+application when the matching and processing of a batch of events has\n+completed.\n+\n+The ``rte_dispatcher_finalize_register`` call is used to\n+register a finalize callback. The function\n+``rte_dispatcher_finalize_unregister`` is used to remove a\n+callback.\n+\n+The finalize hook may be used by a set of event handlers (in the same\n+modules, or a set of cooperating modules) sharing an event output\n+buffer, since it allows for flushing of the buffers at the last\n+possible moment. In particular, it allows for buffering of\n+``RTE_EVENT_OP_FORWARD`` events, which must be flushed before the next\n+``rte_event_dequeue_burst()`` call is made (assuming implicit release\n+is employed).\n+\n+The following is an example with an application-defined event output\n+buffer (the ``event_buffer``):\n+\n+.. code-block:: c\n+\n+    static void\n+    finalize_batch(uint8_t event_dev_id, uint8_t event_port_id,\n+                   void *cb_data)\n+    {\n+            struct event_buffer *buffer = cb_data;\n+            unsigned lcore_id = rte_lcore_id();\n+            struct event_buffer_lcore *lcore_buffer =\n+                    &buffer->lcore_buffer[lcore_id];\n+    \n+            event_buffer_lcore_flush(lcore_buffer);\n+    }\n+\n+    /* In the module's initialization code */\n+    rte_dispatcher_finalize_register(dispatcher, finalize_batch,\n+                                     shared_event_buffer);\n+\n+The dispatcher does not track any relationship between a handler and a\n+finalize callback, and all finalize callbacks will be called, if (and\n+only if) at least one event was dequeued from the event device.\n+\n+Finalize callback registration and unregistration cannot safely be\n+done while the dispatcher's service function is running on any lcore.\n+\n+Service\n+-------\n+\n+The dispatcher is a DPDK service, and is managed in a manner similar\n+to other DPDK services (e.g., an Event Timer Adapter).\n+\n+Below is an example of how to configure a particular lcore to serve as\n+a service lcore, and to map an already-configured dispatcher\n+(identified by ``DISPATCHER_ID``) to that lcore.\n+\n+.. code-block:: c\n+\n+    static void\n+    launch_dispatcher_core(struct rte_dispatcher *dispatcher,\n+                           unsigned lcore_id)\n+    {\n+            uint32_t service_id;\n+    \n+            rte_service_lcore_add(lcore_id);\n+    \n+            rte_dispatcher_service_id_get(dispatcher, &service_id);\n+    \n+            rte_service_map_lcore_set(service_id, lcore_id, 1);\n+    \n+            rte_service_lcore_start(lcore_id);\n+    \n+            rte_service_runstate_set(service_id, 1);\n+    }\n+\n+As the final step, the dispatcher must be started.\n+\n+.. code-block:: c\n+\n+    rte_dispatcher_start(dispatcher);\n+\n+\n+Multi Service Dispatcher Lcores\n+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n+\n+In an Eventdev application, most (or all) compute-intensive and\n+performance-sensitive processing is done in an event-driven manner,\n+where CPU cycles spent on application domain logic is the direct\n+result of items of work (i.e., ``rte_event`` events) dequeued from an\n+event device.\n+\n+In the light of this, it makes sense to have the dispatcher service be\n+the only DPDK service on all lcores used for packet processing — at\n+least in principle.\n+\n+However, there is nothing in DPDK that prevents colocating other\n+services with the dispatcher service on the same lcore.\n+\n+Tasks that prior to the introduction of the dispatcher into the\n+application was performed on the lcore, even though no events were\n+received, are prime targets for being converted into such auxiliary\n+services, running on the dispatcher core set.\n+\n+An example of such a task would be the management of a per-lcore timer\n+wheel (i.e., calling ``rte_timer_manage()``).\n+\n+For applications employing :doc:`Read-Copy-Update (RCU) <rcu_lib>` (or\n+similar technique), may opt for having quiescent state (e.g., calling\n+``rte_rcu_qsbr_quiescent()``) signaling factored out into a separate\n+service, to assure resource reclaimination occurs even in though some\n+lcores currently do not process any events.\n+\n+If more services than the dispatcher service is mapped to a service\n+lcore, it's important that the other service are well-behaved and\n+don't interfere with event processing to the extent the system's\n+throughput and/or latency requirements are at risk of not being met.\n+\n+In particular, to avoid jitter, they should have an small upper bound\n+for the maximum amount of time spent in a single service function\n+call.\n+\n+An example of scenario with a more CPU-heavy colocated service is a\n+low-lcore count deployment, where the event device lacks the\n+``RTE_EVENT_ETH_RX_ADAPTER_CAP_INTERNAL_PORT`` capability (and thus\n+require software to feed incoming packets into the event device). In\n+this case, the best performance may be achieved if the Event Ethernet\n+RX and/or TX Adapters are mapped to lcores also used by for event\n+dispatching, since otherwise the adapter lcores would have a lot of\n+idle CPU cycles.\n+\n+.. rubric:: Footnotes\n+\n+.. [#Mapping]\n+   Event routing may reasonably be done based on other ``rte_event``\n+   fields (or even event user data). Indeed, that's the very reason to\n+   have match callback functions, instead of a simple queue\n+   id-to-handler mapping scheme. Queue id-based routing serves well in\n+   a simple example.\n+\n+.. [#Port-MT-Safety]\n+   This property (which is a feature, not a bug) is inherited from the\n+   core Eventdev APIs.\ndiff --git a/doc/guides/prog_guide/index.rst b/doc/guides/prog_guide/index.rst\nindex 52a6d9e7aa..ab05bd6074 100644\n--- a/doc/guides/prog_guide/index.rst\n+++ b/doc/guides/prog_guide/index.rst\n@@ -60,6 +60,7 @@ Programmer's Guide\n     event_ethernet_tx_adapter\n     event_timer_adapter\n     event_crypto_adapter\n+    dispatcher_lib\n     qos_framework\n     power_man\n     packet_classif_access_ctrl\n",
    "prefixes": [
        "v5",
        "3/3"
    ]
}