get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 126473,
    "url": "http://patches.dpdk.org/api/patches/126473/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20230424130208.9517-2-fengchengwen@huawei.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": "<20230424130208.9517-2-fengchengwen@huawei.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20230424130208.9517-2-fengchengwen@huawei.com",
    "date": "2023-04-24T13:02:06",
    "name": "[RFC,1/3] lib/coroutine: add coroutine library",
    "commit_ref": null,
    "pull_url": null,
    "state": "rejected",
    "archived": true,
    "hash": "5d308f296a2dcd0affe254dbca0133b46b39a148",
    "submitter": {
        "id": 2146,
        "url": "http://patches.dpdk.org/api/people/2146/?format=api",
        "name": "fengchengwen",
        "email": "fengchengwen@huawei.com"
    },
    "delegate": {
        "id": 319,
        "url": "http://patches.dpdk.org/api/users/319/?format=api",
        "username": "fyigit",
        "first_name": "Ferruh",
        "last_name": "Yigit",
        "email": "ferruh.yigit@amd.com"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20230424130208.9517-2-fengchengwen@huawei.com/mbox/",
    "series": [
        {
            "id": 27847,
            "url": "http://patches.dpdk.org/api/series/27847/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=27847",
            "date": "2023-04-24T13:02:05",
            "name": "introduce coroutine library",
            "version": 1,
            "mbox": "http://patches.dpdk.org/series/27847/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/126473/comments/",
    "check": "warning",
    "checks": "http://patches.dpdk.org/api/patches/126473/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 A79D8429DB;\n\tMon, 24 Apr 2023 15:09:31 +0200 (CEST)",
            "from mails.dpdk.org (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 4B62042D16;\n\tMon, 24 Apr 2023 15:09:18 +0200 (CEST)",
            "from szxga01-in.huawei.com (szxga01-in.huawei.com [45.249.212.187])\n by mails.dpdk.org (Postfix) with ESMTP id D682041138\n for <dev@dpdk.org>; Mon, 24 Apr 2023 15:09:13 +0200 (CEST)",
            "from dggpeml500024.china.huawei.com (unknown [172.30.72.57])\n by szxga01-in.huawei.com (SkyGuard) with ESMTP id 4Q4lm76VYYzsRJx;\n Mon, 24 Apr 2023 21:07:35 +0800 (CST)",
            "from localhost.localdomain (10.50.163.32) by\n dggpeml500024.china.huawei.com (7.185.36.10) with Microsoft SMTP Server\n (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id\n 15.1.2507.23; Mon, 24 Apr 2023 21:09:11 +0800"
        ],
        "From": "Chengwen Feng <fengchengwen@huawei.com>",
        "To": "<thomas@monjalon.net>, <ferruh.yigit@amd.com>",
        "CC": "<dev@dpdk.org>",
        "Subject": "[RFC 1/3] lib/coroutine: add coroutine library",
        "Date": "Mon, 24 Apr 2023 13:02:06 +0000",
        "Message-ID": "<20230424130208.9517-2-fengchengwen@huawei.com>",
        "X-Mailer": "git-send-email 2.17.1",
        "In-Reply-To": "<20230424130208.9517-1-fengchengwen@huawei.com>",
        "References": "<20230424130208.9517-1-fengchengwen@huawei.com>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain",
        "X-Originating-IP": "[10.50.163.32]",
        "X-ClientProxiedBy": "dggems706-chm.china.huawei.com (10.3.19.183) To\n dggpeml500024.china.huawei.com (7.185.36.10)",
        "X-CFilter-Loop": "Reflected",
        "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": "This patch adds coroutine library. The main elements are:\n1. scheduler: container of coroutines, which is responsible for\nscheduling coroutine.\n2. coroutine: Minimum scheduling unit, it should associated to one\nscheduler.\n\nIn the coroutine callback, application could invoke rte_co_yield() to\ngive up the CPU, and invoke rte_co_delay() to delay the specified\nmicrosecond.\n\nSigned-off-by: Chengwen Feng <fengchengwen@huawei.com>\n---\n lib/coroutine/meson.build         |   8 ++\n lib/coroutine/rte_coroutine.c     | 190 ++++++++++++++++++++++++++++++\n lib/coroutine/rte_coroutine.h     | 110 +++++++++++++++++\n lib/coroutine/rte_coroutine_imp.h |  46 ++++++++\n lib/coroutine/version.map         |  11 ++\n lib/meson.build                   |   1 +\n 6 files changed, 366 insertions(+)\n create mode 100644 lib/coroutine/meson.build\n create mode 100644 lib/coroutine/rte_coroutine.c\n create mode 100644 lib/coroutine/rte_coroutine.h\n create mode 100644 lib/coroutine/rte_coroutine_imp.h\n create mode 100644 lib/coroutine/version.map",
    "diff": "diff --git a/lib/coroutine/meson.build b/lib/coroutine/meson.build\nnew file mode 100644\nindex 0000000000..2064fb1909\n--- /dev/null\n+++ b/lib/coroutine/meson.build\n@@ -0,0 +1,8 @@\n+# SPDX-License-Identifier: BSD-3-Clause\n+# Copyright(c) 2023 HiSilicon Limited.\n+\n+sources = files('rte_coroutine.c')\n+headers = files('rte_coroutine.h')\n+indirect_headers += files('rte_coroutine_imp.h')\n+\n+deps += ['ring']\ndiff --git a/lib/coroutine/rte_coroutine.c b/lib/coroutine/rte_coroutine.c\nnew file mode 100644\nindex 0000000000..07c79fc901\n--- /dev/null\n+++ b/lib/coroutine/rte_coroutine.c\n@@ -0,0 +1,190 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2023 HiSilicon Limited\n+ */\n+\n+#include <pthread.h>\n+#include <stdio.h>\n+#include <stdlib.h>\n+#include <ucontext.h>\n+\n+#include <rte_alarm.h>\n+#include <rte_ring.h>\n+\n+#include \"rte_coroutine.h\"\n+#include \"rte_coroutine_imp.h\"\n+\n+#define FATAL(fmt, args...) printf(\"[FATAL] %s() %d: \" fmt \"\\n\", __func__, __LINE__, ##args)\n+\n+static __thread struct rte_schedule *co_schedule;\n+\n+struct rte_schedule *\n+rte_schedule_create(const char *name, uint32_t max_coroutines)\n+{\n+\tstruct rte_schedule *s = calloc(1, sizeof(struct rte_schedule));\n+\tif (s == NULL)\n+\t\treturn NULL;\n+\n+\ts->ring = rte_ring_create(name, max_coroutines, rte_socket_id(),\n+\t\t\t\t  RING_F_SC_DEQ);\n+\tif (s->ring == NULL) {\n+\t\tfree(s);\n+\t\treturn NULL;\n+\t}\n+\n+\ts->max_coroutines = max_coroutines;\n+\n+\treturn s;\n+}\n+\n+static void\n+co_run_func(uint32_t low, uint32_t hi)\n+{\n+\tuintptr_t ptr = (uint64_t)low | ((uint64_t)hi << 32);\n+\tstruct rte_cocontext *co = (struct rte_cocontext *)ptr;\n+\tco->cb(co->arg);\n+\t/* Run complete, so free it. */\n+\tfree(co->stack);\n+\tfree(co);\n+}\n+\n+int\n+rte_schedule_run(struct rte_schedule *s)\n+{\n+\tstruct rte_cocontext *co = NULL;\n+\tuintptr_t ptr;\n+\n+\t/* Set local thread variable as input argument. */\n+\tco_schedule = s;\n+\n+\twhile (!rte_ring_empty(s->ring)) {\n+\t\trte_ring_dequeue(s->ring, (void **)&co);\n+\t\tif (co->state == COROUTINE_READY) {\n+\t\t\tgetcontext(&co->ctx);\n+\t\t\tco->ctx.uc_stack.ss_sp = co->stack;\n+\t\t\tco->ctx.uc_stack.ss_size = co->stack_sz;\n+\t\t\tco->ctx.uc_link = &s->main;\n+\t\t\tco->state = COROUTINE_RUNNING;\n+\t\t\ts->running = co;\n+\t\t\tptr = (uintptr_t)co;\n+\t\t\tmakecontext(&co->ctx, (void (*)(void))co_run_func, 2,\n+\t\t\t\t    (uint32_t)ptr, (uint32_t)(ptr >> 32));\n+\t\t\tswapcontext(&s->main, &co->ctx);\n+\t\t} else if (co->state == COROUTINE_SUSPEND) {\n+\t\t\tco->state = COROUTINE_RUNNING;\n+\t\t\ts->running = co;\n+\t\t\tswapcontext(&s->main, &co->ctx);\n+\t\t} else {\n+\t\t\tFATAL(\"invalid state!\");\n+\t\t}\n+\t}\n+\n+\twhile (s->yield_head != NULL) {\n+\t\tco = s->yield_head;\n+\t\ts->yield_head = co->yield_next;\n+\t\tif (co->state == COROUTINE_YIELD) {\n+\t\t\tco->state = COROUTINE_RUNNING;\n+\t\t\ts->running = co;\n+\t\t\tswapcontext(&s->main, &co->ctx);\n+\t\t} else {\n+\t\t\tFATAL(\"invalid yield state!\");\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int\n+rte_co_create(struct rte_schedule *s, coroutine_callback_t cb, void *arg, uint32_t stack_sz)\n+{\n+\tstruct rte_cocontext *co = calloc(1, sizeof(struct rte_cocontext));\n+\tint ret;\n+\tif (co == NULL)\n+\t\treturn -ENOMEM;\n+\n+\tco->owner = s;\n+\tco->state = COROUTINE_READY;\n+\tco->cb = cb;\n+\tco->arg = arg;\n+\tif (stack_sz < MIN_STACK_SIZE)\n+\t\tstack_sz = MIN_STACK_SIZE;\n+\tco->stack_sz = stack_sz;\n+\tco->stack = calloc(1, stack_sz);\n+\tif (co->stack == NULL) {\n+\t\tfree(co);\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tret = rte_ring_enqueue(s->ring, co);\n+\tif (ret != 0) {\n+\t\tfree(co->stack);\n+\t\tfree(co);\n+\t}\n+\n+\treturn ret;\n+}\n+\n+static inline void\n+co_addto_yield_list(struct rte_schedule *s, struct rte_cocontext *co)\n+{\n+\tco->yield_next = NULL;\n+\tif (s->yield_head == NULL) {\n+\t\ts->yield_head = s->yield_tail = co;\n+\t} else {\n+\t\ts->yield_tail->yield_next = co;\n+\t\ts->yield_tail = co;\n+\t}\n+}\n+\n+void\n+rte_co_yield(void)\n+{\n+\tstruct rte_schedule *s = co_schedule;\n+\tstruct rte_cocontext *co;\n+\tif (s == NULL) {\n+\t\tFATAL(\"thread co_schedule is NULL!\");\n+\t\treturn;\n+\t}\n+\tco = s->running;\n+\tif (co == NULL) {\n+\t\tFATAL(\"running is NULL!\");\n+\t\treturn;\n+\t}\n+\tco->state = COROUTINE_YIELD;\n+\ts->running = NULL;\n+\tco_addto_yield_list(s, co);\n+\tswapcontext(&co->ctx, &s->main);\n+}\n+\n+static void\n+co_delay_imp(void *arg)\n+{\n+\tstruct rte_cocontext *co = (struct rte_cocontext *)arg;\n+\tint ret;\n+\n+\tret = rte_ring_enqueue(co->owner->ring, (void *)co);\n+\tif (ret != 0)\n+\t\tFATAL(\"enqueue failed!\");\n+}\n+\n+void\n+rte_co_delay(unsigned int us)\n+{\n+\tstruct rte_schedule *s = co_schedule;\n+\tstruct rte_cocontext *co;\n+\n+\tif (s == NULL) {\n+\t\tFATAL(\"thread co_schedule is NULL!\");\n+\t\treturn;\n+\t}\n+\n+\tco = s->running;\n+\tif (co == NULL) {\n+\t\tFATAL(\"running is NULL!\");\n+\t\treturn;\n+\t}\n+\n+\trte_eal_alarm_set(us, co_delay_imp, (void *)co);\n+\tco->state = COROUTINE_SUSPEND;\n+\ts->running = NULL;\n+\tswapcontext(&co->ctx, &s->main);\n+}\ndiff --git a/lib/coroutine/rte_coroutine.h b/lib/coroutine/rte_coroutine.h\nnew file mode 100644\nindex 0000000000..71ac9488b6\n--- /dev/null\n+++ b/lib/coroutine/rte_coroutine.h\n@@ -0,0 +1,110 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2023 HiSilicon Limited\n+ */\n+\n+#ifndef RTE_COROUTINE_H\n+#define RTE_COROUTINE_H\n+\n+#include <stdint.h>\n+\n+#include <rte_compat.h>\n+\n+/**\n+ * Callback prototype of coroutine.\n+ *\n+ * @param arg\n+ *   An arg pointer coming from the caller.\n+ */\n+typedef void (*coroutine_callback_t)(void *arg);\n+\n+struct rte_schedule;\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Create coroutine scheduler.\n+ *\n+ * The scheduler is a coroutines container, which could schedule coroutine\n+ * running.\n+ *\n+ * @param name\n+ *   The unique name of scheduler.\n+ * @param max_coroutines\n+ *   Maximum number of coroutines that can be processed by the scheduler.\n+ *\n+ * @return\n+ *   Non-NULL on success. Otherwise NULL value is returned.\n+ */\n+__rte_experimental\n+struct rte_schedule *rte_schedule_create(const char *name, uint32_t max_coroutines);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Run the coroutine scheduler.\n+ *\n+ * This function will schedule all associated coroutine, it will return zero if\n+ * no coroutines are active after scheduled.\n+ *\n+ * @param s\n+ *   The pointer of the scheduler.\n+ *\n+ * @return\n+ *   0 on success. Otherwise negative value is returned.\n+ */\n+__rte_experimental\n+int rte_schedule_run(struct rte_schedule *s);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Create one coroutine.\n+ *\n+ * This function will create one coroutine which associated target scheduler\n+ * 's'.\n+ *\n+ * @param s\n+ *   The pointer of the scheduler.\n+ * @param cb\n+ *   The callback function.\n+ * @param arg\n+ *   The argument parameter for callback function.\n+ * @param stack_sz\n+ *   The stack size which associated to coroutine. The value zero indicates that\n+ *   the default size (which is 8KB) is used.\n+ *\n+ * @return\n+ *   0 on success. Otherwise negative value is returned.\n+ */\n+__rte_experimental\n+int rte_co_create(struct rte_schedule *s, coroutine_callback_t cb, void *arg, uint32_t stack_sz);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Coroutine yield the CPU.\n+ *\n+ * This function yield the cpu of current coroutine.\n+ */\n+__rte_experimental\n+void rte_co_yield(void);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Coroutine delay function.\n+ *\n+ * This function support delay microseconds of current coroutine.\n+ *\n+ * @param us\n+ *   The time in microseconds which need delay.\n+ */\n+__rte_experimental\n+void rte_co_delay(unsigned int us);\n+\n+#endif /* RTE_COROUTINE_H */\ndiff --git a/lib/coroutine/rte_coroutine_imp.h b/lib/coroutine/rte_coroutine_imp.h\nnew file mode 100644\nindex 0000000000..70b4f19670\n--- /dev/null\n+++ b/lib/coroutine/rte_coroutine_imp.h\n@@ -0,0 +1,46 @@\n+#ifndef RTE_COROUTINE_IMP_H\n+#define RTE_COROUTINE_IMP_H\n+\n+#include <stdbool.h>\n+#include <stdint.h>\n+#include <ucontext.h>\n+\n+#include \"rte_coroutine.h\"\n+\n+#define MIN_STACK_SIZE\t8192\n+\n+enum rte_costate {\n+\tCOROUTINE_INVALID,\n+\tCOROUTINE_READY,\n+\tCOROUTINE_RUNNING,\n+\tCOROUTINE_YIELD,\n+\tCOROUTINE_SUSPEND,\n+};\n+\n+struct rte_cocontext {\n+\tstruct rte_schedule *owner; /**< Which scheduler this coroutine belongs. */\n+\tint state; /**< The current coroutine state. */\n+\tucontext_t ctx;\n+\n+\tcoroutine_callback_t cb; /**< The coroutine callback function. */\n+\tvoid *arg; /**< The coroutine callback function's input argument. */\n+\n+\tstruct rte_cocontext *yield_next;\n+\n+\tvoid *stack; /**< The allocated stack pointer. */\n+\tuint32_t stack_sz; /**< The allocated stack size. */\n+};\n+\n+struct rte_schedule {\n+\tuint32_t max_coroutines; /**< Max coroutines which this scheduler supports. */\n+\n+\tucontext_t main;\n+\tstruct rte_cocontext *running; /**< Current running coroutine. */\n+\n+\tstruct rte_ring *ring; /**< Command ring for schedule. */\n+\n+\tstruct rte_cocontext *yield_head; /**< Yield coroutine list for schedule. */\n+\tstruct rte_cocontext *yield_tail;\n+};\n+\n+#endif /* RTE_COROUTINE_IMP_H */\ndiff --git a/lib/coroutine/version.map b/lib/coroutine/version.map\nnew file mode 100644\nindex 0000000000..393b8979a6\n--- /dev/null\n+++ b/lib/coroutine/version.map\n@@ -0,0 +1,11 @@\n+EXPERIMENTAL {\n+\tglobal:\n+\n+\trte_co_create;\n+\trte_co_delay;\n+\trte_co_yield;\n+\trte_schedule_create;\n+\trte_schedule_run;\n+\n+\tlocal: *;\n+};\ndiff --git a/lib/meson.build b/lib/meson.build\nindex dc8aa4ac84..50e41f1511 100644\n--- a/lib/meson.build\n+++ b/lib/meson.build\n@@ -64,6 +64,7 @@ libraries = [\n         'flow_classify', # flow_classify lib depends on pkt framework table lib\n         'graph',\n         'node',\n+        'coroutine',\n ]\n \n optional_libs = [\n",
    "prefixes": [
        "RFC",
        "1/3"
    ]
}