get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 131818,
    "url": "https://patches.dpdk.org/api/patches/131818/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/20230922073825.351453-4-mattias.ronnblom@ericsson.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": "<20230922073825.351453-4-mattias.ronnblom@ericsson.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20230922073825.351453-4-mattias.ronnblom@ericsson.com",
    "date": "2023-09-22T07:38:25",
    "name": "[v4,3/3] doc: add dispatcher programming guide",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "a8c10fc0e15e72b6ac549606d5b053bb88938342",
    "submitter": {
        "id": 1077,
        "url": "https://patches.dpdk.org/api/people/1077/?format=api",
        "name": "Mattias Rönnblom",
        "email": "mattias.ronnblom@ericsson.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/20230922073825.351453-4-mattias.ronnblom@ericsson.com/mbox/",
    "series": [
        {
            "id": 29599,
            "url": "https://patches.dpdk.org/api/series/29599/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=29599",
            "date": "2023-09-22T07:38:22",
            "name": "Add dispatcher library",
            "version": 4,
            "mbox": "https://patches.dpdk.org/series/29599/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/131818/comments/",
    "check": "fail",
    "checks": "https://patches.dpdk.org/api/patches/131818/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 D8B3A42614;\n\tFri, 22 Sep 2023 09:44:11 +0200 (CEST)",
            "from mails.dpdk.org (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 4401640395;\n\tFri, 22 Sep 2023 09:44:02 +0200 (CEST)",
            "from EUR05-AM6-obe.outbound.protection.outlook.com\n (mail-am6eur05on2071.outbound.protection.outlook.com [40.107.22.71])\n by mails.dpdk.org (Postfix) with ESMTP id 7FC0C402DF;\n Fri, 22 Sep 2023 09:43:58 +0200 (CEST)",
            "from AS9PR05CA0041.eurprd05.prod.outlook.com (2603:10a6:20b:489::21)\n by AM7PR07MB6803.eurprd07.prod.outlook.com (2603:10a6:20b:1b2::22)\n with Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6813.19; Fri, 22 Sep\n 2023 07:43:56 +0000",
            "from AM1PEPF000252DB.eurprd07.prod.outlook.com\n (2603:10a6:20b:489:cafe::61) by AS9PR05CA0041.outlook.office365.com\n (2603:10a6:20b:489::21) with Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6792.32 via Frontend\n Transport; Fri, 22 Sep 2023 07:43:56 +0000",
            "from oa.msg.ericsson.com (192.176.1.74) by\n AM1PEPF000252DB.mail.protection.outlook.com (10.167.16.53) with Microsoft\n SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) id\n 15.20.6792.19 via Frontend Transport; Fri, 22 Sep 2023 07:43:56 +0000",
            "from SESSMB602.ericsson.se (100.87.178.24) by ESESBMB505.ericsson.se\n (153.88.183.89) with Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.32; Fri, 22\n Sep 2023 09:43:55 +0200",
            "from ESESSMB504.ericsson.se (153.88.183.54) by SESSMB602.ericsson.se\n (100.87.178.24) with Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) id 15.2.1118.26; Fri, 22 Sep\n 2023 09:43:55 +0200",
            "from seliicinfr00050.seli.gic.ericsson.se (153.88.183.153) by\n smtp.internal.ericsson.com (153.88.183.192) with Microsoft SMTP Server id\n 15.1.2507.32 via Frontend Transport; Fri, 22 Sep 2023 09:43:55 +0200",
            "from breslau.. (seliicwb00002.seli.gic.ericsson.se [10.156.25.100])\n by seliicinfr00050.seli.gic.ericsson.se (Postfix) with ESMTP id\n 6F6EF1C006A; Fri, 22 Sep 2023 09:43:55 +0200 (CEST)"
        ],
        "ARC-Seal": "i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none;\n b=Z2YcTcBUYZFVKVEU5OQeFOGhp1WC+aC3SLOboSLUQVLs1NG2+HBfGeuJAMKmnwA4N/5fjXcbqGT+1Y9xm2/dZ1CmBOk65AoXZ3WGrJZpyy275GrCuqWAWJBHg3rQzK3RumMSvPZrbEKPcOmorjf+8pIcUcCQNeOG8UAp72BzrHXuazia0RRj5lPxHoSnZy+Fd2ZZfReGzavKn/smDxTJldE4SxtYq2jkAmJRnvyRJqfL7aMlbWz5GaJkElcXU1/lRM78HQszVsVmBzXctzghqHtl4INcfFAM5URzqeZw99RRoMMca+0fWyIdnFFyUiWh/1Ui30JAEmA2BMdqd1JFNA==",
        "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=TUg8kVd2KCSEp0Vg07y/MwZnpaExwnBi56LgtBxMErE=;\n b=IPDe6sl0c5DnngZft7tjJELhuxkTPCg/RP0AHRlNjyW71koVeCYauIM/qVj3UZT6uhqT8imMyiS4tPnnjddY6PFWXfULWmtQmHi3Lf5NyHBJyslPcSiiWo9itlPoX8njSB/AkolslK96laT77gjqnwcUStkteT70HKTC6AKwYYUi52fFJZEUg57RIOEhoNxZb4YJ7XOEAJJUNo30vC6mburmQOCGWOkWhhBd2E4d9AWDkL16EBrZy/EcgReAjZRD8dNTl1SeaI/7lPlJLjKxifJGZN+aL6VLwKMuyO6gJeIYOaxZ34L769fQZI0+8nSN3ByJBYcUCR4U3gCwULqJgw==",
        "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=TUg8kVd2KCSEp0Vg07y/MwZnpaExwnBi56LgtBxMErE=;\n b=N/fAQBMIBDxx1RIr6wj1Zj1eDPGq0Q4OZ51eDvZC4DkhNN0mjc81EbZ8npKZL5AEGALVWf/veiM+xmN6zoS2Ef/xkRdbP7VHrHwL8YRsdwyUrFAKftV0hahRpvLibgXFo3ji2eNTt83hLooMnbwT0xnLSuvo5/VQgSQNsmzql/s=",
        "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 v4 3/3] doc: add dispatcher programming guide",
        "Date": "Fri, 22 Sep 2023 09:38:25 +0200",
        "Message-ID": "<20230922073825.351453-4-mattias.ronnblom@ericsson.com>",
        "X-Mailer": "git-send-email 2.34.1",
        "In-Reply-To": "<20230922073825.351453-1-mattias.ronnblom@ericsson.com>",
        "References": "<20230904130313.327809-2-mattias.ronnblom@ericsson.com>\n <20230922073825.351453-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": "AM1PEPF000252DB:EE_|AM7PR07MB6803:EE_",
        "X-MS-Office365-Filtering-Correlation-Id": "0c3cd6ea-8cbd-4be2-2ace-08dbbb3fad0a",
        "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 bjmZY1QDQtr+dmlk/rEVxJDxua2zdg5NmD0Ve41br56xWJV1PuwBHLP/ydgn2p1KBIGsoiYI4wgvW9fW/305WBQa1ItYW95E45St7CT5BqXNSscPP4xLT0RxR4WmphIuwodsJpKOvQ9QvVmGMqE275L8c5NYsmFKJ1trwmV6FdB7N6GReMDnPOYbeolXHI4Bj8GzeSNoTyCSTlP/nYWL7CSTaeQTdPWf6dwi13YHKQ3pLHmF07UEIN9kPfT/ol2uYZOLjs2zwvRTRE/4U0Tzohz9XsMqBoJxTK2ngmz0Smr2qdx1kBZwtG0PlZSKOno5EuBpenbLTx2rCqoorgB45rhZvRYrg097TZmlNpaCshxorT4CPRxIllFmlHzduDsLsTBg+heuuYntpRpNJX0jwzuQ9qInEsAyNMwK0reBh8xMjnYx2QRlnl2Xw+TX5IJrGzYNBufV2b3xFvS1w6++BgguvnCWyzicJGd9BIxDJAowfVJAPkpZ+fRyFPS5tu75yb8fOBmBaEHHkOeTjD8QDGz0GOdimdnR0L7BKGZvabX9nvhkJdGy6Rsu77RI1EVUHujGrZ+bxubx9BrxPQi9BUUbbl7NzCenP3fxa3Tferrs+xtvU7GN7A9FXwiXrgTSy/hDGa/BbdWG6jZM5guLtMIrSCscSnciqg0HVL4MWnHseX4yByzH9GwMO2qDUUGUxM9XfNmVTY8Jlu7LbD3sO5A3jhkjnlE7ZaFXm3v0GJHFM/hKJELUSPiWfAcAgiSJBWAwJ69z1Y5tBxrTyx/QrIu7fxSP5Wu6WQidpCypQ/DemDpY0e7//wPmgoVaIe6ShC1WaW5PFG+Skj+vttHfAA==",
        "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)(396003)(136003)(39860400002)(346002)(376002)(82310400011)(230921699003)(1800799009)(451199024)(186009)(40470700004)(46966006)(36840700001)(6666004)(478600001)(8676002)(8936002)(83380400001)(70586007)(54906003)(70206006)(6916009)(316002)(40460700003)(66899024)(5660300002)(66574015)(107886003)(2616005)(26005)(82960400001)(36756003)(41300700001)(82740400003)(40480700001)(4326008)(86362001)(336012)(7416002)(6266002)(1076003)(36860700001)(7636003)(47076005)(2906002)(356005)(30864003);\n DIR:OUT; SFP:1101;",
        "X-OriginatorOrg": "ericsson.com",
        "X-MS-Exchange-CrossTenant-OriginalArrivalTime": "22 Sep 2023 07:43:56.3046 (UTC)",
        "X-MS-Exchange-CrossTenant-Network-Message-Id": "\n 0c3cd6ea-8cbd-4be2-2ace-08dbbb3fad0a",
        "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 AM1PEPF000252DB.eurprd07.prod.outlook.com",
        "X-MS-Exchange-CrossTenant-AuthAs": "Anonymous",
        "X-MS-Exchange-CrossTenant-FromEntityHeader": "HybridOnPrem",
        "X-MS-Exchange-Transport-CrossTenantHeadersStamped": "AM7PR07MB6803",
        "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 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 | 434 +++++++++++++++++++++++\n doc/guides/prog_guide/index.rst          |   1 +\n 3 files changed, 436 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..d4f29ce7ba\n--- /dev/null\n+++ b/doc/guides/prog_guide/dispatcher_lib.rst\n@@ -0,0 +1,434 @@\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_ID, 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 dispatcher id is provided by the application, and must be unique.\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_ID, 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(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_ID, &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_ID);\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": [
        "v4",
        "3/3"
    ]
}