get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 26775,
    "url": "http://patches.dpdk.org/api/patches/26775/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/1499782773-12277-2-git-send-email-harry.van.haaren@intel.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": "<1499782773-12277-2-git-send-email-harry.van.haaren@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1499782773-12277-2-git-send-email-harry.van.haaren@intel.com",
    "date": "2017-07-11T14:19:27",
    "name": "[dpdk-dev,v5,1/7] service cores: header and implementation",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "e2226a4d30460727a461a375b2e1e0b87d2f37eb",
    "submitter": {
        "id": 317,
        "url": "http://patches.dpdk.org/api/people/317/?format=api",
        "name": "Van Haaren, Harry",
        "email": "harry.van.haaren@intel.com"
    },
    "delegate": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/1499782773-12277-2-git-send-email-harry.van.haaren@intel.com/mbox/",
    "series": [],
    "comments": "http://patches.dpdk.org/api/patches/26775/comments/",
    "check": "fail",
    "checks": "http://patches.dpdk.org/api/patches/26775/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [IPv6:::1])\n\tby dpdk.org (Postfix) with ESMTP id 9AADA5398;\n\tTue, 11 Jul 2017 16:19:39 +0200 (CEST)",
            "from mga06.intel.com (mga06.intel.com [134.134.136.31])\n\tby dpdk.org (Postfix) with ESMTP id 409133257\n\tfor <dev@dpdk.org>; Tue, 11 Jul 2017 16:19:35 +0200 (CEST)",
            "from fmsmga005.fm.intel.com ([10.253.24.32])\n\tby orsmga104.jf.intel.com with ESMTP; 11 Jul 2017 07:19:34 -0700",
            "from silpixa00398672.ir.intel.com ([10.237.223.128])\n\tby fmsmga005.fm.intel.com with ESMTP; 11 Jul 2017 07:19:32 -0700"
        ],
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.40,346,1496127600\"; d=\"scan'208\";a=\"125185159\"",
        "From": "Harry van Haaren <harry.van.haaren@intel.com>",
        "To": "dev@dpdk.org",
        "Cc": "thomas@monjalon.net, jerin.jacob@caviumnetworks.com,\n\tkeith.wiles@intel.com, bruce.richardson@intel.com,\n\tHarry van Haaren <harry.van.haaren@intel.com>",
        "Date": "Tue, 11 Jul 2017 15:19:27 +0100",
        "Message-Id": "<1499782773-12277-2-git-send-email-harry.van.haaren@intel.com>",
        "X-Mailer": "git-send-email 2.7.4",
        "In-Reply-To": "<1499782773-12277-1-git-send-email-harry.van.haaren@intel.com>",
        "References": "<1499445667-32588-1-git-send-email-harry.van.haaren@intel.com>\n\t<1499782773-12277-1-git-send-email-harry.van.haaren@intel.com>",
        "Subject": "[dpdk-dev] [PATCH v5 1/7] service cores: header and implementation",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<http://dpdk.org/ml/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://dpdk.org/ml/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<http://dpdk.org/ml/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "Add header files, update .map files with new service\nfunctions, and add the service header to the doxygen\nfor building.\n\nThis service header API allows DPDK to use services as\na concept of something that requires CPU cycles. An example\nis a PMD that runs in software to schedule events, where a\nhardware version exists that does not require a CPU.\n\nSigned-off-by: Harry van Haaren <harry.van.haaren@intel.com>\n\n---\n\nv5:\n- Improved service_set_stats_enable() to operate per service (Jerin)\n- Fixed un-documented doxygen parameter (Jerin)\n- Renamed cores_state to lcore_states (Jerin)\n- Optimized atomic operations and flags (Jerin)\n- Removed info about RFCs etc from commit message (Jerin)\n- Add lcore_count check to default setup function and return early (Jerin)\n- Add memory barriers to lcore_add() and lcore_del() (Jerin)\n- Rename start function to rte_service_start_with_defaults() (Jerin)\n- Rename header to rte_service_component.h (Jerin/Thomas)\n\nv4:\n- Fixed (unsigned) checkpatch error\n- Fixed misleading-indentation/if { } brackets (checkpatch/Jerin)\n- Fixed set function argument to be \"enable\" instead of \"enabled\" (Jerin)\n- Improve doxygen comment for size of array in rte_service_core_list (Jerin)\n- Fixed typos (Jerin)\n- Optimized atomic clear after running service (Jerin)\n- Added smp_rmb() at end of loop to re-load runstate / mapping (Jerin)\n- Fix issue with lcore role not being adhered to (Jerin)\n- Add experimental warnings for all service core functions (Thomas)\n- Moved service core functions into EXPERIMENTAL section of .map (Thomas)\n- Improve documentation of rte_service_lcore_reset_all() (Harry)\n\nv3:\n- None.\n\nv2:\nThanks Jerin for review - below a list your suggested changes;\n- Doxygen rename to \"service cores\" for consistency\n- use lcore instead of core for function names\n- Fix about 10 typos / seplling msitakse ;)\n- Dix doxygen /** comments for functions\n- Doxygen @param[out] improvements\n- int8_t for socket_id to ordinary int\n- Rename MACROS for readability\n- Align structs to cache lines\n- Allocate fastpath-used data from hugepages\n- Added/fixed memory barriers for multi-core scheduling\n- Add const to variables, and hoist above loop\n- Optimize cmpset atomic if MT_SAFE or only one core mapped\n- Statistics collection only when requested\n- Add error check for array pointer\n- Remove panic() calls from library\n- Fix TODO notes from previous patchset\n\nThere are also some other changes;\n- Checkpatch issues fixed\n- .map file updates\n- Add rte_service_get_by_name() function\n---\n doc/api/doxy-api-index.md                          |   1 +\n lib/librte_eal/bsdapp/eal/Makefile                 |   1 +\n lib/librte_eal/bsdapp/eal/rte_eal_version.map      |  23 +\n lib/librte_eal/common/Makefile                     |   1 +\n lib/librte_eal/common/eal_common_lcore.c           |   1 +\n lib/librte_eal/common/include/rte_eal.h            |   4 +\n lib/librte_eal/common/include/rte_lcore.h          |   3 +-\n lib/librte_eal/common/include/rte_service.h        | 387 +++++++++++\n .../common/include/rte_service_component.h         | 144 +++++\n lib/librte_eal/common/rte_service.c                | 704 +++++++++++++++++++++\n lib/librte_eal/linuxapp/eal/Makefile               |   1 +\n lib/librte_eal/linuxapp/eal/eal_thread.c           |   9 +-\n lib/librte_eal/linuxapp/eal/rte_eal_version.map    |  23 +\n 13 files changed, 1300 insertions(+), 2 deletions(-)\n create mode 100644 lib/librte_eal/common/include/rte_service.h\n create mode 100644 lib/librte_eal/common/include/rte_service_component.h\n create mode 100644 lib/librte_eal/common/rte_service.c",
    "diff": "diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md\nindex 67594e1..e99e114 100644\n--- a/doc/api/doxy-api-index.md\n+++ b/doc/api/doxy-api-index.md\n@@ -160,6 +160,7 @@ There are many libraries, so their headers may be grouped by topics:\n   [common]             (@ref rte_common.h),\n   [ABI compat]         (@ref rte_compat.h),\n   [keepalive]          (@ref rte_keepalive.h),\n+  [service cores]      (@ref rte_service.h),\n   [device metrics]     (@ref rte_metrics.h),\n   [bitrate statistics] (@ref rte_bitrate.h),\n   [latency statistics] (@ref rte_latencystats.h),\ndiff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile\nindex a0f9950..05517a2 100644\n--- a/lib/librte_eal/bsdapp/eal/Makefile\n+++ b/lib/librte_eal/bsdapp/eal/Makefile\n@@ -87,6 +87,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += rte_malloc.c\n SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += malloc_elem.c\n SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += malloc_heap.c\n SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += rte_keepalive.c\n+SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += rte_service.c\n \n # from arch dir\n SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += rte_cpuflags.c\ndiff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map\nindex 381f895..480ad23 100644\n--- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map\n+++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map\n@@ -209,5 +209,28 @@ EXPERIMENTAL {\n \trte_eal_devargs_parse;\n \trte_eal_hotplug_add;\n \trte_eal_hotplug_remove;\n+\trte_service_disable_on_lcore;\n+\trte_service_dump;\n+\trte_service_enable_on_lcore;\n+\trte_service_get_by_id;\n+\trte_service_get_by_name;\n+\trte_service_get_count;\n+\trte_service_get_enabled_on_lcore;\n+\trte_service_is_running;\n+\trte_service_lcore_add;\n+\trte_service_lcore_count;\n+\trte_service_lcore_del;\n+\trte_service_lcore_list;\n+\trte_service_lcore_reset_all;\n+\trte_service_lcore_start;\n+\trte_service_lcore_stop;\n+\trte_service_probe_capability;\n+\trte_service_register;\n+\trte_service_reset;\n+\trte_service_set_stats_enable;\n+\trte_service_start;\n+\trte_service_start_with_defaults;\n+\trte_service_stop;\n+\trte_service_unregister;\n \n } DPDK_17.08;\ndiff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile\nindex f2fe052..e8fd67a 100644\n--- a/lib/librte_eal/common/Makefile\n+++ b/lib/librte_eal/common/Makefile\n@@ -41,6 +41,7 @@ INC += rte_eal_memconfig.h rte_malloc_heap.h\n INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h rte_vdev.h\n INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h\n INC += rte_malloc.h rte_keepalive.h rte_time.h\n+INC += rte_service.h rte_service_component.h\n \n GENERIC_INC := rte_atomic.h rte_byteorder.h rte_cycles.h rte_prefetch.h\n GENERIC_INC += rte_spinlock.h rte_memcpy.h rte_cpuflags.h rte_rwlock.h\ndiff --git a/lib/librte_eal/common/eal_common_lcore.c b/lib/librte_eal/common/eal_common_lcore.c\nindex 84fa0cb..0db1555 100644\n--- a/lib/librte_eal/common/eal_common_lcore.c\n+++ b/lib/librte_eal/common/eal_common_lcore.c\n@@ -81,6 +81,7 @@ rte_eal_cpu_init(void)\n \n \t\t/* By default, each detected core is enabled */\n \t\tconfig->lcore_role[lcore_id] = ROLE_RTE;\n+\t\tlcore_config[lcore_id].core_role = ROLE_RTE;\n \t\tlcore_config[lcore_id].core_id = eal_cpu_core_id(lcore_id);\n \t\tlcore_config[lcore_id].socket_id = eal_cpu_socket_id(lcore_id);\n \t\tif (lcore_config[lcore_id].socket_id >= RTE_MAX_NUMA_NODES) {\ndiff --git a/lib/librte_eal/common/include/rte_eal.h b/lib/librte_eal/common/include/rte_eal.h\nindex 6b7c5ca..0e7363d 100644\n--- a/lib/librte_eal/common/include/rte_eal.h\n+++ b/lib/librte_eal/common/include/rte_eal.h\n@@ -61,6 +61,7 @@ extern \"C\" {\n enum rte_lcore_role_t {\n \tROLE_RTE,\n \tROLE_OFF,\n+\tROLE_SERVICE,\n };\n \n /**\n@@ -80,6 +81,7 @@ enum rte_proc_type_t {\n struct rte_config {\n \tuint32_t master_lcore;       /**< Id of the master lcore */\n \tuint32_t lcore_count;        /**< Number of available logical cores. */\n+\tuint32_t service_lcore_count;/**< Number of available service cores. */\n \tenum rte_lcore_role_t lcore_role[RTE_MAX_LCORE]; /**< State of cores. */\n \n \t/** Primary or secondary configuration */\n@@ -185,6 +187,8 @@ int rte_eal_iopl_init(void);\n  *\n  *     EPROTO indicates that the PCI bus is either not present, or is not\n  *            readable by the eal.\n+ *\n+ *     ENOEXEC indicates that a service core failed to launch successfully.\n  */\n int rte_eal_init(int argc, char **argv);\n \ndiff --git a/lib/librte_eal/common/include/rte_lcore.h b/lib/librte_eal/common/include/rte_lcore.h\nindex fe7b586..50e0d0f 100644\n--- a/lib/librte_eal/common/include/rte_lcore.h\n+++ b/lib/librte_eal/common/include/rte_lcore.h\n@@ -73,6 +73,7 @@ struct lcore_config {\n \tunsigned core_id;          /**< core number on socket for this lcore */\n \tint core_index;            /**< relative index, starting from 0 */\n \trte_cpuset_t cpuset;       /**< cpu set which the lcore affinity to */\n+\tuint8_t core_role;         /**< role of core eg: OFF, RTE, SERVICE */\n };\n \n /**\n@@ -175,7 +176,7 @@ rte_lcore_is_enabled(unsigned lcore_id)\n \tstruct rte_config *cfg = rte_eal_get_configuration();\n \tif (lcore_id >= RTE_MAX_LCORE)\n \t\treturn 0;\n-\treturn cfg->lcore_role[lcore_id] != ROLE_OFF;\n+\treturn cfg->lcore_role[lcore_id] == ROLE_RTE;\n }\n \n /**\ndiff --git a/lib/librte_eal/common/include/rte_service.h b/lib/librte_eal/common/include/rte_service.h\nnew file mode 100644\nindex 0000000..7c6f738\n--- /dev/null\n+++ b/lib/librte_eal/common/include/rte_service.h\n@@ -0,0 +1,387 @@\n+/*\n+ *   BSD LICENSE\n+ *\n+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.\n+ *\n+ *   Redistribution and use in source and binary forms, with or without\n+ *   modification, are permitted provided that the following conditions\n+ *   are met:\n+ *\n+ *     * Redistributions of source code must retain the above copyright\n+ *       notice, this list of conditions and the following disclaimer.\n+ *     * Redistributions in binary form must reproduce the above copyright\n+ *       notice, this list of conditions and the following disclaimer in\n+ *       the documentation and/or other materials provided with the\n+ *       distribution.\n+ *     * Neither the name of Intel Corporation nor the names of its\n+ *       contributors may be used to endorse or promote products derived\n+ *       from this software without specific prior written permission.\n+ *\n+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+ *   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+#ifndef _RTE_SERVICE_H_\n+#define _RTE_SERVICE_H_\n+\n+/**\n+ * @file\n+ *\n+ * Service functions\n+ *\n+ * The service functionality provided by this header allows a DPDK component\n+ * to indicate that it requires a function call in order for it to perform\n+ * its processing.\n+ *\n+ * An example usage of this functionality would be a component that registers\n+ * a service to perform a particular packet processing duty: for example the\n+ * eventdev software PMD. At startup the application requests all services\n+ * that have been registered, and the cores in the service-coremask run the\n+ * required services. The EAL removes these number of cores from the available\n+ * runtime cores, and dedicates them to performing service-core workloads. The\n+ * application has access to the remaining lcores as normal.\n+ */\n+\n+#ifdef __cplusplus\n+extern \"C\" {\n+#endif\n+\n+#include<stdio.h>\n+#include <stdint.h>\n+#include <sys/queue.h>\n+\n+#include <rte_lcore.h>\n+\n+/* forward declaration only. Definition in rte_service_private.h */\n+struct rte_service_spec;\n+\n+#define RTE_SERVICE_NAME_MAX 32\n+\n+/* Capabilities of a service.\n+ *\n+ * Use the *rte_service_probe_capability* function to check if a service is\n+ * capable of a specific capability.\n+ */\n+/** When set, the service is capable of having multiple threads run it at the\n+ *  same time.\n+ */\n+#define RTE_SERVICE_CAP_MT_SAFE (1 << 0)\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ *  Return the number of services registered.\n+ *\n+ * The number of services registered can be passed to *rte_service_get_by_id*,\n+ * enabling the application to retrieve the specification of each service.\n+ *\n+ * @return The number of services registered.\n+ */\n+uint32_t rte_service_get_count(void);\n+\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ * Return the specification of a service by integer id.\n+ *\n+ * This function provides the specification of a service. This can be used by\n+ * the application to understand what the service represents. The service\n+ * must not be modified by the application directly, only passed to the various\n+ * rte_service_* functions.\n+ *\n+ * @param id The integer id of the service to retrieve\n+ * @retval non-zero A valid pointer to the service_spec\n+ * @retval NULL Invalid *id* provided.\n+ */\n+struct rte_service_spec *rte_service_get_by_id(uint32_t id);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ * Return the specification of a service by name.\n+ *\n+ * This function provides the specification of a service using the service name\n+ * as lookup key. This can be used by the application to understand what the\n+ * service represents. The service must not be modified by the application\n+ * directly, only passed to the various rte_service_* functions.\n+ *\n+ * @param name The name of the service to retrieve\n+ * @retval non-zero A valid pointer to the service_spec\n+ * @retval NULL Invalid *name* provided.\n+ */\n+struct rte_service_spec *rte_service_get_by_name(const char *name);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ * Return the name of the service.\n+ *\n+ * @return A pointer to the name of the service. The returned pointer remains\n+ *         in ownership of the service, and the application must not free it.\n+ */\n+const char *rte_service_get_name(const struct rte_service_spec *service);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ * Check if a service has a specific capability.\n+ *\n+ * This function returns if *service* has implements *capability*.\n+ * See RTE_SERVICE_CAP_* defines for a list of valid capabilities.\n+ * @retval 1 Capability supported by this service instance\n+ * @retval 0 Capability not supported by this service instance\n+ */\n+int32_t rte_service_probe_capability(const struct rte_service_spec *service,\n+\t\t\t\t     uint32_t capability);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ * Enable a core to run a service.\n+ *\n+ * Each core can be added or removed from running specific services. This\n+ * functions adds *lcore* to the set of cores that will run *service*.\n+ *\n+ * If multiple cores are enabled on a service, an atomic is used to ensure that\n+ * only one cores runs the service at a time. The exception to this is when\n+ * a service indicates that it is multi-thread safe by setting the capability\n+ * called RTE_SERVICE_CAP_MT_SAFE. With the multi-thread safe capability set,\n+ * the service function can be run on multiple threads at the same time.\n+ *\n+ * @retval 0 lcore added successfully\n+ * @retval -EINVAL An invalid service or lcore was provided.\n+ */\n+int32_t rte_service_enable_on_lcore(struct rte_service_spec *service,\n+\t\t\t\t   uint32_t lcore);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ * Disable a core to run a service.\n+ *\n+ * Each core can be added or removed from running specific services. This\n+ * functions removes *lcore* to the set of cores that will run *service*.\n+ *\n+ * @retval 0 Lcore removed successfully\n+ * @retval -EINVAL An invalid service or lcore was provided.\n+ */\n+int32_t rte_service_disable_on_lcore(struct rte_service_spec *service,\n+\t\t\t\t   uint32_t lcore);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ * Return if an lcore is enabled for the service.\n+ *\n+ * This function allows the application to query if *lcore* is currently set to\n+ * run *service*.\n+ *\n+ * @retval 1 Lcore enabled on this lcore\n+ * @retval 0 Lcore disabled on this lcore\n+ * @retval -EINVAL An invalid service or lcore was provided.\n+ */\n+int32_t rte_service_get_enabled_on_lcore(struct rte_service_spec *service,\n+\t\t\t\t\tuint32_t lcore);\n+\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ * Enable *service* to run.\n+ *\n+ * This function switches on a service during runtime.\n+ * @retval 0 The service was successfully started\n+ */\n+int32_t rte_service_start(struct rte_service_spec *service);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ * Disable *service*.\n+ *\n+ * Switch off a service, so it is not run until it is *rte_service_start* is\n+ * called on it.\n+ * @retval 0 Service successfully switched off\n+ */\n+int32_t rte_service_stop(struct rte_service_spec *service);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ * Returns if *service* is currently running.\n+ *\n+ * This function returns true if the service has been started using\n+ * *rte_service_start*, AND a service core is mapped to the service. This\n+ * function can be used to ensure that the service will be run.\n+ *\n+ * @retval 1 Service is currently running, and has a service lcore mapped\n+ * @retval 0 Service is currently stopped, or no service lcore is mapped\n+ * @retval -EINVAL Invalid service pointer provided\n+ */\n+int32_t rte_service_is_running(const struct rte_service_spec *service);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ * Start a service core.\n+ *\n+ * Starting a core makes the core begin polling. Any services assigned to it\n+ * will be run as fast as possible.\n+ *\n+ * @retval 0 Success\n+ * @retval -EINVAL Failed to start core. The *lcore_id* passed in is not\n+ *          currently assigned to be a service core.\n+ */\n+int32_t rte_service_lcore_start(uint32_t lcore_id);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ * Stop a service core.\n+ *\n+ * Stopping a core makes the core become idle, but remains  assigned as a\n+ * service core.\n+ *\n+ * @retval 0 Success\n+ * @retval -EINVAL Invalid *lcore_id* provided\n+ * @retval -EALREADY Already stopped core\n+ * @retval -EBUSY Failed to stop core, as it would cause a service to not\n+ *          be run, as this is the only core currently running the service.\n+ *          The application must stop the service first, and then stop the\n+ *          lcore.\n+ */\n+int32_t rte_service_lcore_stop(uint32_t lcore_id);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ * Adds lcore to the list of service cores.\n+ *\n+ * This functions can be used at runtime in order to modify the service core\n+ * mask.\n+ *\n+ * @retval 0 Success\n+ * @retval -EBUSY lcore is busy, and not available for service core duty\n+ * @retval -EALREADY lcore is already added to the service core list\n+ * @retval -EINVAL Invalid lcore provided\n+ */\n+int32_t rte_service_lcore_add(uint32_t lcore);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ * Removes lcore from the list of service cores.\n+ *\n+ * This can fail if the core is not stopped, see *rte_service_core_stop*.\n+ *\n+ * @retval 0 Success\n+ * @retval -EBUSY Lcore is not stopped, stop service core before removing.\n+ * @retval -EINVAL failed to add lcore to service core mask.\n+ */\n+int32_t rte_service_lcore_del(uint32_t lcore);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ * Retrieve the number of service cores currently available.\n+ *\n+ * This function returns the integer count of service cores available. The\n+ * service core count can be used in mapping logic when creating mappings\n+ * from service cores to services.\n+ *\n+ * See *rte_service_lcore_list* for details on retrieving the lcore_id of each\n+ * service core.\n+ *\n+ * @return The number of service cores currently configured.\n+ */\n+int32_t rte_service_lcore_count(void);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ * Resets all service core mappings. This does not remove the service cores\n+ * from duty, just unmaps all services / cores, and stops() the service cores.\n+ * The runstate of services is not modified.\n+ *\n+ * @retval 0 Success\n+ */\n+int32_t rte_service_lcore_reset_all(void);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ * Enable or disable statistics collection for *service*.\n+ *\n+ * This function enables per core, per-service cycle count collection.\n+ * @param service The service to enable statistics gathering on.\n+ * @param enable Zero to disable statistics, non-zero to enable.\n+ * @retval 0 Success\n+ * @retval -EINVAL Invalid service pointer passed\n+ */\n+int32_t rte_service_set_stats_enable(struct rte_service_spec *service,\n+\t\t\t\t  int32_t enable);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ * Retrieve the list of currently enabled service cores.\n+ *\n+ * This function fills in an application supplied array, with each element\n+ * indicating the lcore_id of a service core.\n+ *\n+ * Adding and removing service cores can be performed using\n+ * *rte_service_lcore_add* and *rte_service_lcore_del*.\n+ * @param [out] array An array of at least *rte_service_lcore_count* items.\n+ *              If statically allocating the buffer, use RTE_MAX_LCORE.\n+ * @param [out] n The size of *array*.\n+ * @retval >=0 Number of service cores that have been populated in the array\n+ * @retval -ENOMEM The provided array is not large enough to fill in the\n+ *          service core list. No items have been populated, call this function\n+ *          with a size of at least *rte_service_core_count* items.\n+ */\n+int32_t rte_service_lcore_list(uint32_t array[], uint32_t n);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ * Dumps any information available about the service. If service is NULL,\n+ * dumps info for all services.\n+ */\n+int32_t rte_service_dump(FILE *f, struct rte_service_spec *service);\n+\n+#ifdef __cplusplus\n+}\n+#endif\n+\n+\n+#endif /* _RTE_SERVICE_H_ */\ndiff --git a/lib/librte_eal/common/include/rte_service_component.h b/lib/librte_eal/common/include/rte_service_component.h\nnew file mode 100644\nindex 0000000..7a946a1\n--- /dev/null\n+++ b/lib/librte_eal/common/include/rte_service_component.h\n@@ -0,0 +1,144 @@\n+/*\n+ *   BSD LICENSE\n+ *\n+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.\n+ *\n+ *   Redistribution and use in source and binary forms, with or without\n+ *   modification, are permitted provided that the following conditions\n+ *   are met:\n+ *\n+ *     * Redistributions of source code must retain the above copyright\n+ *       notice, this list of conditions and the following disclaimer.\n+ *     * Redistributions in binary form must reproduce the above copyright\n+ *       notice, this list of conditions and the following disclaimer in\n+ *       the documentation and/or other materials provided with the\n+ *       distribution.\n+ *     * Neither the name of Intel Corporation nor the names of its\n+ *       contributors may be used to endorse or promote products derived\n+ *       from this software without specific prior written permission.\n+ *\n+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+ *   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+#ifndef _RTE_SERVICE_PRIVATE_H_\n+#define _RTE_SERVICE_PRIVATE_H_\n+\n+/* This file specifies the internal service specification.\n+ * Include this file if you are writing a component that requires CPU cycles to\n+ * operate, and you wish to run the component using service cores\n+ */\n+\n+#include <rte_service.h>\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ * Signature of callback function to run a service.\n+ */\n+typedef int32_t (*rte_service_func)(void *args);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ * The specification of a service.\n+ *\n+ * This struct contains metadata about the service itself, the callback\n+ * function to run one iteration of the service, a userdata pointer, flags etc.\n+ */\n+struct rte_service_spec {\n+\t/** The name of the service. This should be used by the application to\n+\t * understand what purpose this service provides.\n+\t */\n+\tchar name[RTE_SERVICE_NAME_MAX];\n+\t/** The callback to invoke to run one iteration of the service. */\n+\trte_service_func callback;\n+\t/** The userdata pointer provided to the service callback. */\n+\tvoid *callback_userdata;\n+\t/** Flags to indicate the capabilities of this service. See defines in\n+\t * the public header file for values of RTE_SERVICE_CAP_*\n+\t */\n+\tuint32_t capabilities;\n+\t/** NUMA socket ID that this service is affinitized to */\n+\tint socket_id;\n+};\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ * Register a new service.\n+ *\n+ * A service represents a component that the requires CPU time periodically to\n+ * achieve its purpose.\n+ *\n+ * For example the eventdev SW PMD requires CPU cycles to perform its\n+ * scheduling. This can be achieved by registering it as a service, and the\n+ * application can then assign CPU resources to it using\n+ * *rte_service_set_coremask*.\n+ *\n+ * @param spec The specification of the service to register\n+ * @retval 0 Successfully registered the service.\n+ *         -EINVAL Attempted to register an invalid service (eg, no callback\n+ *         set)\n+ */\n+int32_t rte_service_register(const struct rte_service_spec *spec);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ * Unregister a service.\n+ *\n+ * The service being removed must be stopped before calling this function.\n+ *\n+ * @retval 0 The service was successfully unregistered.\n+ * @retval -EBUSY The service is currently running, stop the service before\n+ *          calling unregister. No action has been taken.\n+ */\n+int32_t rte_service_unregister(struct rte_service_spec *service);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ * Private function to allow EAL to initialized default mappings.\n+ *\n+ * This function iterates all the services, and maps then to the available\n+ * cores. Based on the capabilities of the services, they are set to run on the\n+ * available cores in a round-robin manner.\n+ *\n+ * @retval 0 Success\n+ * @retval -ENOTSUP No service lcores in use\n+ * @retval -EINVAL Error while iterating over services\n+ * @retval -ENODEV Error in enabling service lcore on a service\n+ * @retval -ENOEXEC Error when starting services\n+ */\n+int32_t rte_service_start_with_defaults(void);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ * Initialize the service library.\n+ *\n+ * In order to use the service library, it must be initialized. EAL initializes\n+ * the library at startup.\n+ *\n+ * @retval 0 Success\n+ * @retval -EALREADY Service library is already initialized\n+ */\n+int32_t rte_service_init(void);\n+\n+#endif /* _RTE_SERVICE_PRIVATE_H_ */\ndiff --git a/lib/librte_eal/common/rte_service.c b/lib/librte_eal/common/rte_service.c\nnew file mode 100644\nindex 0000000..e82b9ad\n--- /dev/null\n+++ b/lib/librte_eal/common/rte_service.c\n@@ -0,0 +1,704 @@\n+/*-\n+ *   BSD LICENSE\n+ *\n+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.\n+ *   All rights reserved.\n+ *\n+ *   Redistribution and use in source and binary forms, with or without\n+ *   modification, are permitted provided that the following conditions\n+ *   are met:\n+ *\n+ *     * Redistributions of source code must retain the above copyright\n+ *       notice, this list of conditions and the following disclaimer.\n+ *     * Redistributions in binary form must reproduce the above copyright\n+ *       notice, this list of conditions and the following disclaimer in\n+ *       the documentation and/or other materials provided with the\n+ *       distribution.\n+ *     * Neither the name of Intel Corporation nor the names of its\n+ *       contributors may be used to endorse or promote products derived\n+ *       from this software without specific prior written permission.\n+ *\n+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+ *   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+#include <stdio.h>\n+#include <unistd.h>\n+#include <inttypes.h>\n+#include <limits.h>\n+#include <string.h>\n+#include <dirent.h>\n+\n+#include <rte_service.h>\n+#include \"include/rte_service_component.h\"\n+\n+#include <rte_eal.h>\n+#include <rte_lcore.h>\n+#include <rte_common.h>\n+#include <rte_debug.h>\n+#include <rte_cycles.h>\n+#include <rte_atomic.h>\n+#include <rte_memory.h>\n+#include <rte_malloc.h>\n+\n+#define RTE_SERVICE_NUM_MAX 64\n+\n+#define SERVICE_F_REGISTERED    (1 << 0)\n+#define SERVICE_F_STATS_ENABLED (1 << 1)\n+\n+/* runstates for services and lcores, denoting if they are active or not */\n+#define RUNSTATE_STOPPED 0\n+#define RUNSTATE_RUNNING 1\n+\n+/* internal representation of a service */\n+struct rte_service_spec_impl {\n+\t/* public part of the struct */\n+\tstruct rte_service_spec spec;\n+\n+\t/* atomic lock that when set indicates a service core is currently\n+\t * running this service callback. When not set, a core may take the\n+\t * lock and then run the service callback.\n+\t */\n+\trte_atomic32_t execute_lock;\n+\n+\t/* API set/get-able variables */\n+\tint32_t runstate;\n+\tuint8_t internal_flags;\n+\n+\t/* per service statistics */\n+\tuint32_t num_mapped_cores;\n+\tuint64_t calls;\n+\tuint64_t cycles_spent;\n+} __rte_cache_aligned;\n+\n+/* the internal values of a service core */\n+struct core_state {\n+\t/* map of services IDs are run on this core */\n+\tuint64_t service_mask;\n+\tuint8_t runstate; /* running or stopped */\n+\tuint8_t is_service_core; /* set if core is currently a service core */\n+\n+\t/* extreme statistics */\n+\tuint64_t calls_per_service[RTE_SERVICE_NUM_MAX];\n+} __rte_cache_aligned;\n+\n+static uint32_t rte_service_count;\n+static struct rte_service_spec_impl *rte_services;\n+static struct core_state *lcore_states;\n+static uint32_t rte_service_library_initialized;\n+\n+int32_t rte_service_init(void)\n+{\n+\tif (rte_service_library_initialized) {\n+\t\tprintf(\"service library init() called, init flag %d\\n\",\n+\t\t\trte_service_library_initialized);\n+\t\treturn -EALREADY;\n+\t}\n+\n+\trte_services = rte_calloc(\"rte_services\", RTE_SERVICE_NUM_MAX,\n+\t\t\tsizeof(struct rte_service_spec_impl),\n+\t\t\tRTE_CACHE_LINE_SIZE);\n+\tif (!rte_services) {\n+\t\tprintf(\"error allocating rte services array\\n\");\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tlcore_states = rte_calloc(\"rte_service_core_states\", RTE_MAX_LCORE,\n+\t\t\tsizeof(struct core_state), RTE_CACHE_LINE_SIZE);\n+\tif (!lcore_states) {\n+\t\tprintf(\"error allocating core states array\\n\");\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tint i;\n+\tint count = 0;\n+\tstruct rte_config *cfg = rte_eal_get_configuration();\n+\tfor (i = 0; i < RTE_MAX_LCORE; i++) {\n+\t\tif (lcore_config[i].core_role == ROLE_SERVICE) {\n+\t\t\tif ((unsigned int)i == cfg->master_lcore)\n+\t\t\t\tcontinue;\n+\t\t\trte_service_lcore_add(i);\n+\t\t\tcount++;\n+\t\t}\n+\t}\n+\n+\trte_service_library_initialized = 1;\n+\treturn 0;\n+}\n+\n+/* returns 1 if service is registered and has not been unregistered\n+ * Returns 0 if service never registered, or has been unregistered\n+ */\n+static inline int\n+service_valid(uint32_t id)\n+{\n+\treturn !!(rte_services[id].internal_flags & SERVICE_F_REGISTERED);\n+}\n+\n+/* returns 1 if statistics should be colleced for service\n+ * Returns 0 if statistics should not be collected for service\n+ */\n+static inline int\n+service_stats_enabled(struct rte_service_spec_impl *impl)\n+{\n+\treturn !!(impl->internal_flags & SERVICE_F_STATS_ENABLED);\n+}\n+\n+static inline int\n+service_mt_safe(struct rte_service_spec_impl *s)\n+{\n+\treturn s->spec.capabilities & RTE_SERVICE_CAP_MT_SAFE;\n+}\n+\n+int32_t rte_service_set_stats_enable(struct rte_service_spec *service,\n+\t\t\t\t  int32_t enabled)\n+{\n+\tstruct rte_service_spec_impl *impl =\n+\t\t(struct rte_service_spec_impl *)service;\n+\tif (!impl)\n+\t\treturn -EINVAL;\n+\n+\tif (enabled)\n+\t\timpl->internal_flags |= SERVICE_F_STATS_ENABLED;\n+\telse\n+\t\timpl->internal_flags &= ~(SERVICE_F_STATS_ENABLED);\n+\n+\treturn 0;\n+}\n+\n+uint32_t\n+rte_service_get_count(void)\n+{\n+\treturn rte_service_count;\n+}\n+\n+struct rte_service_spec *\n+rte_service_get_by_id(uint32_t id)\n+{\n+\tstruct rte_service_spec *service = NULL;\n+\tif (id < rte_service_count)\n+\t\tservice = (struct rte_service_spec *)&rte_services[id];\n+\n+\treturn service;\n+}\n+\n+struct rte_service_spec *rte_service_get_by_name(const char *name)\n+{\n+\tstruct rte_service_spec *service = NULL;\n+\tint i;\n+\tfor (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {\n+\t\tif (service_valid(i) &&\n+\t\t\t\tstrcmp(name, rte_services[i].spec.name) == 0) {\n+\t\t\tservice = (struct rte_service_spec *)&rte_services[i];\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\treturn service;\n+}\n+\n+const char *\n+rte_service_get_name(const struct rte_service_spec *service)\n+{\n+\treturn service->name;\n+}\n+\n+int32_t\n+rte_service_probe_capability(const struct rte_service_spec *service,\n+\t\t\t     uint32_t capability)\n+{\n+\treturn service->capabilities & capability;\n+}\n+\n+int32_t\n+rte_service_is_running(const struct rte_service_spec *spec)\n+{\n+\tconst struct rte_service_spec_impl *impl =\n+\t\t(const struct rte_service_spec_impl *)spec;\n+\tif (!impl)\n+\t\treturn -EINVAL;\n+\n+\treturn (impl->runstate == RUNSTATE_RUNNING) &&\n+\t\t(impl->num_mapped_cores > 0);\n+}\n+\n+int32_t\n+rte_service_register(const struct rte_service_spec *spec)\n+{\n+\tuint32_t i;\n+\tint32_t free_slot = -1;\n+\n+\tif (spec->callback == NULL || strlen(spec->name) == 0)\n+\t\treturn -EINVAL;\n+\n+\tfor (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {\n+\t\tif (!service_valid(i)) {\n+\t\t\tfree_slot = i;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\tif ((free_slot < 0) || (i == RTE_SERVICE_NUM_MAX))\n+\t\treturn -ENOSPC;\n+\n+\tstruct rte_service_spec_impl *s = &rte_services[free_slot];\n+\ts->spec = *spec;\n+\ts->internal_flags |= SERVICE_F_REGISTERED;\n+\n+\trte_smp_wmb();\n+\trte_service_count++;\n+\n+\treturn 0;\n+}\n+\n+int32_t\n+rte_service_unregister(struct rte_service_spec *spec)\n+{\n+\tstruct rte_service_spec_impl *s = NULL;\n+\tstruct rte_service_spec_impl *spec_impl =\n+\t\t(struct rte_service_spec_impl *)spec;\n+\n+\tuint32_t i;\n+\tuint32_t service_id;\n+\tfor (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {\n+\t\tif (&rte_services[i] == spec_impl) {\n+\t\t\ts = spec_impl;\n+\t\t\tservice_id = i;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\tif (!s)\n+\t\treturn -EINVAL;\n+\n+\trte_service_count--;\n+\trte_smp_wmb();\n+\n+\ts->internal_flags &= ~(SERVICE_F_REGISTERED);\n+\n+\tfor (i = 0; i < RTE_MAX_LCORE; i++)\n+\t\tlcore_states[i].service_mask &= ~(1 << service_id);\n+\n+\tmemset(&rte_services[service_id], 0,\n+\t\t\tsizeof(struct rte_service_spec_impl));\n+\n+\treturn 0;\n+}\n+\n+int32_t\n+rte_service_start(struct rte_service_spec *service)\n+{\n+\tstruct rte_service_spec_impl *s =\n+\t\t(struct rte_service_spec_impl *)service;\n+\ts->runstate = RUNSTATE_RUNNING;\n+\trte_smp_wmb();\n+\treturn 0;\n+}\n+\n+int32_t\n+rte_service_stop(struct rte_service_spec *service)\n+{\n+\tstruct rte_service_spec_impl *s =\n+\t\t(struct rte_service_spec_impl *)service;\n+\ts->runstate = RUNSTATE_STOPPED;\n+\trte_smp_wmb();\n+\treturn 0;\n+}\n+\n+static int32_t\n+rte_service_runner_func(void *arg)\n+{\n+\tRTE_SET_USED(arg);\n+\tuint32_t i;\n+\tconst int lcore = rte_lcore_id();\n+\tstruct core_state *cs = &lcore_states[lcore];\n+\n+\twhile (lcore_states[lcore].runstate == RUNSTATE_RUNNING) {\n+\t\tconst uint64_t service_mask = cs->service_mask;\n+\t\tfor (i = 0; i < rte_service_count; i++) {\n+\t\t\tstruct rte_service_spec_impl *s = &rte_services[i];\n+\t\t\tif (s->runstate != RUNSTATE_RUNNING ||\n+\t\t\t\t\t!(service_mask & (1 << i)))\n+\t\t\t\tcontinue;\n+\n+\t\t\t/* check do we need cmpset, if MT safe or <= 1 core\n+\t\t\t * mapped, atomic ops are not required.\n+\t\t\t */\n+\t\t\tconst int need_cmpset = !((service_mt_safe(s) == 0) &&\n+\t\t\t\t\t\t(s->num_mapped_cores > 1));\n+\t\t\tuint32_t *lock = (uint32_t *)&s->execute_lock;\n+\n+\t\t\tif (need_cmpset || rte_atomic32_cmpset(lock, 0, 1)) {\n+\t\t\t\tvoid *userdata = s->spec.callback_userdata;\n+\n+\t\t\t\tif (service_stats_enabled(s)) {\n+\t\t\t\t\tuint64_t start = rte_rdtsc();\n+\t\t\t\t\ts->spec.callback(userdata);\n+\t\t\t\t\tuint64_t end = rte_rdtsc();\n+\t\t\t\t\ts->cycles_spent += end - start;\n+\t\t\t\t\tcs->calls_per_service[i]++;\n+\t\t\t\t\ts->calls++;\n+\t\t\t\t} else\n+\t\t\t\t\ts->spec.callback(userdata);\n+\n+\t\t\t\tif (need_cmpset)\n+\t\t\t\t\trte_atomic32_clear(&s->execute_lock);\n+\t\t\t}\n+\t\t}\n+\n+\t\trte_smp_rmb();\n+\t}\n+\n+\tlcore_config[lcore].state = WAIT;\n+\n+\treturn 0;\n+}\n+\n+int32_t\n+rte_service_lcore_count(void)\n+{\n+\tint32_t count = 0;\n+\tuint32_t i;\n+\tfor (i = 0; i < RTE_MAX_LCORE; i++)\n+\t\tcount += lcore_states[i].is_service_core;\n+\treturn count;\n+}\n+\n+int32_t\n+rte_service_lcore_list(uint32_t array[], uint32_t n)\n+{\n+\tuint32_t count = rte_service_lcore_count();\n+\tif (count > n)\n+\t\treturn -ENOMEM;\n+\n+\tif (!array)\n+\t\treturn -EINVAL;\n+\n+\tuint32_t i;\n+\tuint32_t idx = 0;\n+\tfor (i = 0; i < RTE_MAX_LCORE; i++) {\n+\t\tstruct core_state *cs = &lcore_states[i];\n+\t\tif (cs->is_service_core) {\n+\t\t\tarray[idx] = i;\n+\t\t\tidx++;\n+\t\t}\n+\t}\n+\n+\treturn count;\n+}\n+\n+int32_t\n+rte_service_start_with_defaults(void)\n+{\n+\t/* create a default mapping from cores to services, then start the\n+\t * services to make them transparent to unaware applications.\n+\t */\n+\tuint32_t i;\n+\tint ret;\n+\tuint32_t count = rte_service_get_count();\n+\n+\tint32_t lcore_iter = 0;\n+\tuint32_t ids[RTE_MAX_LCORE];\n+\tint32_t lcore_count = rte_service_lcore_list(ids, RTE_MAX_LCORE);\n+\n+\tif (lcore_count == 0)\n+\t\treturn -ENOTSUP;\n+\n+\tfor (i = 0; (int)i < lcore_count; i++)\n+\t\trte_service_lcore_start(ids[i]);\n+\n+\tfor (i = 0; i < count; i++) {\n+\t\tstruct rte_service_spec *s = rte_service_get_by_id(i);\n+\t\tif (!s)\n+\t\t\treturn -EINVAL;\n+\n+\t\t/* do 1:1 core mapping here, with each service getting\n+\t\t * assigned a single core by default. Adding multiple services\n+\t\t * should multiplex to a single core, or 1:1 if there are the\n+\t\t * same amount of services as service-cores\n+\t\t */\n+\t\tret = rte_service_enable_on_lcore(s, ids[lcore_iter]);\n+\t\tif (ret)\n+\t\t\treturn -ENODEV;\n+\n+\t\tlcore_iter++;\n+\t\tif (lcore_iter >= lcore_count)\n+\t\t\tlcore_iter = 0;\n+\n+\t\tret = rte_service_start(s);\n+\t\tif (ret)\n+\t\t\treturn -ENOEXEC;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int32_t\n+service_update(struct rte_service_spec *service, uint32_t lcore,\n+\t\tuint32_t *set, uint32_t *enabled)\n+{\n+\tuint32_t i;\n+\tint32_t sid = -1;\n+\n+\tfor (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {\n+\t\tif ((struct rte_service_spec *)&rte_services[i] == service &&\n+\t\t\t\tservice_valid(i)) {\n+\t\t\tsid = i;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\tif (sid == -1 || lcore >= RTE_MAX_LCORE)\n+\t\treturn -EINVAL;\n+\n+\tif (!lcore_states[lcore].is_service_core)\n+\t\treturn -EINVAL;\n+\n+\tif (set) {\n+\t\tif (*set) {\n+\t\t\tlcore_states[lcore].service_mask |=  (1 << sid);\n+\t\t\trte_services[sid].num_mapped_cores++;\n+\t\t} else {\n+\t\t\tlcore_states[lcore].service_mask &= ~(1 << sid);\n+\t\t\trte_services[sid].num_mapped_cores--;\n+\t\t}\n+\t}\n+\n+\tif (enabled)\n+\t\t*enabled = (lcore_states[lcore].service_mask & (1 << sid));\n+\n+\trte_smp_wmb();\n+\n+\treturn 0;\n+}\n+\n+int32_t rte_service_get_enabled_on_lcore(struct rte_service_spec *service,\n+\t\t\t\t\tuint32_t lcore)\n+{\n+\tuint32_t enabled;\n+\tint ret = service_update(service, lcore, 0, &enabled);\n+\tif (ret == 0)\n+\t\treturn enabled;\n+\treturn -EINVAL;\n+}\n+\n+int32_t\n+rte_service_enable_on_lcore(struct rte_service_spec *service, uint32_t lcore)\n+{\n+\tuint32_t on = 1;\n+\treturn service_update(service, lcore, &on, 0);\n+}\n+\n+int32_t\n+rte_service_disable_on_lcore(struct rte_service_spec *service, uint32_t lcore)\n+{\n+\tuint32_t off = 0;\n+\treturn service_update(service, lcore, &off, 0);\n+}\n+\n+int32_t rte_service_lcore_reset_all(void)\n+{\n+\t/* loop over cores, reset all to mask 0 */\n+\tuint32_t i;\n+\tfor (i = 0; i < RTE_MAX_LCORE; i++) {\n+\t\tlcore_states[i].service_mask = 0;\n+\t\tlcore_states[i].is_service_core = 0;\n+\t\tlcore_states[i].runstate = RUNSTATE_STOPPED;\n+\t}\n+\tfor (i = 0; i < RTE_SERVICE_NUM_MAX; i++)\n+\t\trte_services[i].num_mapped_cores = 0;\n+\n+\trte_smp_wmb();\n+\n+\treturn 0;\n+}\n+\n+static void\n+set_lcore_state(uint32_t lcore, int32_t state)\n+{\n+\t/* mark core state in hugepage backed config */\n+\tstruct rte_config *cfg = rte_eal_get_configuration();\n+\tcfg->lcore_role[lcore] = state;\n+\n+\t/* mark state in process local lcore_config */\n+\tlcore_config[lcore].core_role = state;\n+\n+\t/* update per-lcore optimized state tracking */\n+\tlcore_states[lcore].is_service_core = (state == ROLE_SERVICE);\n+}\n+\n+int32_t\n+rte_service_lcore_add(uint32_t lcore)\n+{\n+\tif (lcore >= RTE_MAX_LCORE)\n+\t\treturn -EINVAL;\n+\tif (lcore_states[lcore].is_service_core)\n+\t\treturn -EALREADY;\n+\n+\tset_lcore_state(lcore, ROLE_SERVICE);\n+\n+\t/* ensure that after adding a core the mask and state are defaults */\n+\tlcore_states[lcore].service_mask = 0;\n+\tlcore_states[lcore].runstate = RUNSTATE_STOPPED;\n+\n+\trte_smp_wmb();\n+\treturn 0;\n+}\n+\n+int32_t\n+rte_service_lcore_del(uint32_t lcore)\n+{\n+\tif (lcore >= RTE_MAX_LCORE)\n+\t\treturn -EINVAL;\n+\n+\tstruct core_state *cs = &lcore_states[lcore];\n+\tif (!cs->is_service_core)\n+\t\treturn -EINVAL;\n+\n+\tif (cs->runstate != RUNSTATE_STOPPED)\n+\t\treturn -EBUSY;\n+\n+\tset_lcore_state(lcore, ROLE_RTE);\n+\n+\trte_smp_wmb();\n+\treturn 0;\n+}\n+\n+int32_t\n+rte_service_lcore_start(uint32_t lcore)\n+{\n+\tif (lcore >= RTE_MAX_LCORE)\n+\t\treturn -EINVAL;\n+\n+\tstruct core_state *cs = &lcore_states[lcore];\n+\tif (!cs->is_service_core)\n+\t\treturn -EINVAL;\n+\n+\tif (cs->runstate == RUNSTATE_RUNNING)\n+\t\treturn -EALREADY;\n+\n+\t/* set core to run state first, and then launch otherwise it will\n+\t * return immediately as runstate keeps it in the service poll loop\n+\t */\n+\tlcore_states[lcore].runstate = RUNSTATE_RUNNING;\n+\n+\tint ret = rte_eal_remote_launch(rte_service_runner_func, 0, lcore);\n+\t/* returns -EBUSY if the core is already launched, 0 on success */\n+\treturn ret;\n+}\n+\n+int32_t\n+rte_service_lcore_stop(uint32_t lcore)\n+{\n+\tif (lcore >= RTE_MAX_LCORE)\n+\t\treturn -EINVAL;\n+\n+\tif (lcore_states[lcore].runstate == RUNSTATE_STOPPED)\n+\t\treturn -EALREADY;\n+\n+\tuint32_t i;\n+\tfor (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {\n+\t\tint32_t enabled = lcore_states[i].service_mask & (1 << i);\n+\t\tint32_t service_running = rte_services[i].runstate !=\n+\t\t\t\t\t\tRUNSTATE_STOPPED;\n+\t\tint32_t only_core = rte_services[i].num_mapped_cores == 1;\n+\n+\t\t/* if the core is mapped, and the service is running, and this\n+\t\t * is the only core that is mapped, the service would cease to\n+\t\t * run if this core stopped, so fail instead.\n+\t\t */\n+\t\tif (enabled && service_running && only_core)\n+\t\t\treturn -EBUSY;\n+\t}\n+\n+\tlcore_states[lcore].runstate = RUNSTATE_STOPPED;\n+\n+\treturn 0;\n+}\n+\n+static void\n+rte_service_dump_one(FILE *f, struct rte_service_spec_impl *s,\n+\t\t     uint64_t all_cycles, uint32_t reset)\n+{\n+\t/* avoid divide by zero */\n+\tif (all_cycles == 0)\n+\t\tall_cycles = 1;\n+\n+\tint calls = 1;\n+\tif (s->calls != 0)\n+\t\tcalls = s->calls;\n+\n+\tfprintf(f, \"  %s: stats %d\\tcalls %\"PRIu64\"\\tcycles %\"\n+\t\t\tPRIu64\"\\tavg: %\"PRIu64\"\\n\",\n+\t\t\ts->spec.name, service_stats_enabled(s), s->calls,\n+\t\t\ts->cycles_spent, s->cycles_spent / calls);\n+\n+\tif (reset) {\n+\t\ts->cycles_spent = 0;\n+\t\ts->calls = 0;\n+\t}\n+}\n+\n+static void\n+service_dump_calls_per_lcore(FILE *f, uint32_t lcore, uint32_t reset)\n+{\n+\tuint32_t i;\n+\tstruct core_state *cs = &lcore_states[lcore];\n+\n+\tfprintf(f, \"%02d\\t\", lcore);\n+\tfor (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {\n+\t\tif (!service_valid(i))\n+\t\t\tcontinue;\n+\t\tfprintf(f, \"%\"PRIu64\"\\t\", cs->calls_per_service[i]);\n+\t\tif (reset)\n+\t\t\tcs->calls_per_service[i] = 0;\n+\t}\n+\tfprintf(f, \"\\n\");\n+}\n+\n+int32_t rte_service_dump(FILE *f, struct rte_service_spec *service)\n+{\n+\tuint32_t i;\n+\n+\tuint64_t total_cycles = 0;\n+\tfor (i = 0; i < rte_service_count; i++) {\n+\t\tif (!service_valid(i))\n+\t\t\tcontinue;\n+\t\ttotal_cycles += rte_services[i].cycles_spent;\n+\t}\n+\n+\tif (service) {\n+\t\tstruct rte_service_spec_impl *s =\n+\t\t\t(struct rte_service_spec_impl *)service;\n+\t\tfprintf(f, \"Service %s Summary\\n\", s->spec.name);\n+\t\tuint32_t reset = 0;\n+\t\trte_service_dump_one(f, s, total_cycles, reset);\n+\t\treturn 0;\n+\t}\n+\n+\tfprintf(f, \"Services Summary\\n\");\n+\tfor (i = 0; i < rte_service_count; i++) {\n+\t\tuint32_t reset = 1;\n+\t\trte_service_dump_one(f, &rte_services[i], total_cycles, reset);\n+\t}\n+\n+\tfprintf(f, \"Service Cores Summary\\n\");\n+\tfor (i = 0; i < RTE_MAX_LCORE; i++) {\n+\t\tif (lcore_config[i].core_role != ROLE_SERVICE)\n+\t\t\tcontinue;\n+\n+\t\tuint32_t reset = 0;\n+\t\tservice_dump_calls_per_lcore(f, i, reset);\n+\t}\n+\n+\treturn 0;\n+}\ndiff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile\nindex 8651e27..e6ab6c3 100644\n--- a/lib/librte_eal/linuxapp/eal/Makefile\n+++ b/lib/librte_eal/linuxapp/eal/Makefile\n@@ -99,6 +99,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += rte_malloc.c\n SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += malloc_elem.c\n SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += malloc_heap.c\n SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += rte_keepalive.c\n+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += rte_service.c\n \n # from arch dir\n SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += rte_cpuflags.c\ndiff --git a/lib/librte_eal/linuxapp/eal/eal_thread.c b/lib/librte_eal/linuxapp/eal/eal_thread.c\nindex 9f88530..831ba07 100644\n--- a/lib/librte_eal/linuxapp/eal/eal_thread.c\n+++ b/lib/librte_eal/linuxapp/eal/eal_thread.c\n@@ -184,7 +184,14 @@ eal_thread_loop(__attribute__((unused)) void *arg)\n \t\tret = lcore_config[lcore_id].f(fct_arg);\n \t\tlcore_config[lcore_id].ret = ret;\n \t\trte_wmb();\n-\t\tlcore_config[lcore_id].state = FINISHED;\n+\n+\t\t/* when a service core returns, it should go directly to WAIT\n+\t\t * state, because the application will not lcore_wait() for it.\n+\t\t */\n+\t\tif (lcore_config[lcore_id].core_role == ROLE_SERVICE)\n+\t\t\tlcore_config[lcore_id].state = WAIT;\n+\t\telse\n+\t\t\tlcore_config[lcore_id].state = FINISHED;\n \t}\n \n \t/* never reached */\ndiff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map\nindex 0f9e009..fbaec39 100644\n--- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map\n+++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map\n@@ -214,5 +214,28 @@ EXPERIMENTAL {\n \trte_eal_devargs_parse;\n \trte_eal_hotplug_add;\n \trte_eal_hotplug_remove;\n+\trte_service_disable_on_lcore;\n+\trte_service_dump;\n+\trte_service_enable_on_lcore;\n+\trte_service_get_by_id;\n+\trte_service_get_by_name;\n+\trte_service_get_count;\n+\trte_service_get_enabled_on_lcore;\n+\trte_service_is_running;\n+\trte_service_lcore_add;\n+\trte_service_lcore_count;\n+\trte_service_lcore_del;\n+\trte_service_lcore_list;\n+\trte_service_lcore_reset_all;\n+\trte_service_lcore_start;\n+\trte_service_lcore_stop;\n+\trte_service_probe_capability;\n+\trte_service_register;\n+\trte_service_reset;\n+\trte_service_set_stats_enable;\n+\trte_service_start;\n+\trte_service_start_with_defaults;\n+\trte_service_stop;\n+\trte_service_unregister;\n \n } DPDK_17.08;\n",
    "prefixes": [
        "dpdk-dev",
        "v5",
        "1/7"
    ]
}