get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 96464,
    "url": "https://patches.dpdk.org/api/patches/96464/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/20210730135533.417611-5-thomas@monjalon.net/",
    "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": "<20210730135533.417611-5-thomas@monjalon.net>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20210730135533.417611-5-thomas@monjalon.net",
    "date": "2021-07-30T13:55:30",
    "name": "[RFC,v2,4/7] hcdev: support multi-process",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "1dcec72bb75a749c38b9f2595844fda846d22a29",
    "submitter": {
        "id": 685,
        "url": "https://patches.dpdk.org/api/people/685/?format=api",
        "name": "Thomas Monjalon",
        "email": "thomas@monjalon.net"
    },
    "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/20210730135533.417611-5-thomas@monjalon.net/mbox/",
    "series": [
        {
            "id": 18101,
            "url": "https://patches.dpdk.org/api/series/18101/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=18101",
            "date": "2021-07-30T13:55:26",
            "name": "heterogeneous computing library",
            "version": 2,
            "mbox": "https://patches.dpdk.org/series/18101/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/96464/comments/",
    "check": "success",
    "checks": "https://patches.dpdk.org/api/patches/96464/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 00656A0A0C;\n\tFri, 30 Jul 2021 15:56:26 +0200 (CEST)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id E102E40042;\n\tFri, 30 Jul 2021 15:56:26 +0200 (CEST)",
            "from new3-smtp.messagingengine.com (new3-smtp.messagingengine.com\n [66.111.4.229]) by mails.dpdk.org (Postfix) with ESMTP id B828B40042\n for <dev@dpdk.org>; Fri, 30 Jul 2021 15:56:24 +0200 (CEST)",
            "from compute6.internal (compute6.nyi.internal [10.202.2.46])\n by mailnew.nyi.internal (Postfix) with ESMTP id 2E950580B58;\n Fri, 30 Jul 2021 09:56:24 -0400 (EDT)",
            "from mailfrontend1 ([10.202.2.162])\n by compute6.internal (MEProxy); Fri, 30 Jul 2021 09:56:24 -0400",
            "by mail.messagingengine.com (Postfix) with ESMTPA; Fri,\n 30 Jul 2021 09:56:20 -0400 (EDT)"
        ],
        "DKIM-Signature": [
            "v=1; a=rsa-sha256; c=relaxed/relaxed; d=monjalon.net; h=\n from:to:cc:subject:date:message-id:in-reply-to:references\n :mime-version:content-transfer-encoding; s=fm1; bh=2OM+Tyxhvm5/2\n ES2ktr/06yWh18g26sBU2kMwzlPuUM=; b=d2NR46AdcvxT3Vk3gw5GqPsA4yfEO\n DYktMPeb8Z2XeBs/yg9Ex3yxdEL7Cr4qSC/DGwTf7PFqgrJmWJTWhaL28ueJ6ZA+\n yQ8+dNxPhC2CGq2v45nBhZoPW8SHtbAgXauh/CPVy9yywJxUiyktHIf5apbS/ZKE\n /9962pg9PDN/cXu+7FSLfKDCBvBOIswRess9xNd7lMmNtggk+dmXjsc1onX0iwXe\n sU8tB7QrwCVQzQDc9K9L85g66uSVCHB5MeoQL6RphbR4M0I/E/ERDDgf2rrkoxe9\n FJaBLz7+LBhtNKegE+jN4QkseQpouFuftXRFIVg1NBUEc8IxwmvowepTQ==",
            "v=1; a=rsa-sha256; c=relaxed/relaxed; d=\n messagingengine.com; h=cc:content-transfer-encoding:date:from\n :in-reply-to:message-id:mime-version:references:subject:to\n :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=\n fm3; bh=2OM+Tyxhvm5/2ES2ktr/06yWh18g26sBU2kMwzlPuUM=; b=ORivtDnJ\n ClvyoMgUYggQQQXpVnHUtIXnA3gnGuRItFIX1vgkQ33n8PPtvBCgEobodhyu4v5f\n dQQkvJ6w6i4HhtZ+5MdqLtgXVZS2Pxbnvvn86xClSljMYpLyDhfaESeKwPiXCyir\n Dt02fAcjjQxl1S30RwXOQdsc4C802wFb5g7oy1/eF/mRtxjpukEbyBEd1V4ZQ2D6\n Sjh0ku2AXmVYuc0wOJh4VkPre+DyUObrfnitjrNLizhEisl8pIOU8+AOrSn+6N2W\n XOq9Hh8btw6kGOPA4M9zhuIsC2ChXCrXamk34LpX2BIxBvg/d3TEQBRsjQom+JHV\n S8fyTeKZlEcmSQ=="
        ],
        "X-ME-Sender": "<xms:BgUEYYTsEZYOLgODldTlMkp_p7evwyahbFnJ5mdWLst3IuaU9qHiXA>\n <xme:BgUEYVxoxsnU-40A_MxvsrfOuSci0sPaiMUoPNV_5tfvagxtQq9HluhFmDWdDzZ0z\n hIflVDbQxudUoJ_Wg>",
        "X-ME-Received": "\n <xmr:BgUEYV1vbR_xL3uGwBAEm-N7sBDnYMu08uKj5Z0sDhWxB6x1_rnYIJT6C9Jn2SrWPUxVui8OOW4pGyrRmbsh49rmx2EHywo>",
        "X-ME-Proxy-Cause": "\n gggruggvucftvghtrhhoucdtuddrgedvtddrheehgdeijecutefuodetggdotefrodftvf\n curfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfghnecu\n uegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenuc\n fjughrpefhvffufffkofgjfhgggfestdekredtredttdenucfhrhhomhepvfhhohhmrghs\n ucfoohhnjhgrlhhonhcuoehthhhomhgrshesmhhonhhjrghlohhnrdhnvghtqeenucggtf\n frrghtthgvrhhnpedvhefgiedvjeegtdevheefhfetleefgfeivefgffevfeejgedtgfeu\n tdehtdegveenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhroh\n hmpehthhhomhgrshesmhhonhhjrghlohhnrdhnvght",
        "X-ME-Proxy": "<xmx:BgUEYcBkRUiGcQfTsEOI7WdxA69Au9VEWXady_sKFjPt21MHZlbBIw>\n <xmx:BgUEYRgqVLslAo7I2VJpGJLnzIQCNLVFAkJzZq7yvO4dyWBvKx2Fbw>\n <xmx:BgUEYYoYrn8lvPyJtcsNahp0rAlWCvNBKTvLeVVTwUQN-Z7RkhJo0g>\n <xmx:CAUEYYM1fajaxlAXtnBoBfSo7Hbn8pEtiyNPnt0iv-dnCjPL6roaOw>",
        "From": "Thomas Monjalon <thomas@monjalon.net>",
        "To": "dev@dpdk.org",
        "Cc": "Stephen Hemminger <stephen@networkplumber.org>,\n David Marchand <david.marchand@redhat.com>,\n Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>,\n Haiyue Wang <haiyue.wang@intel.com>,\n Honnappa Nagarahalli <honnappa.nagarahalli@arm.com>,\n Jerin Jacob <jerinj@marvell.com>, Ferruh Yigit <ferruh.yigit@intel.com>,\n Elena Agostini <eagostini@nvidia.com>, Ray Kinsella <mdr@ashroe.eu>,\n Anatoly Burakov <anatoly.burakov@intel.com>",
        "Date": "Fri, 30 Jul 2021 15:55:30 +0200",
        "Message-Id": "<20210730135533.417611-5-thomas@monjalon.net>",
        "X-Mailer": "git-send-email 2.31.1",
        "In-Reply-To": "<20210730135533.417611-1-thomas@monjalon.net>",
        "References": "<20210602203531.2288645-1-thomas@monjalon.net>\n <20210730135533.417611-1-thomas@monjalon.net>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[dpdk-dev] [RFC PATCH v2 4/7] hcdev: support multi-process",
        "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",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "The device data shared between processes are moved in a struct\nallocated in a shared memory (a new memzone for all hcdevs).\nThe main struct rte_hcdev references the shared memory\nvia the pointer mpshared.\n\nThe API function rte_hcdev_attach() is added to attach a device\nfrom the secondary process.\nThe function rte_hcdev_allocate() can be used only by primary process.\n\nSigned-off-by: Thomas Monjalon <thomas@monjalon.net>\n---\n lib/hcdev/hcdev.c        | 114 ++++++++++++++++++++++++++++++++-------\n lib/hcdev/hcdev_driver.h |  23 ++++++--\n lib/hcdev/rte_hcdev.h    |   3 +-\n lib/hcdev/version.map    |   1 +\n 4 files changed, 115 insertions(+), 26 deletions(-)",
    "diff": "diff --git a/lib/hcdev/hcdev.c b/lib/hcdev/hcdev.c\nindex d40010749a..a7badd122b 100644\n--- a/lib/hcdev/hcdev.c\n+++ b/lib/hcdev/hcdev.c\n@@ -5,6 +5,7 @@\n #include <rte_eal.h>\n #include <rte_tailq.h>\n #include <rte_string_fns.h>\n+#include <rte_memzone.h>\n #include <rte_errno.h>\n #include <rte_log.h>\n \n@@ -28,6 +29,12 @@ static int16_t hcdev_max;\n /* Number of currently valid devices */\n static int16_t hcdev_count;\n \n+/* Shared memory between processes. */\n+static const char *HCDEV_MEMZONE = \"rte_hcdev_shared\";\n+static struct {\n+\t__extension__ struct rte_hcdev_mpshared hcdevs[0];\n+} *hcdev_shared_mem;\n+\n /* Event callback object */\n struct rte_hcdev_callback {\n \tTAILQ_ENTRY(rte_hcdev_callback) next;\n@@ -40,6 +47,8 @@ static void hcdev_free_callbacks(struct rte_hcdev *dev);\n int\n rte_hcdev_init(size_t dev_max)\n {\n+\tconst struct rte_memzone *memzone;\n+\n \tif (dev_max == 0 || dev_max > INT16_MAX) {\n \t\tHCDEV_LOG(ERR, \"invalid array size\");\n \t\trte_errno = EINVAL;\n@@ -60,6 +69,23 @@ rte_hcdev_init(size_t dev_max)\n \t\treturn -rte_errno;\n \t}\n \n+\tif (rte_eal_process_type() == RTE_PROC_PRIMARY) {\n+\t\tmemzone = rte_memzone_reserve(HCDEV_MEMZONE,\n+\t\t\t\tsizeof(*hcdev_shared_mem) +\n+\t\t\t\tsizeof(*hcdev_shared_mem->hcdevs) * dev_max,\n+\t\t\t\tSOCKET_ID_ANY, 0);\n+\t} else {\n+\t\tmemzone = rte_memzone_lookup(HCDEV_MEMZONE);\n+\t}\n+\tif (memzone == NULL) {\n+\t\tHCDEV_LOG(ERR, \"cannot initialize shared memory\");\n+\t\tfree(hcdevs);\n+\t\thcdevs = NULL;\n+\t\trte_errno = ENOMEM;\n+\t\treturn -rte_errno;\n+\t}\n+\thcdev_shared_mem = memzone->addr;\n+\n \thcdev_max = dev_max;\n \treturn 0;\n }\n@@ -74,7 +100,7 @@ bool\n rte_hcdev_is_valid(int16_t dev_id)\n {\n \tif (dev_id >= 0 && dev_id < hcdev_max &&\n-\t\thcdevs[dev_id].state == RTE_HCDEV_STATE_INITIALIZED)\n+\t\thcdevs[dev_id].process_state == RTE_HCDEV_STATE_INITIALIZED)\n \t\treturn true;\n \treturn false;\n }\n@@ -84,7 +110,7 @@ hcdev_match_parent(int16_t dev_id, int16_t parent)\n {\n \tif (parent == RTE_HCDEV_ID_ANY)\n \t\treturn true;\n-\treturn hcdevs[dev_id].info.parent == parent;\n+\treturn hcdevs[dev_id].mpshared->info.parent == parent;\n }\n \n int16_t\n@@ -93,7 +119,7 @@ rte_hcdev_find_next(int16_t dev_id, int16_t parent)\n \tif (dev_id < 0)\n \t\tdev_id = 0;\n \twhile (dev_id < hcdev_max &&\n-\t\t\t(hcdevs[dev_id].state == RTE_HCDEV_STATE_UNUSED ||\n+\t\t\t(hcdevs[dev_id].process_state == RTE_HCDEV_STATE_UNUSED ||\n \t\t\t!hcdev_match_parent(dev_id, parent)))\n \t\tdev_id++;\n \n@@ -108,7 +134,7 @@ hcdev_find_free_id(void)\n \tint16_t dev_id;\n \n \tfor (dev_id = 0; dev_id < hcdev_max; dev_id++) {\n-\t\tif (hcdevs[dev_id].state == RTE_HCDEV_STATE_UNUSED)\n+\t\tif (hcdevs[dev_id].process_state == RTE_HCDEV_STATE_UNUSED)\n \t\t\treturn dev_id;\n \t}\n \treturn RTE_HCDEV_ID_NONE;\n@@ -135,7 +161,7 @@ rte_hcdev_get_by_name(const char *name)\n \n \tRTE_HCDEV_FOREACH(dev_id) {\n \t\tdev = &hcdevs[dev_id];\n-\t\tif (strncmp(name, dev->name, RTE_DEV_NAME_MAX_LEN) == 0)\n+\t\tif (strncmp(name, dev->mpshared->name, RTE_DEV_NAME_MAX_LEN) == 0)\n \t\t\treturn dev;\n \t}\n \treturn NULL;\n@@ -177,16 +203,20 @@ rte_hcdev_allocate(const char *name)\n \tdev = &hcdevs[dev_id];\n \tmemset(dev, 0, sizeof(*dev));\n \n-\tif (rte_strscpy(dev->name, name, RTE_DEV_NAME_MAX_LEN) < 0) {\n+\tdev->mpshared = &hcdev_shared_mem->hcdevs[dev_id];\n+\tmemset(dev->mpshared, 0, sizeof(*dev->mpshared));\n+\n+\tif (rte_strscpy(dev->mpshared->name, name, RTE_DEV_NAME_MAX_LEN) < 0) {\n \t\tHCDEV_LOG(ERR, \"device name too long: %s\", name);\n \t\trte_errno = ENAMETOOLONG;\n \t\treturn NULL;\n \t}\n-\tdev->info.name = dev->name;\n-\tdev->info.dev_id = dev_id;\n-\tdev->info.numa_node = -1;\n-\tdev->info.parent = RTE_HCDEV_ID_NONE;\n+\tdev->mpshared->info.name = dev->mpshared->name;\n+\tdev->mpshared->info.dev_id = dev_id;\n+\tdev->mpshared->info.numa_node = -1;\n+\tdev->mpshared->info.parent = RTE_HCDEV_ID_NONE;\n \tTAILQ_INIT(&dev->callbacks);\n+\t__atomic_fetch_add(&dev->mpshared->process_refcnt, 1, __ATOMIC_RELAXED);\n \n \thcdev_count++;\n \tHCDEV_LOG(DEBUG, \"new device %s (id %d) of total %d\",\n@@ -194,6 +224,51 @@ rte_hcdev_allocate(const char *name)\n \treturn dev;\n }\n \n+struct rte_hcdev *\n+rte_hcdev_attach(const char *name)\n+{\n+\tint16_t dev_id;\n+\tstruct rte_hcdev *dev;\n+\tstruct rte_hcdev_mpshared *shared_dev;\n+\n+\tif (rte_eal_process_type() != RTE_PROC_SECONDARY) {\n+\t\tHCDEV_LOG(ERR, \"only secondary process can attach device\");\n+\t\trte_errno = EPERM;\n+\t\treturn NULL;\n+\t}\n+\tif (name == NULL) {\n+\t\tHCDEV_LOG(ERR, \"attach device without a name\");\n+\t\trte_errno = EINVAL;\n+\t\treturn NULL;\n+\t}\n+\n+\t/* implicit initialization of library before adding first device */\n+\tif (hcdevs == NULL && rte_hcdev_init(RTE_HCDEV_DEFAULT_MAX) < 0)\n+\t\treturn NULL;\n+\n+\tfor (dev_id = 0; dev_id < hcdev_max; dev_id++) {\n+\t\tshared_dev = &hcdev_shared_mem->hcdevs[dev_id];\n+\t\tif (strncmp(name, shared_dev->name, RTE_DEV_NAME_MAX_LEN) == 0)\n+\t\t\tbreak;\n+\t}\n+\tif (dev_id >= hcdev_max) {\n+\t\tHCDEV_LOG(ERR, \"device with name %s not found\", name);\n+\t\trte_errno = ENOENT;\n+\t\treturn NULL;\n+\t}\n+\tdev = &hcdevs[dev_id];\n+\tmemset(dev, 0, sizeof(*dev));\n+\n+\tTAILQ_INIT(&dev->callbacks);\n+\tdev->mpshared = shared_dev;\n+\t__atomic_fetch_add(&dev->mpshared->process_refcnt, 1, __ATOMIC_RELAXED);\n+\n+\thcdev_count++;\n+\tHCDEV_LOG(DEBUG, \"attached device %s (id %d) of total %d\",\n+\t\t\tname, dev_id, hcdev_count);\n+\treturn dev;\n+}\n+\n int16_t\n rte_hcdev_add_child(const char *name, int16_t parent, uint64_t child_context)\n {\n@@ -209,11 +284,11 @@ rte_hcdev_add_child(const char *name, int16_t parent, uint64_t child_context)\n \tif (dev == NULL)\n \t\treturn -rte_errno;\n \n-\tdev->info.parent = parent;\n-\tdev->info.context = child_context;\n+\tdev->mpshared->info.parent = parent;\n+\tdev->mpshared->info.context = child_context;\n \n \trte_hcdev_complete_new(dev);\n-\treturn dev->info.dev_id;\n+\treturn dev->mpshared->info.dev_id;\n }\n \n void\n@@ -222,7 +297,7 @@ rte_hcdev_complete_new(struct rte_hcdev *dev)\n \tif (dev == NULL)\n \t\treturn;\n \n-\tdev->state = RTE_HCDEV_STATE_INITIALIZED;\n+\tdev->process_state = RTE_HCDEV_STATE_INITIALIZED;\n \trte_hcdev_notify(dev, RTE_HCDEV_EVENT_NEW);\n }\n \n@@ -235,7 +310,7 @@ rte_hcdev_release(struct rte_hcdev *dev)\n \t\trte_errno = ENODEV;\n \t\treturn -rte_errno;\n \t}\n-\tdev_id = dev->info.dev_id;\n+\tdev_id = dev->mpshared->info.dev_id;\n \tRTE_HCDEV_FOREACH_CHILD(child, dev_id) {\n \t\tHCDEV_LOG(ERR, \"cannot release device %d with child %d\",\n \t\t\t\tdev_id, child);\n@@ -244,11 +319,12 @@ rte_hcdev_release(struct rte_hcdev *dev)\n \t}\n \n \tHCDEV_LOG(DEBUG, \"free device %s (id %d)\",\n-\t\t\tdev->info.name, dev->info.dev_id);\n+\t\t\tdev->mpshared->info.name, dev->mpshared->info.dev_id);\n \trte_hcdev_notify(dev, RTE_HCDEV_EVENT_DEL);\n \n \thcdev_free_callbacks(dev);\n-\tdev->state = RTE_HCDEV_STATE_UNUSED;\n+\tdev->process_state = RTE_HCDEV_STATE_UNUSED;\n+\t__atomic_fetch_sub(&dev->mpshared->process_refcnt, 1, __ATOMIC_RELAXED);\n \thcdev_count--;\n \n \treturn 0;\n@@ -394,7 +470,7 @@ rte_hcdev_notify(struct rte_hcdev *dev, enum rte_hcdev_event event)\n \tint16_t dev_id;\n \tstruct rte_hcdev_callback *callback;\n \n-\tdev_id = dev->info.dev_id;\n+\tdev_id = dev->mpshared->info.dev_id;\n \tTAILQ_FOREACH(callback, &dev->callbacks, next) {\n \t\tif (callback->event != event || callback->function == NULL)\n \t\t\tcontinue;\n@@ -420,7 +496,7 @@ rte_hcdev_info_get(int16_t dev_id, struct rte_hcdev_info *info)\n \t}\n \n \tif (dev->ops.dev_info_get == NULL) {\n-\t\t*info = dev->info;\n+\t\t*info = dev->mpshared->info;\n \t\treturn 0;\n \t}\n \treturn HCDEV_DRV_RET(dev->ops.dev_info_get(dev, info));\ndiff --git a/lib/hcdev/hcdev_driver.h b/lib/hcdev/hcdev_driver.h\nindex 39f6fc57ab..f33b56947b 100644\n--- a/lib/hcdev/hcdev_driver.h\n+++ b/lib/hcdev/hcdev_driver.h\n@@ -35,19 +35,28 @@ struct rte_hcdev_ops {\n \trte_hcdev_close_t *dev_close;\n };\n \n-struct rte_hcdev {\n-\t/* Backing device. */\n-\tstruct rte_device *device;\n+struct rte_hcdev_mpshared {\n \t/* Unique identifier name. */\n \tchar name[RTE_DEV_NAME_MAX_LEN]; /* Updated by this library. */\n+\t/* Driver-specific private data shared in multi-process. */\n+\tvoid *dev_private;\n \t/* Device info structure. */\n \tstruct rte_hcdev_info info;\n+\t/* Counter of processes using the device. */\n+\tuint16_t process_refcnt; /* Updated by this library. */\n+};\n+\n+struct rte_hcdev {\n+\t/* Backing device. */\n+\tstruct rte_device *device;\n+\t/* Data shared between processes. */\n+\tstruct rte_hcdev_mpshared *mpshared;\n \t/* Driver functions. */\n \tstruct rte_hcdev_ops ops;\n \t/* Event callback list. */\n \tTAILQ_HEAD(rte_hcdev_callback_list, rte_hcdev_callback) callbacks;\n \t/* Current state (used or not) in the running process. */\n-\tenum rte_hcdev_state state; /* Updated by this library. */\n+\tenum rte_hcdev_state process_state; /* Updated by this library. */\n \t/* Driver-specific private data for the running process. */\n \tvoid *process_private;\n } __rte_cache_aligned;\n@@ -55,10 +64,14 @@ struct rte_hcdev {\n __rte_internal\n struct rte_hcdev *rte_hcdev_get_by_name(const char *name);\n \n-/* First step of initialization */\n+/* First step of initialization in primary process. */\n __rte_internal\n struct rte_hcdev *rte_hcdev_allocate(const char *name);\n \n+/* First step of initialization in secondary process. */\n+__rte_internal\n+struct rte_hcdev *rte_hcdev_attach(const char *name);\n+\n /* Last step of initialization. */\n __rte_internal\n void rte_hcdev_complete_new(struct rte_hcdev *dev);\ndiff --git a/lib/hcdev/rte_hcdev.h b/lib/hcdev/rte_hcdev.h\nindex 518020fd2f..c95f37063d 100644\n--- a/lib/hcdev/rte_hcdev.h\n+++ b/lib/hcdev/rte_hcdev.h\n@@ -15,9 +15,8 @@\n  * @file\n  * Generic library to interact with heterogeneous computing device.\n  *\n- * The API is not thread-safe.\n- * Device management must be done by a single thread.\n  * TODO device rwlock for callback list\n+ * TODO mp shared rwlock for device array\n  *\n  * @warning\n  * @b EXPERIMENTAL: this API may change without prior notice.\ndiff --git a/lib/hcdev/version.map b/lib/hcdev/version.map\nindex 6d1a1ab1c9..450c256527 100644\n--- a/lib/hcdev/version.map\n+++ b/lib/hcdev/version.map\n@@ -17,6 +17,7 @@ INTERNAL {\n \tglobal:\n \n \trte_hcdev_allocate;\n+\trte_hcdev_attach;\n \trte_hcdev_complete_new;\n \trte_hcdev_get_by_name;\n \trte_hcdev_notify;\n",
    "prefixes": [
        "RFC",
        "v2",
        "4/7"
    ]
}