get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 89419,
    "url": "https://patches.dpdk.org/api/patches/89419/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/1616029240-26588-2-git-send-email-navasile@linux.microsoft.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": "<1616029240-26588-2-git-send-email-navasile@linux.microsoft.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1616029240-26588-2-git-send-email-navasile@linux.microsoft.com",
    "date": "2021-03-18T01:00:38",
    "name": "[1/3] Add EAL threads API",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "d598e6390ebca6412b46130e5e676e39c18759c5",
    "submitter": {
        "id": 1668,
        "url": "https://patches.dpdk.org/api/people/1668/?format=api",
        "name": "Narcisa Ana Maria Vasile",
        "email": "navasile@linux.microsoft.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/1616029240-26588-2-git-send-email-navasile@linux.microsoft.com/mbox/",
    "series": [
        {
            "id": 15749,
            "url": "https://patches.dpdk.org/api/series/15749/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=15749",
            "date": "2021-03-18T01:00:37",
            "name": "eal: Add new API for threading",
            "version": 1,
            "mbox": "https://patches.dpdk.org/series/15749/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/89419/comments/",
    "check": "warning",
    "checks": "https://patches.dpdk.org/api/patches/89419/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 172B3A0561;\n\tThu, 18 Mar 2021 02:01:50 +0100 (CET)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id C5667140FBE;\n\tThu, 18 Mar 2021 02:01:39 +0100 (CET)",
            "from linux.microsoft.com (linux.microsoft.com [13.77.154.182])\n by mails.dpdk.org (Postfix) with ESMTP id 3362040698\n for <dev@dpdk.org>; Thu, 18 Mar 2021 02:01:36 +0100 (CET)",
            "by linux.microsoft.com (Postfix, from userid 1059)\n id 8653C209C373; Wed, 17 Mar 2021 18:01:35 -0700 (PDT)"
        ],
        "DKIM-Filter": "OpenDKIM Filter v2.11.0 linux.microsoft.com 8653C209C373",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com;\n s=default; t=1616029295;\n bh=p+cF3Ojbi6OrNkUObaW8v7kD67Jsi4tWwDOiuwfCnac=;\n h=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n b=STERqIc35ErJit/WXM2bL8LKQiy1Lyoa6LiXcsRtnfxwWlCoYgNj/f0TL7uErFv8K\n WXZKGtKIYF/sH1Yuwl4p0WX07SdNBya044RzNvVnf5F7ltWdYfMI5QADNbzTkHu/oX\n M4XFlD01RLgEiISZtbdI6PT1QUMymnVYsNi1pB4g=",
        "From": "Narcisa Ana Maria Vasile <navasile@linux.microsoft.com>",
        "To": "dev@dpdk.org, thomas@monjalon.net, dmitry.kozliuk@gmail.com,\n khot@microsoft.com, navasile@microsoft.com, dmitrym@microsoft.com,\n roretzla@microsoft.com, ocardona@microsoft.com",
        "Cc": "bruce.richardson@intel.com, david.marchand@redhat.com,\n pallavi.kadam@intel.com",
        "Date": "Wed, 17 Mar 2021 18:00:38 -0700",
        "Message-Id": "<1616029240-26588-2-git-send-email-navasile@linux.microsoft.com>",
        "X-Mailer": "git-send-email 1.8.3.1",
        "In-Reply-To": "<1616029240-26588-1-git-send-email-navasile@linux.microsoft.com>",
        "References": "<1616029240-26588-1-git-send-email-navasile@linux.microsoft.com>",
        "Subject": "[dpdk-dev] [PATCH 1/3] Add EAL threads API",
        "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": "From: Narcisa Vasile <navasile@microsoft.com>\n\nEAL must hide the environment specifics from apps and libraries.\nAdd an EAL API for managing threads.\n\nSigned-off-by: Narcisa Vasile <navasile@microsoft.com>\nSigned-off-by: Dmitry Malloy <dmitrym@microsoft.com>\n---\n lib/librte_eal/common/eal_common_thread.c     |   6 +-\n lib/librte_eal/common/rte_thread.c            | 346 ++++++++++++\n lib/librte_eal/include/rte_thread.h           | 323 ++++++++++-\n lib/librte_eal/include/rte_thread_types.h     |  20 +\n lib/librte_eal/windows/eal_lcore.c            | 167 ++++--\n lib/librte_eal/windows/eal_windows.h          |  10 +\n .../include/rte_windows_thread_types.h        |  19 +\n lib/librte_eal/windows/rte_thread.c           | 507 +++++++++++++++++-\n 8 files changed, 1338 insertions(+), 60 deletions(-)\n create mode 100644 lib/librte_eal/common/rte_thread.c\n create mode 100644 lib/librte_eal/include/rte_thread_types.h\n create mode 100644 lib/librte_eal/windows/include/rte_windows_thread_types.h",
    "diff": "diff --git a/lib/librte_eal/common/eal_common_thread.c b/lib/librte_eal/common/eal_common_thread.c\nindex 73a055902..5219e783e 100644\n--- a/lib/librte_eal/common/eal_common_thread.c\n+++ b/lib/librte_eal/common/eal_common_thread.c\n@@ -84,7 +84,7 @@ thread_update_affinity(rte_cpuset_t *cpusetp)\n }\n \n int\n-rte_thread_set_affinity(rte_cpuset_t *cpusetp)\n+rte_thread_self_set_affinity(rte_cpuset_t *cpusetp)\n {\n \tif (pthread_setaffinity_np(pthread_self(), sizeof(rte_cpuset_t),\n \t\t\tcpusetp) != 0) {\n@@ -97,7 +97,7 @@ rte_thread_set_affinity(rte_cpuset_t *cpusetp)\n }\n \n void\n-rte_thread_get_affinity(rte_cpuset_t *cpusetp)\n+rte_thread_self_get_affinity(rte_cpuset_t *cpusetp)\n {\n \tassert(cpusetp);\n \tmemmove(cpusetp, &RTE_PER_LCORE(_cpuset),\n@@ -140,7 +140,7 @@ eal_thread_dump_current_affinity(char *str, unsigned int size)\n {\n \trte_cpuset_t cpuset;\n \n-\trte_thread_get_affinity(&cpuset);\n+\trte_thread_self_get_affinity(&cpuset);\n \treturn eal_thread_dump_affinity(&cpuset, str, size);\n }\n \ndiff --git a/lib/librte_eal/common/rte_thread.c b/lib/librte_eal/common/rte_thread.c\nnew file mode 100644\nindex 000000000..275876534\n--- /dev/null\n+++ b/lib/librte_eal/common/rte_thread.c\n@@ -0,0 +1,346 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright 2021 Mellanox Technologies, Ltd\n+ * Copyright(c) 2021 Microsoft Corporation\n+ */\n+\n+#include <errno.h>\n+#include <pthread.h>\n+#include <stdlib.h>\n+#include <string.h>\n+\n+#include <rte_common.h>\n+#include <rte_errno.h>\n+#include <rte_log.h>\n+#include <rte_thread.h>\n+\n+struct eal_tls_key {\n+\tpthread_key_t thread_index;\n+};\n+\n+rte_thread_t\n+rte_thread_self(void)\n+{\n+\treturn pthread_self();\n+}\n+\n+int\n+rte_thread_equal(rte_thread_t t1, rte_thread_t t2)\n+{\n+\treturn pthread_equal(t1, t2);\n+}\n+\n+int\n+rte_thread_set_affinity(rte_thread_t thread_id, size_t cpuset_size,\n+\t\t\tconst rte_cpuset_t *cpuset)\n+{\n+\treturn pthread_setaffinity_np(thread_id, cpuset_size, cpuset);\n+}\n+\n+int rte_thread_get_affinity(rte_thread_t threadid, size_t cpuset_size,\n+\t\trte_cpuset_t *cpuset)\n+{\n+\treturn pthread_getaffinity_np(threadid, cpuset_size, cpuset);\n+}\n+\n+int\n+rte_thread_set_priority(rte_thread_t thread_id,\n+\t\tenum rte_thread_priority priority)\n+{\n+\tint policy;\n+\tstruct sched_param param = {\n+\t\t.sched_priority = 0,\n+\t};\n+\n+\n+\tif (priority == RTE_THREAD_PRIORITY_REALTIME_CRITICAL) {\n+\t\tpolicy = SCHED_RR;\n+\t\tparam.sched_priority = priority;\n+\t} else if (priority == RTE_THREAD_PRIORITY_NORMAL) {\n+\t\tpolicy = SCHED_OTHER;\n+\t\tparam.sched_priority = priority;\n+\t} else {\n+\t\tRTE_LOG(DEBUG, EAL, \"Invalid priority to set.\"\n+\t\t\t\t    \"Defaulting to priority 'normal'.\\n\");\n+\t\tpolicy = SCHED_OTHER;\n+\t}\n+\n+\treturn pthread_setschedparam(thread_id, policy, &param);\n+}\n+\n+int\n+rte_thread_attr_init(rte_thread_attr_t *attr)\n+{\n+\tint ret = 0;\n+\tpthread_attr_t pthread_attr;\n+\n+\tif (attr == NULL) {\n+\t\tRTE_LOG(DEBUG, EAL, \"Invalid thread attributes parameter\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tret = pthread_getattr_default_np(&pthread_attr);\n+\tif (ret != 0) {\n+\t\tRTE_LOG(DEBUG, EAL, \"pthread_getattr_default_np failed\\n\");\n+\t\treturn ret;\n+\t}\n+\n+\tret = pthread_attr_getaffinity_np(&pthread_attr, sizeof(attr->cpuset), &attr->cpuset);\n+\tif (ret != 0) {\n+\t\tRTE_LOG(DEBUG, EAL, \"pthread_attr_getaffinity_np failed\\n\");\n+\t\treturn ret;\n+\t}\n+\n+\tattr->priority = RTE_THREAD_PRIORITY_NORMAL;\n+\n+\treturn 0;\n+}\n+\n+int\n+rte_thread_attr_set_affinity(rte_thread_attr_t *thread_attr, rte_cpuset_t *cpuset)\n+{\n+\tif (thread_attr == NULL || cpuset == NULL) {\n+\t\tRTE_LOG(DEBUG, EAL, \"Invalid thread attributes parameter\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\tthread_attr->cpuset = *cpuset;\n+\treturn 0;\n+}\n+\n+int\n+rte_thread_attr_get_affinity(rte_thread_attr_t *thread_attr, rte_cpuset_t *cpuset)\n+{\n+\tif ((thread_attr == NULL) || (cpuset == NULL)) {\n+\t\tRTE_LOG(DEBUG, EAL, \"Invalid thread attributes parameter\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t*cpuset = thread_attr->cpuset;\n+\treturn 0;\n+}\n+\n+int\n+rte_thread_attr_set_priority(rte_thread_attr_t *thread_attr, enum rte_thread_priority priority)\n+{\n+\tif (thread_attr == NULL) {\n+\t\tRTE_LOG(DEBUG, EAL,\n+\t\t\t\"Unable to set priority attribute, invalid parameter\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tthread_attr->priority = priority;\n+\treturn 0;\n+}\n+\n+int\n+rte_thread_create(rte_thread_t *thread_id,\n+\t\t  const rte_thread_attr_t *thread_attr, void *(*thread_func) (void*),\n+\t\t  void *args)\n+{\n+\tint ret = 0;\n+\tpthread_attr_t attr;\n+\tpthread_attr_t *attrp = NULL;\n+\tstruct sched_param param = {\n+\t\t.sched_priority = 0,\n+\t};\n+\tint policy = SCHED_OTHER;\n+\n+\tif (thread_attr != NULL) {\n+\t\tret = pthread_attr_init(&attr);\n+\t\tif (ret != 0) {\n+\t\t\tRTE_LOG(DEBUG, EAL, \"pthread_attr_init failed\\n\");\n+\t\t\tgoto cleanup;\n+\t\t}\n+\n+\t\tattrp = &attr;\n+\n+\t\t/* Set the inherit scheduler parameter to explicit,\n+\t\t * otherwise the priority attribute is ignored.\n+\t\t */\n+\t\tret = pthread_attr_setinheritsched(attrp, PTHREAD_EXPLICIT_SCHED);\n+\t\tif (ret != 0) {\n+\t\t\tRTE_LOG(DEBUG, EAL, \"pthread_attr_setinheritsched failed\\n\");\n+\t\t\tgoto cleanup;\n+\t\t}\n+\n+\t\t/* In case a realtime scheduling policy is requested, the sched_priority\n+\t\t * parameter is set to the value stored in thread_attr. Otherwise, for\n+\t\t * the default scheduling policy (SCHED_OTHER) sched_priority needs to\n+\t\t * be intialized to 0. */\n+\t\tif (thread_attr->priority == RTE_THREAD_PRIORITY_REALTIME_CRITICAL) {\n+\t\t\tpolicy = SCHED_RR;\n+\t\t\tparam.sched_priority = thread_attr->priority;\n+\t\t}\n+\n+\t\tret = pthread_attr_setschedpolicy(attrp, policy);\n+\t\tif (ret != 0) {\n+\t\t\tRTE_LOG(DEBUG, EAL, \"pthread_attr_setschedpolicy failed\\n\");\n+\t\t\tgoto cleanup;\n+\t\t}\n+\n+\t\tret = pthread_attr_setschedparam(attrp, &param);\n+\t\tif (ret != 0) {\n+\t\t\tRTE_LOG(DEBUG, EAL, \"pthread_attr_setschedparam failed\\n\");\n+\t\t\tgoto cleanup;\n+\t\t}\n+\n+\t\tret = pthread_attr_setaffinity_np(attrp, sizeof(thread_attr->cpuset), &thread_attr->cpuset);\n+\t\tif (ret != 0) {\n+\t\t\tRTE_LOG(DEBUG, EAL, \"pthread_attr_setaffinity_np failed\\n\");\n+\t\t\tgoto cleanup;\n+\t\t}\n+\t}\n+\n+\tret = pthread_create(thread_id, attrp, thread_func, args);\n+\tif (ret != 0) {\n+\t\tRTE_LOG(DEBUG, EAL, \"pthread_create failed\\n\");\n+\t\tgoto cleanup;\n+\t}\n+\n+cleanup:\n+\tif (attrp != NULL) {\n+\t\tpthread_attr_destroy(&attr);\n+\t}\n+\treturn ret;\n+}\n+\n+int\n+rte_thread_join(rte_thread_t thread_id, int *value_ptr)\n+{\n+\tint ret = 0;\n+\tvoid *res = NULL;\n+\tvoid **pres = NULL;\n+\n+\tif (value_ptr != NULL) {\n+\t\tpres = &res;\n+\t}\n+\n+\tret = pthread_join(thread_id, pres);\n+\tif (ret != 0) {\n+\t\tRTE_LOG(DEBUG, EAL, \"pthread_join failed\\n\");\n+\t\treturn ret;\n+\t}\n+\n+\tif (pres != NULL) {\n+\t\t*value_ptr = *(int*)(*pres);\n+\t}\n+\treturn 0;\n+}\n+\n+int\n+rte_thread_mutex_init(rte_thread_mutex_t *mutex)\n+{\n+\treturn pthread_mutex_init(mutex, NULL);\n+}\n+\n+int\n+rte_thread_mutex_lock(rte_thread_mutex_t *mutex)\n+{\n+\treturn pthread_mutex_lock(mutex);\n+}\n+\n+int\n+rte_thread_mutex_unlock(rte_thread_mutex_t *mutex)\n+{\n+\treturn pthread_mutex_unlock(mutex);\n+}\n+\n+int\n+rte_thread_mutex_destroy(rte_thread_mutex_t *mutex)\n+{\n+\treturn pthread_mutex_destroy(mutex);\n+}\n+\n+int\n+rte_thread_barrier_init(rte_thread_barrier_t *barrier, int count)\n+{\n+\treturn pthread_barrier_init(barrier, NULL, count);\n+}\n+\n+int rte_thread_barrier_wait(rte_thread_barrier_t *barrier)\n+{\n+\treturn pthread_barrier_wait(barrier);\n+}\n+\n+int rte_thread_barrier_destroy(rte_thread_barrier_t *barrier)\n+{\n+\treturn pthread_barrier_destroy(barrier);\n+}\n+\n+int rte_thread_cancel(rte_thread_t thread_id)\n+{\n+\t/*\n+\t * TODO: Behavior is different between POSIX and Windows threads.\n+\t * POSIX threads wait for a cancellation point.\n+\t * Current Windows emulation kills thread at any point.\n+\t */\n+\treturn pthread_cancel(thread_id);\n+}\n+\n+int\n+rte_thread_tls_key_create(rte_tls_key *key, void (*destructor)(void *))\n+{\n+\tint err;\n+\n+\t*key = malloc(sizeof(**key));\n+\tif ((*key) == NULL) {\n+\t\tRTE_LOG(DEBUG, EAL, \"Cannot allocate TLS key.\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\terr = pthread_key_create(&((*key)->thread_index), destructor);\n+\tif (err != 0) {\n+\t\tRTE_LOG(DEBUG, EAL, \"pthread_key_create failed: %s\\n\",\n+\t\t\t strerror(err));\n+\t\tfree(*key);\n+\t\treturn -ENOMEM;\n+\t}\n+\treturn 0;\n+}\n+\n+int\n+rte_thread_tls_key_delete(rte_tls_key key)\n+{\n+\tint err;\n+\n+\tif (key == NULL) {\n+\t\tRTE_LOG(DEBUG, EAL, \"Invalid TLS key.\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\terr = pthread_key_delete(key->thread_index);\n+\tif (err != 0) {\n+\t\tRTE_LOG(DEBUG, EAL, \"pthread_key_delete failed: %s\\n\",\n+\t\t\t strerror(err));\n+\t\tfree(key);\n+\t\treturn -EINVAL;\n+\t}\n+\tfree(key);\n+\treturn 0;\n+}\n+\n+int\n+rte_thread_tls_value_set(rte_tls_key key, const void *value)\n+{\n+\tint err;\n+\n+\tif (key == NULL) {\n+\t\tRTE_LOG(DEBUG, EAL, \"Invalid TLS key.\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\terr = pthread_setspecific(key->thread_index, value);\n+\tif (err != 0) {\n+\t\tRTE_LOG(DEBUG, EAL, \"pthread_setspecific failed: %s\\n\",\n+\t\t\tstrerror(err));\n+\t\treturn -ENOMEM;\n+\t}\n+\treturn 0;\n+}\n+\n+void *\n+rte_thread_tls_value_get(rte_tls_key key)\n+{\n+\tif (key == NULL) {\n+\t\tRTE_LOG(DEBUG, EAL, \"Invalid TLS key.\\n\");\n+\t\trte_errno = EINVAL;\n+\t\treturn NULL;\n+\t}\n+\treturn pthread_getspecific(key->thread_index);\n+}\ndiff --git a/lib/librte_eal/include/rte_thread.h b/lib/librte_eal/include/rte_thread.h\nindex e640ea185..66b112bc4 100644\n--- a/lib/librte_eal/include/rte_thread.h\n+++ b/lib/librte_eal/include/rte_thread.h\n@@ -20,11 +20,330 @@\n extern \"C\" {\n #endif\n \n+#include <sched.h>\n+#if defined(RTE_USE_WINDOWS_THREAD_TYPES)\n+#include <rte_windows_thread_types.h>\n+#else\n+#include <rte_thread_types.h>\n+#endif\n+\n+enum rte_thread_priority\n+{\n+\tRTE_THREAD_PRIORITY_NORMAL            = EAL_THREAD_PRIORITY_NORMAL,\n+\tRTE_THREAD_PRIORITY_REALTIME_CRITICAL = EAL_THREAD_PRIORITY_REALTIME_CIRTICAL,\n+\t/*\n+\t * This enum can be extended to allow more priority levels.\n+\t */\n+};\n+\n+typedef struct\n+{\n+\tenum rte_thread_priority priority;\n+\trte_cpuset_t cpuset;\n+} rte_thread_attr_t;\n+\n /**\n  * TLS key type, an opaque pointer.\n  */\n typedef struct eal_tls_key *rte_tls_key;\n \n+/**\n+ * Get the id of the calling thread.\n+ *\n+ * @return\n+ *   Return the thread id of the calling thread.\n+ */\n+__rte_experimental\n+rte_thread_t rte_thread_self(void);\n+\n+/**\n+ * Check if 2 thread ids are equal.\n+ *\n+ * @param t1\n+ *   First thread id.\n+ *\n+ * @param t2\n+ *   Second thread id.\n+ *\n+ * @return\n+ *   If the ids are equal, return nonzero.\n+ *   Otherwise, return 0.\n+ */\n+__rte_experimental\n+int rte_thread_equal(rte_thread_t t1, rte_thread_t t2);\n+\n+/**\n+ * Set the affinity of thread 'thread_id' to the cpu set\n+ * specified by 'cpuset'.\n+ *\n+ * @param thread_id\n+ *    Id of the thread for which to set the affinity.\n+ *\n+ * @param cpuset_size\n+ *\n+ * @param cpuset\n+ *   Pointer to CPU affinity to set.\n+ *\n+ * @return\n+ *   On success, return 0.\n+ *   On failure, return nonzero.\n+ */\n+__rte_experimental\n+int rte_thread_set_affinity(rte_thread_t thread_id, size_t cpuset_size,\n+\t\t\t    const rte_cpuset_t *cpuset);\n+\n+/**\n+ * Get the affinity of thread 'thread_id' and store it\n+ * in 'cpuset'.\n+ *\n+ * @param thread_id\n+ *    Id of the thread for which to get the affinity.\n+ *\n+ * @param cpuset_size\n+ *    Size of the cpu set.\n+ *\n+ * @param cpuset\n+ *   Pointer for storing the affinity value.\n+ *\n+ * @return\n+ *   On success, return 0.\n+ *   On failure, return nonzero.\n+ */\n+__rte_experimental\n+int rte_thread_get_affinity(rte_thread_t thread_id, size_t cpuset_size,\n+\t\t\t    rte_cpuset_t *cpuset);\n+\n+/**\n+ * Set the priority of a thread.\n+ *\n+ * @param thread_id\n+ *    Id of the thread for which to set priority.\n+ *\n+ * @param priority\n+ *   Priority value to be set.\n+ *\n+ * @return\n+ *   On success, return 0.\n+ *   On failure, return nonzero.\n+ */\n+__rte_experimental\n+int rte_thread_set_priority(rte_thread_t thread_id, enum rte_thread_priority priority);\n+\n+/**\n+ * Initialize the attributes of a thread.\n+ * These attributes can be passed to the rte_thread_create() function\n+ * that will create a new thread and set its attributes according to attr;\n+ *\n+ * @param attr\n+ *   Thread attributes to initialize.\n+ *\n+ * @return\n+ *   On success, return 0.\n+ *   On failure, return nonzero.\n+ */\n+__rte_experimental\n+int rte_thread_attr_init(rte_thread_attr_t *attr);\n+\n+/**\n+ * Set the CPU affinity value in the thread attributes pointed to\n+ * by 'thread_attr'.\n+ *\n+ * @param thread_attr\n+ *   Points to the thread attributes in which affinity will be updated.\n+ *\n+ * @param cpuset\n+ *   Points to the value of the affinity to be set.\n+ *\n+ * @return\n+ *   On success, return 0.\n+ *   On failure, return nonzero.\n+ */\n+__rte_experimental\n+int rte_thread_attr_set_affinity(rte_thread_attr_t *thread_attr, rte_cpuset_t *cpuset);\n+\n+/**\n+ * Get the value of CPU affinity that is set in the thread attributes pointed to\n+ * by 'thread_attr'.\n+ *\n+ * @param thread_attr\n+ *   Points to the thread attributes from which affinity will be retrieved.\n+ *\n+ * @param cpuset\n+ *   Pointer to the memory that will store the affinity.\n+ *\n+ * @return\n+ *   On success, return 0.\n+ *   On failure, return nonzero.\n+ */\n+__rte_experimental\n+int rte_thread_attr_get_affinity(rte_thread_attr_t *thread_attr, rte_cpuset_t *cpuset);\n+\n+/**\n+ * Set the thread priority value in the thread attributes pointed to\n+ * by 'thread_attr'.\n+ *\n+ * @param thread_attr\n+ *   Points to the thread attributes in which priority will be updated.\n+ *\n+ * @param cpuset\n+ *   Points to the value of the priority to be set.\n+ *\n+ * @return\n+ *   On success, return 0.\n+ *   On failure, return nonzero.\n+ */\n+__rte_experimental\n+int rte_thread_attr_set_priority(rte_thread_attr_t *thread_attr, enum rte_thread_priority priority);\n+\n+/**\n+ * Create a new thread that will invoke the 'thread_func' routine.\n+ *\n+ * @param thread_id\n+ *    A pointer that will store the id of the newly created thread.\n+ *\n+ * @param thread_attr\n+ *    Attributes that are used at the creation of the new thread.\n+ *\n+ * @param thread_func\n+ *    The routine that the new thread will invoke when starting execution.\n+ *\n+ * @param args\n+ *    Arguments to be passed to the 'thread_func' routine.\n+ *\n+ * @return\n+ *   On success, return 0.\n+ *   On failure, return an error number.\n+ */\n+__rte_experimental\n+int rte_thread_create(rte_thread_t *thread_id,\n+\t\t      const rte_thread_attr_t *thread_attr,\n+\t\t      void *(*thread_func) (void*), void *args);\n+\n+/**\n+ * Waits for the thread identified by 'thread_id' to terminate\n+ *\n+ * @param thread_id\n+ *    The identifier of the thread.\n+ *\n+ * @param value_ptr\n+ *    Stores the exit status of the thread.\n+ *\n+ * @return\n+ *   On success, return 0.\n+ *   On failure, return an error number.\n+ */\n+__rte_experimental\n+int rte_thread_join(rte_thread_t thread_id, int *value_ptr);\n+\n+/**\n+ * Initializes a mutex.\n+ *\n+ * @param mutex\n+ *    The mutex to be initialized.\n+ *\n+ * @param attr\n+ *    Attributes for initialization of the mutex.\n+ *\n+ * @return\n+ *   On success, return 0.\n+ *   On failure, return an error number.\n+ */\n+__rte_experimental\n+int rte_thread_mutex_init(rte_thread_mutex_t *mutex);\n+\n+/**\n+ * Locks a mutex.\n+ *\n+ * @param mutex\n+ *    The mutex to be locked.\n+ *\n+ * @return\n+ *   On success, return 0.\n+ *   On failure, return an error number.\n+ */\n+__rte_experimental\n+int rte_thread_mutex_lock(rte_thread_mutex_t *mutex);\n+\n+/**\n+ * Unlocks a mutex.\n+ *\n+ * @param mutex\n+ *    The mutex to be unlocked.\n+ *\n+ * @return\n+ *   On success, return 0.\n+ *   On failure, return an error number.\n+ */\n+__rte_experimental\n+int rte_thread_mutex_unlock(rte_thread_mutex_t *mutex);\n+\n+/**\n+ * Releases all resources associated with a mutex.\n+ *\n+ * @param mutex\n+ *    The mutex to be uninitialized.\n+ *\n+ * @return\n+ *   On success, return 0.\n+ *   On failure, return an error number.\n+ */\n+__rte_experimental\n+int rte_thread_mutex_destroy(rte_thread_mutex_t *mutex);\n+\n+/**\n+ * Initializes a synchronization barrier.\n+ *\n+ * @param barrier\n+ *    A pointer that references the newly created 'barrier' object.\n+ *\n+ * @return\n+ *   On success, return 0.\n+ *   On failure, return an error number.\n+ */\n+__rte_experimental\n+int rte_thread_barrier_init(rte_thread_barrier_t *barrier, int count);\n+\n+/**\n+ * Causes the calling thread to wait at the synchronization barrier 'barrier'.\n+ *\n+ * @param barrier\n+ *    The barrier used for synchronizing the threads.\n+ *\n+ * @return\n+ *   Return RTE_THREAD_BARRIER_SERIAL_THREAD for the thread synchronized at the barrier.\n+ *   Return 0 for all other threads.\n+ *   Return error number in case of error.\n+ */\n+__rte_experimental\n+int rte_thread_barrier_wait(rte_thread_barrier_t *barrier);\n+\n+/**\n+ * Releases all resources used by a synchronization barrier\n+ * and uninitializes it.\n+ *\n+ * @param barrier\n+ *    The barrier to be uninitialized.\n+ *\n+ * @return\n+ *   On success, return 0.\n+ *   On failure, return an error number.\n+ */\n+__rte_experimental\n+int rte_thread_barrier_destroy(rte_thread_barrier_t *barrier);\n+\n+/**\n+ * Terminates a thread.\n+ *\n+ * @param thread_id\n+ *    The id of the thread to be terminated.\n+ *\n+ * @return\n+ *   On success, return 0.\n+ *   On failure, return nonzero.\n+ */\n+__rte_experimental\n+int rte_thread_cancel(rte_thread_t thread_id);\n+\n /**\n  * Set core affinity of the current thread.\n  * Support both EAL and non-EAL thread and update TLS.\n@@ -34,7 +353,7 @@ typedef struct eal_tls_key *rte_tls_key;\n  * @return\n  *   On success, return 0; otherwise return -1;\n  */\n-int rte_thread_set_affinity(rte_cpuset_t *cpusetp);\n+int rte_thread_self_set_affinity(rte_cpuset_t *cpusetp);\n \n /**\n  * Get core affinity of the current thread.\n@@ -44,7 +363,7 @@ int rte_thread_set_affinity(rte_cpuset_t *cpusetp);\n  *   It presumes input is not NULL, otherwise it causes panic.\n  *\n  */\n-void rte_thread_get_affinity(rte_cpuset_t *cpusetp);\n+void rte_thread_self_get_affinity(rte_cpuset_t *cpusetp);\n \n /**\n  * Create a TLS data key visible to all threads in the process.\ndiff --git a/lib/librte_eal/include/rte_thread_types.h b/lib/librte_eal/include/rte_thread_types.h\nnew file mode 100644\nindex 000000000..b055bbf67\n--- /dev/null\n+++ b/lib/librte_eal/include/rte_thread_types.h\n@@ -0,0 +1,20 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2021 Microsoft Corporation\n+ */\n+\n+#ifndef _RTE_THREAD_TYPES_H_\n+#define _RTE_THREAD_TYPES_H_\n+\n+#include <pthread.h>\n+\n+#define RTE_THREAD_BARRIER_SERIAL_THREAD PTHREAD_BARRIER_SERIAL_THREAD\n+#define RTE_THREAD_MUTEX_INITIALIZER     PTHREAD_MUTEX_INITIALIZER\n+\n+#define EAL_THREAD_PRIORITY_NORMAL               0\n+#define EAL_THREAD_PRIORITY_REALTIME_CIRTICAL    99\n+\n+typedef pthread_t                       rte_thread_t;\n+typedef pthread_mutex_t                 rte_thread_mutex_t;\n+typedef pthread_barrier_t               rte_thread_barrier_t;\n+\n+#endif /* _RTE_THREAD_TYPES_H_ */\ndiff --git a/lib/librte_eal/windows/eal_lcore.c b/lib/librte_eal/windows/eal_lcore.c\nindex a85149be9..3e63f9f70 100644\n--- a/lib/librte_eal/windows/eal_lcore.c\n+++ b/lib/librte_eal/windows/eal_lcore.c\n@@ -2,7 +2,6 @@\n  * Copyright(c) 2019 Intel Corporation\n  */\n \n-#include <pthread.h>\n #include <stdbool.h>\n #include <stdint.h>\n \n@@ -28,10 +27,12 @@ struct socket_map {\n };\n \n struct cpu_map {\n-\tunsigned int socket_count;\n \tunsigned int lcore_count;\n+\tunsigned int socket_count;\n+\tunsigned int cpu_count;\n \tstruct lcore_map lcores[RTE_MAX_LCORE];\n \tstruct socket_map sockets[RTE_MAX_NUMA_NODES];\n+\tGROUP_AFFINITY cpus[CPU_SETSIZE];\n };\n \n static struct cpu_map cpu_map = { 0 };\n@@ -48,13 +49,110 @@ log_early(const char *format, ...)\n \tva_end(va);\n }\n \n+static int\n+eal_query_group_affinity(void)\n+{\n+\tSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *infos = NULL;\n+\tDWORD infos_size = 0;\n+\tint ret = 0;\n+\n+\tif (!GetLogicalProcessorInformationEx(RelationGroup, NULL, &infos_size)) {\n+\t\tDWORD error = GetLastError();\n+\t\tif (error != ERROR_INSUFFICIENT_BUFFER) {\n+\t\t\tlog_early(\"Cannot get group information size, error %lu\\n\",\n+\t\t\t\t  error);\n+\t\t\trte_errno = EINVAL;\n+\t\t\tret = -1;\n+\t\t\tgoto cleanup;\n+\t\t}\n+\t}\n+\n+\tinfos = malloc(infos_size);\n+\tif (infos == NULL) {\n+\t\tlog_early(\"Cannot allocate memory for NUMA node information\\n\");\n+\t\trte_errno = ENOMEM;\n+\t\tret = -1;\n+\t\tgoto cleanup;\n+\t}\n+\n+\tif (!GetLogicalProcessorInformationEx(RelationGroup, infos, &infos_size)) {\n+\t\tlog_early(\"Cannot get group information, error %lu\\n\", GetLastError());\n+\t\trte_errno = EINVAL;\n+\t\tret = -1;\n+\t\tgoto cleanup;\n+\t}\n+\n+\tcpu_map.cpu_count = 0;\n+\tUSHORT group_count = infos->Group.ActiveGroupCount;\n+\tfor (USHORT group_number = 0; group_number < group_count; group_number++) {\n+\t\tKAFFINITY affinity = infos->Group.GroupInfo[group_number].ActiveProcessorMask;\n+\n+\t\tfor (unsigned int i = 0; i < EAL_PROCESSOR_GROUP_SIZE; i++) {\n+\t\t\tif ((affinity & ((KAFFINITY)1 << i)) == 0)\n+\t\t\t\tcontinue;\n+\t\t\tcpu_map.cpus[cpu_map.cpu_count].Group = group_number;\n+\t\t\tcpu_map.cpus[cpu_map.cpu_count].Mask = (KAFFINITY)1 << i;\n+\t\t\tcpu_map.cpu_count++;\n+\t\t}\n+\t}\n+\n+cleanup:\n+\tfree(infos);\n+\treturn ret;\n+}\n+\n+static bool\n+eal_check_for_duplicate_numa(const SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *info)\n+{\n+\tconst unsigned int node_id = info->NumaNode.NodeNumber;\n+\tconst GROUP_AFFINITY *cores = &info->NumaNode.GroupMask;\n+\tstruct lcore_map *lcore;\n+\tunsigned int socket_id;\n+\n+\t/* NUMA node may be reported multiple times if it includes\n+\t * cores from different processor groups, e. g. 80 cores\n+\t * of a physical processor comprise one NUMA node, but two\n+\t * processor groups, because group size is limited by 32/64.\n+\t */\n+\tfor (socket_id = 0; socket_id < cpu_map.socket_count; socket_id++) {\n+\t\tif (cpu_map.sockets[socket_id].node_id == node_id)\n+\t\t\tbreak;\n+\t}\n+\n+\tif (socket_id == cpu_map.socket_count) {\n+\t\tif (socket_id == RTE_DIM(cpu_map.sockets)) {\n+\t\t\treturn true;\n+\t\t}\n+\n+\t\tcpu_map.sockets[socket_id].node_id = node_id;\n+\t\tcpu_map.socket_count++;\n+\t}\n+\n+\tfor (unsigned int i = 0; i < EAL_PROCESSOR_GROUP_SIZE; i++) {\n+\t\tif ((cores->Mask & ((KAFFINITY)1 << i)) == 0)\n+\t\t\tcontinue;\n+\n+\t\tif (cpu_map.lcore_count == RTE_DIM(cpu_map.lcores)) {\n+\t\t\treturn true;\n+\t\t}\n+\n+\t\tlcore = &cpu_map.lcores[cpu_map.lcore_count];\n+\t\tlcore->socket_id = socket_id;\n+\t\tlcore->core_id = cores->Group * EAL_PROCESSOR_GROUP_SIZE + i;\n+\t\tcpu_map.lcore_count++;\n+\t}\n+\treturn false;\n+}\n+\n int\n eal_create_cpu_map(void)\n {\n \tSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *infos, *info;\n \tDWORD infos_size;\n \tbool full = false;\n+\tint ret = 0;\n \n+\tinfos = NULL;\n \tinfos_size = 0;\n \tif (!GetLogicalProcessorInformationEx(\n \t\t\tRelationNumaNode, NULL, &infos_size)) {\n@@ -79,57 +177,27 @@ eal_create_cpu_map(void)\n \t\tlog_early(\"Cannot get NUMA node information, error %lu\\n\",\n \t\t\tGetLastError());\n \t\trte_errno = EINVAL;\n-\t\treturn -1;\n+\t\tret = -1;\n+\t\tgoto exit;\n \t}\n \n \tinfo = infos;\n \twhile ((uint8_t *)info - (uint8_t *)infos < infos_size) {\n-\t\tunsigned int node_id = info->NumaNode.NodeNumber;\n-\t\tGROUP_AFFINITY *cores = &info->NumaNode.GroupMask;\n-\t\tstruct lcore_map *lcore;\n-\t\tunsigned int i, socket_id;\n-\n-\t\t/* NUMA node may be reported multiple times if it includes\n-\t\t * cores from different processor groups, e. g. 80 cores\n-\t\t * of a physical processor comprise one NUMA node, but two\n-\t\t * processor groups, because group size is limited by 32/64.\n-\t\t */\n-\t\tfor (socket_id = 0; socket_id < cpu_map.socket_count;\n-\t\t    socket_id++) {\n-\t\t\tif (cpu_map.sockets[socket_id].node_id == node_id)\n-\t\t\t\tbreak;\n-\t\t}\n-\n-\t\tif (socket_id == cpu_map.socket_count) {\n-\t\t\tif (socket_id == RTE_DIM(cpu_map.sockets)) {\n-\t\t\t\tfull = true;\n-\t\t\t\tgoto exit;\n-\t\t\t}\n-\n-\t\t\tcpu_map.sockets[socket_id].node_id = node_id;\n-\t\t\tcpu_map.socket_count++;\n-\t\t}\n-\n-\t\tfor (i = 0; i < EAL_PROCESSOR_GROUP_SIZE; i++) {\n-\t\t\tif ((cores->Mask & ((KAFFINITY)1 << i)) == 0)\n-\t\t\t\tcontinue;\n-\n-\t\t\tif (cpu_map.lcore_count == RTE_DIM(cpu_map.lcores)) {\n-\t\t\t\tfull = true;\n-\t\t\t\tgoto exit;\n-\t\t\t}\n-\n-\t\t\tlcore = &cpu_map.lcores[cpu_map.lcore_count];\n-\t\t\tlcore->socket_id = socket_id;\n-\t\t\tlcore->core_id =\n-\t\t\t\tcores->Group * EAL_PROCESSOR_GROUP_SIZE + i;\n-\t\t\tcpu_map.lcore_count++;\n-\t\t}\n+\t\tif (eal_check_for_duplicate_numa(info))\n+\t\t\tbreak;\n \n \t\tinfo = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(\n \t\t\t(uint8_t *)info + info->Size);\n \t}\n \n+\tif (eal_query_group_affinity()) {\n+\t\t/*\n+\t\t * No need to set rte_errno here.\n+\t\t * It is set by eal_query_group_affinity().\n+\t\t */\n+\t\tret = -1;\n+\t\tgoto exit;\n+\t}\n exit:\n \tif (full) {\n \t\t/* Not a fatal error, but important for troubleshooting. */\n@@ -139,7 +207,7 @@ eal_create_cpu_map(void)\n \n \tfree(infos);\n \n-\treturn 0;\n+\treturn ret;\n }\n \n int\n@@ -165,3 +233,12 @@ eal_socket_numa_node(unsigned int socket_id)\n {\n \treturn cpu_map.sockets[socket_id].node_id;\n }\n+\n+PGROUP_AFFINITY\n+eal_get_cpu_affinity(size_t cpu_index)\n+{\n+\tif (cpu_index < CPU_SETSIZE)\n+\t\treturn &cpu_map.cpus[cpu_index];\n+\n+\treturn NULL;\n+}\ndiff --git a/lib/librte_eal/windows/eal_windows.h b/lib/librte_eal/windows/eal_windows.h\nindex 478accc1b..dc5dc8240 100644\n--- a/lib/librte_eal/windows/eal_windows.h\n+++ b/lib/librte_eal/windows/eal_windows.h\n@@ -55,6 +55,16 @@ int eal_thread_create(pthread_t *thread);\n  */\n unsigned int eal_socket_numa_node(unsigned int socket_id);\n \n+/**\n+ * Get pointer to the group affinity for the cpu.\n+ *\n+ * @param cpu_index\n+ *  Index of the cpu, as it comes from rte_cpuset_t.\n+ * @return\n+ *  Pointer to the group affinity for the cpu.\n+ */\n+PGROUP_AFFINITY eal_get_cpu_affinity(size_t cpu_index);\n+\n /**\n  * Schedule code for execution in the interrupt thread.\n  *\ndiff --git a/lib/librte_eal/windows/include/rte_windows_thread_types.h b/lib/librte_eal/windows/include/rte_windows_thread_types.h\nnew file mode 100644\nindex 000000000..b6209e6eb\n--- /dev/null\n+++ b/lib/librte_eal/windows/include/rte_windows_thread_types.h\n@@ -0,0 +1,19 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2021 Microsoft Corporation\n+ */\n+\n+#ifndef _RTE_THREAD_TYPES_H_\n+#define _RTE_THREAD_TYPES_H_\n+\n+#include <rte_windows.h>\n+\n+#define RTE_THREAD_BARRIER_SERIAL_THREAD TRUE\n+\n+#define EAL_THREAD_PRIORITY_NORMAL             THREAD_PRIORITY_NORMAL\n+#define EAL_THREAD_PRIORITY_REALTIME_CIRTICAL  THREAD_PRIORITY_TIME_CRITICAL\n+\n+typedef DWORD                       rte_thread_t;\n+typedef CRITICAL_SECTION            rte_thread_mutex_t;\n+typedef SYNCHRONIZATION_BARRIER     rte_thread_barrier_t;\n+\n+#endif /* _RTE_THREAD_TYPES_H_ */\ndiff --git a/lib/librte_eal/windows/rte_thread.c b/lib/librte_eal/windows/rte_thread.c\nindex 2e2ab2917..decb4b24d 100644\n--- a/lib/librte_eal/windows/rte_thread.c\n+++ b/lib/librte_eal/windows/rte_thread.c\n@@ -1,16 +1,503 @@\n /* SPDX-License-Identifier: BSD-3-Clause\n  * Copyright 2021 Mellanox Technologies, Ltd\n+ * Copyright(c) 2021 Microsoft Corporation\n  */\n \n #include <rte_common.h>\n-#include <rte_errno.h>\n #include <rte_thread.h>\n-#include <rte_windows.h>\n+\n+#include \"eal_windows.h\"\n \n struct eal_tls_key {\n \tDWORD thread_index;\n };\n \n+/* Translates the most common error codes related to threads */\n+static int rte_thread_translate_win32_error(DWORD error)\n+{\n+\tswitch (error) {\n+\tcase ERROR_SUCCESS:\n+\t\treturn 0;\n+\n+\tcase ERROR_INVALID_PARAMETER:\n+\t\treturn -EINVAL;\n+\n+\tcase ERROR_INVALID_HANDLE:\n+\t\treturn -EFAULT;\n+\n+\tcase ERROR_NOT_ENOUGH_MEMORY:\n+\t/* FALLTHROUGH */\n+\tcase ERROR_NO_SYSTEM_RESOURCES:\n+\t\treturn -ENOMEM;\n+\n+\tcase ERROR_PRIVILEGE_NOT_HELD:\n+\t/* FALLTHROUGH */\n+\tcase ERROR_ACCESS_DENIED:\n+\t\treturn -EACCES;\n+\n+\tcase ERROR_ALREADY_EXISTS:\n+\t\treturn -EEXIST;\n+\n+\tcase ERROR_POSSIBLE_DEADLOCK:\n+\t\treturn -EDEADLK;\n+\n+\tcase ERROR_INVALID_FUNCTION:\n+\t/* FALLTHROUGH */\n+\tcase ERROR_CALL_NOT_IMPLEMENTED:\n+\t\treturn -ENOSYS;\n+\n+\tdefault:\n+\t\treturn -EINVAL;\n+\t}\n+\n+\treturn -EINVAL;\n+}\n+\n+rte_thread_t\n+rte_thread_self(void)\n+{\n+\treturn GetCurrentThreadId();\n+}\n+\n+int\n+rte_thread_equal(rte_thread_t t1, rte_thread_t t2)\n+{\n+\treturn t1 == t2 ? 1 : 0;\n+}\n+\n+static int\n+rte_convert_cpuset_to_affinity(const rte_cpuset_t *cpuset,\n+\t\t\t       PGROUP_AFFINITY affinity)\n+{\n+\tint ret = 0;\n+\tPGROUP_AFFINITY cpu_affinity = NULL;\n+\n+\tmemset(affinity, 0, sizeof(GROUP_AFFINITY));\n+\taffinity->Group = (USHORT)-1;\n+\n+\t/* Check that all cpus of the set belong to the same processor group and\n+\t * accumulate thread affinity to be applied.\n+\t */\n+\tfor (unsigned int cpu_idx = 0; cpu_idx < CPU_SETSIZE; cpu_idx++) {\n+\t\tif (!CPU_ISSET(cpu_idx, cpuset))\n+\t\t\tcontinue;\n+\n+\t\tcpu_affinity = eal_get_cpu_affinity(cpu_idx);\n+\n+\t\tif (affinity->Group == (USHORT)-1) {\n+\t\t\taffinity->Group = cpu_affinity->Group;\n+\t\t} else if (affinity->Group != cpu_affinity->Group) {\n+\t\t\tret = -EINVAL;\n+\t\t\tgoto cleanup;\n+\t\t}\n+\n+\t\taffinity->Mask |= cpu_affinity->Mask;\n+\t}\n+\n+\tif (affinity->Mask == 0) {\n+\t\tret = -EINVAL;\n+\t\tgoto cleanup;\n+\t}\n+\n+cleanup:\n+\treturn ret;\n+}\n+\n+int rte_thread_set_affinity(rte_thread_t thread_id,\n+\t\t\t    size_t cpuset_size,\n+\t\t\t    const rte_cpuset_t *cpuset)\n+{\n+\tint ret = 0;\n+\tGROUP_AFFINITY thread_affinity;\n+\tHANDLE thread_handle = NULL;\n+\n+\tif (cpuset == NULL || cpuset_size < sizeof(*cpuset)) {\n+\t\tret = -EINVAL;\n+\t\tgoto cleanup;\n+\t}\n+\n+\tret = rte_convert_cpuset_to_affinity(cpuset, &thread_affinity);\n+\tif (ret != 0) {\n+\t\tRTE_LOG(DEBUG, EAL, \"Unable to convert cpuset to thread affinity\\n\");\n+\t\tgoto cleanup;\n+\t}\n+\n+\tthread_handle = OpenThread(THREAD_ALL_ACCESS, FALSE, thread_id);\n+\tif (thread_handle == NULL) {\n+\t\tret = rte_thread_translate_win32_error(GetLastError());\n+\t\tRTE_LOG_WIN32_ERR(\"OpenThread()\");\n+\t\tgoto cleanup;\n+\t}\n+\n+\tif (!SetThreadGroupAffinity(thread_handle, &thread_affinity, NULL)) {\n+\t\tret = rte_thread_translate_win32_error(GetLastError());\n+\t\tRTE_LOG_WIN32_ERR(\"SetThreadGroupAffinity()\");\n+\t\tgoto cleanup;\n+\t}\n+\n+cleanup:\n+\tif (thread_handle != NULL) {\n+\t\tCloseHandle(thread_handle);\n+\t\tthread_handle = NULL;\n+\t}\n+\n+\treturn ret;\n+}\n+\n+int\n+rte_thread_get_affinity(rte_thread_t thread_id, size_t cpuset_size,\n+\t\t\trte_cpuset_t *cpuset)\n+{\n+\tHANDLE thread_handle = NULL;\n+\tPGROUP_AFFINITY cpu_affinity;\n+\tGROUP_AFFINITY thread_affinity;\n+\tint ret = 0;\n+\n+\tif (cpuset == NULL || cpuset_size < sizeof(*cpuset)) {\n+\t\tret = -EINVAL;\n+\t\tgoto cleanup;\n+\t}\n+\n+\tthread_handle = OpenThread(THREAD_ALL_ACCESS, FALSE, thread_id);\n+\tif (thread_handle == NULL) {\n+\t\tret = rte_thread_translate_win32_error(GetLastError());\n+\t\tRTE_LOG_WIN32_ERR(\"OpenThread()\");\n+\t\tgoto cleanup;\n+\t}\n+\n+\t/* obtain previous thread affinity */\n+\tif (!GetThreadGroupAffinity(thread_handle, &thread_affinity)) {\n+\t\tret = rte_thread_translate_win32_error(GetLastError());\n+\t\tRTE_LOG_WIN32_ERR(\"GetThreadGroupAffinity()\");\n+\t\tgoto cleanup;\n+\t}\n+\n+\tCPU_ZERO(cpuset);\n+\n+\t/* Convert affinity to DPDK cpu set */\n+\tfor (unsigned int cpu_idx = 0; cpu_idx < CPU_SETSIZE; cpu_idx++) {\n+\n+\t\tcpu_affinity = eal_get_cpu_affinity(cpu_idx);\n+\n+\t\tif ((cpu_affinity->Group == thread_affinity.Group) &&\n+\t\t   ((cpu_affinity->Mask & thread_affinity.Mask) != 0)) {\n+\t\t\tCPU_SET(cpu_idx, cpuset);\n+\t\t}\n+\t}\n+\n+cleanup:\n+\tif (thread_handle != NULL) {\n+\t\tCloseHandle(thread_handle);\n+\t\tthread_handle = NULL;\n+\t}\n+\treturn ret;\n+}\n+\n+static HANDLE\n+get_process_handle_from_thread_handle(HANDLE thread_handle)\n+{\n+\tDWORD process_id = 0;\n+\n+\tprocess_id = GetProcessIdOfThread(thread_handle);\n+\tif (process_id == 0) {\n+\t\tRTE_LOG_WIN32_ERR(\"GetProcessIdOfThread()\");\n+\t\treturn NULL;\n+\t}\n+\n+\treturn OpenProcess(PROCESS_SET_INFORMATION, FALSE, process_id);\n+}\n+\n+int\n+rte_thread_set_priority(rte_thread_t thread_id, enum rte_thread_priority priority)\n+{\n+\tHANDLE thread_handle = NULL;\n+\tHANDLE process_handle = NULL;\n+\tDWORD priority_class = NORMAL_PRIORITY_CLASS;\n+\tint ret = 0;\n+\n+\tthread_handle = OpenThread(THREAD_SET_INFORMATION |\n+\t\t\t\t   THREAD_QUERY_INFORMATION, FALSE, thread_id);\n+\tif (thread_handle == NULL) {\n+\t\tret = rte_thread_translate_win32_error(GetLastError());\n+\t\tRTE_LOG_WIN32_ERR(\"OpenThread()\");\n+\t\tgoto cleanup;\n+\t}\n+\n+\tswitch (priority) {\n+\n+\tcase RTE_THREAD_PRIORITY_REALTIME_CRITICAL:\n+\t\tpriority_class = REALTIME_PRIORITY_CLASS;\n+\t\tbreak;\n+\n+\tcase RTE_THREAD_PRIORITY_NORMAL:\n+\t/* FALLTHROUGH */\n+\tdefault:\n+\t\tpriority_class = NORMAL_PRIORITY_CLASS;\n+\t\tpriority = RTE_THREAD_PRIORITY_NORMAL;\n+\t\tbreak;\n+\t}\n+\n+\tprocess_handle = get_process_handle_from_thread_handle(thread_handle);\n+\tif (process_handle == NULL) {\n+\t\tret = rte_thread_translate_win32_error(GetLastError());\n+\t\tRTE_LOG_WIN32_ERR(\"get_process_handle_from_thread_handle()\");\n+\t\tgoto cleanup;\n+\t}\n+\n+\tif (!SetPriorityClass(process_handle, priority_class)) {\n+\t\tret = rte_thread_translate_win32_error(GetLastError());\n+\t\tRTE_LOG_WIN32_ERR(\"SetPriorityClass()\");\n+\t\tgoto cleanup;\n+\t}\n+\n+\tif (!SetThreadPriority(thread_handle, priority)) {\n+\t\tret = rte_thread_translate_win32_error(GetLastError());\n+\t\tRTE_LOG_WIN32_ERR(\"SetThreadPriority()\");\n+\t\tgoto cleanup;\n+\t}\n+\n+cleanup:\n+\tif (thread_handle != NULL) {\n+\t\tCloseHandle(thread_handle);\n+\t\tthread_handle = NULL;\n+\t}\n+\tif (process_handle != NULL) {\n+\t\tCloseHandle(process_handle);\n+\t\tprocess_handle = NULL;\n+\t}\n+\treturn ret;\n+}\n+\n+int\n+rte_thread_attr_init(rte_thread_attr_t *attr)\n+{\n+\tif (attr == NULL) {\n+\t\tRTE_LOG(DEBUG, EAL,\n+\t\t\t\"Unable to init thread attributes, invalid parameter\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tattr->priority = RTE_THREAD_PRIORITY_NORMAL;\n+\tCPU_ZERO(&attr->cpuset);\n+\treturn 0;\n+}\n+\n+int\n+rte_thread_attr_set_affinity(rte_thread_attr_t *thread_attr, rte_cpuset_t *cpuset)\n+{\n+\tif (thread_attr == NULL) {\n+\t\tRTE_LOG(DEBUG, EAL,\n+\t\t\t\"Unable to set affinity attribute, invalid parameter\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tthread_attr->cpuset = *cpuset;\n+\treturn 0;\n+}\n+\n+int\n+rte_thread_attr_get_affinity(rte_thread_attr_t *thread_attr, rte_cpuset_t *cpuset)\n+{\n+\tif (thread_attr == NULL) {\n+\t\tRTE_LOG(DEBUG, EAL,\n+\t\t\t\"Unable to set affinity attribute, invalid parameter\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t*cpuset = thread_attr->cpuset;\n+\treturn 0;\n+}\n+\n+int\n+rte_thread_attr_set_priority(rte_thread_attr_t *thread_attr, enum rte_thread_priority priority)\n+{\n+\tif (thread_attr == NULL) {\n+\t\tRTE_LOG(DEBUG, EAL,\n+\t\t\t\"Unable to set priority attribute, invalid parameter\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tthread_attr->priority = priority;\n+\treturn 0;\n+}\n+\n+int\n+rte_thread_create(rte_thread_t *thread_id,\n+\t\t  const rte_thread_attr_t *thread_attr, void *(*thread_func) (void*),\n+\t\t  void *args)\n+{\n+\tint ret = 0;\n+\tHANDLE thread_handle = NULL;\n+\tGROUP_AFFINITY thread_affinity;\n+\n+\tthread_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)thread_func, args, 0, thread_id);\n+\tif (thread_handle == NULL) {\n+\t\tret = rte_thread_translate_win32_error(GetLastError());\n+\t\tRTE_LOG_WIN32_ERR(\"CreateThread()\");\n+\t\tgoto cleanup;\n+\t}\n+\n+\tif (thread_attr != NULL) {\n+\t\tif (CPU_COUNT(&thread_attr->cpuset) > 0) {\n+\t\t\tret = rte_convert_cpuset_to_affinity(&thread_attr->cpuset, &thread_affinity);\n+\t\t\tif (ret != 0) {\n+\t\t\t\tRTE_LOG(DEBUG, EAL, \"Unable to convert cpuset to thread affinity\\n\");\n+\t\t\t\tgoto cleanup;\n+\t\t\t}\n+\n+\t\t\tif (!SetThreadGroupAffinity(thread_handle, &thread_affinity, NULL)) {\n+\t\t\t\tret = rte_thread_translate_win32_error(GetLastError());\n+\t\t\t\tRTE_LOG_WIN32_ERR(\"SetThreadGroupAffinity()\");\n+\t\t\t\tgoto cleanup;\n+\t\t\t}\n+\t\t}\n+\t\tret = rte_thread_set_priority(*thread_id, thread_attr->priority);\n+\t\tif (ret != 0) {\n+\t\t\tRTE_LOG(DEBUG, EAL, \"Unable to set thread priority\\n\");\n+\t\t\tgoto cleanup;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+\n+cleanup:\n+\tif (thread_handle != NULL) {\n+\t\tCloseHandle(thread_handle);\n+\t\tthread_handle = NULL;\n+\t}\n+\treturn ret;\n+}\n+\n+int\n+rte_thread_join(rte_thread_t thread_id, int *value_ptr)\n+{\n+\tHANDLE thread_handle = NULL;\n+\tDWORD result = 0;\n+\tDWORD exit_code = 0;\n+\tBOOL err = 0;\n+\tint ret = 0;\n+\n+\tthread_handle = OpenThread(SYNCHRONIZE | THREAD_QUERY_INFORMATION, FALSE, thread_id);\n+\tif (thread_handle == NULL) {\n+\t\tret = rte_thread_translate_win32_error(GetLastError());\n+\t\tRTE_LOG_WIN32_ERR(\"OpenThread()\");\n+\t\tgoto cleanup;\n+\t}\n+\n+\tresult = WaitForSingleObject(thread_handle, INFINITE);\n+\tif (result != WAIT_OBJECT_0) {\n+\t\tret = rte_thread_translate_win32_error(GetLastError());\n+\t\tRTE_LOG_WIN32_ERR(\"WaitForSingleObject()\");\n+\t\tgoto cleanup;\n+\t}\n+\n+\tif (value_ptr != NULL) {\n+\t\terr = GetExitCodeThread(thread_handle, &exit_code);\n+\t\tif (err == 0) {\n+\t\t\tret = rte_thread_translate_win32_error(GetLastError());\n+\t\t\tRTE_LOG_WIN32_ERR(\"GetExitCodeThread()\");\n+\t\t\tgoto cleanup;\n+\t\t}\n+\t\t*value_ptr = exit_code;\n+\t}\n+\n+cleanup:\n+\tif (thread_handle != NULL) {\n+\t\tCloseHandle(thread_handle);\n+\t\tthread_handle = NULL;\n+\t}\n+\n+\treturn ret;\n+}\n+\n+int\n+rte_thread_mutex_init(rte_thread_mutex_t *mutex)\n+{\n+\tInitializeCriticalSection(mutex);\n+\treturn 0;\n+}\n+\n+int\n+rte_thread_mutex_lock(rte_thread_mutex_t *mutex)\n+{\n+\tEnterCriticalSection(mutex);\n+\treturn 0;\n+}\n+\n+int\n+rte_thread_mutex_unlock(rte_thread_mutex_t *mutex)\n+{\n+\tLeaveCriticalSection(mutex);\n+\treturn 0;\n+}\n+\n+int\n+rte_thread_mutex_destroy(rte_thread_mutex_t *mutex)\n+{\n+\tDeleteCriticalSection(mutex);\n+\treturn 0;\n+}\n+\n+int\n+rte_thread_barrier_init(rte_thread_barrier_t *barrier, int count)\n+{\n+\tint ret = 0;\n+\n+\tif (!InitializeSynchronizationBarrier(barrier, count, -1)) {\n+\t\tret = rte_thread_translate_win32_error(GetLastError());\n+\t\tRTE_LOG_WIN32_ERR(\"InitializeSynchronizationBarrier()\");\n+\t\treturn ret;\n+\t}\n+\treturn 0;\n+}\n+\n+int\n+rte_thread_barrier_wait(rte_thread_barrier_t *barrier)\n+{\n+\treturn EnterSynchronizationBarrier(barrier,\n+\t\t\t\tSYNCHRONIZATION_BARRIER_FLAGS_BLOCK_ONLY);\n+}\n+\n+int\n+rte_thread_barrier_destroy(rte_thread_barrier_t *barrier)\n+{\n+\tDeleteSynchronizationBarrier(barrier);\n+\treturn 0;\n+}\n+\n+int\n+rte_thread_cancel(rte_thread_t thread_id)\n+{\n+\tint ret = 0;\n+\tHANDLE thread_handle = NULL;\n+\n+\tthread_handle = OpenThread(THREAD_TERMINATE, FALSE, thread_id);\n+\tif (thread_handle == NULL) {\n+\t\tret = rte_thread_translate_win32_error(GetLastError());\n+\t\tRTE_LOG_WIN32_ERR(\"OpenThread()\");\n+\t\tgoto cleanup;\n+\t}\n+\n+\t/*\n+\t * TODO: Behavior is different between POSIX and Windows threads.\n+\t * POSIX threads wait for a cancellation point.\n+\t * Current Windows emulation kills thread at any point.\n+\t */\n+\tret = TerminateThread(thread_handle, 0);\n+\tif (ret != 0) {\n+\t\tret = rte_thread_translate_win32_error(GetLastError());\n+\t\tRTE_LOG_WIN32_ERR(\"TerminateThread()\");\n+\t\tgoto cleanup;\n+\t}\n+\n+cleanup:\n+\tif (thread_handle != NULL) {\n+\t\tCloseHandle(thread_handle);\n+\t\tthread_handle = NULL;\n+\t}\n+\treturn ret;\n+}\n+\n int\n rte_thread_tls_key_create(rte_tls_key *key,\n \t\t__rte_unused void (*destructor)(void *))\n@@ -18,13 +505,13 @@ rte_thread_tls_key_create(rte_tls_key *key,\n \t*key = malloc(sizeof(**key));\n \tif ((*key) == NULL) {\n \t\tRTE_LOG(DEBUG, EAL, \"Cannot allocate TLS key.\\n\");\n-\t\treturn -1;\n+\t\treturn -ENOMEM;\n \t}\n \t(*key)->thread_index = TlsAlloc();\n \tif ((*key)->thread_index == TLS_OUT_OF_INDEXES) {\n \t\tRTE_LOG_WIN32_ERR(\"TlsAlloc()\");\n \t\tfree(*key);\n-\t\treturn -1;\n+\t\treturn rte_thread_translate_win32_error(GetLastError());;\n \t}\n \treturn 0;\n }\n@@ -32,14 +519,14 @@ rte_thread_tls_key_create(rte_tls_key *key,\n int\n rte_thread_tls_key_delete(rte_tls_key key)\n {\n-\tif (!key) {\n+\tif (key == NULL) {\n \t\tRTE_LOG(DEBUG, EAL, \"Invalid TLS key.\\n\");\n-\t\treturn -1;\n+\t\treturn -EINVAL;\n \t}\n \tif (!TlsFree(key->thread_index)) {\n \t\tRTE_LOG_WIN32_ERR(\"TlsFree()\");\n \t\tfree(key);\n-\t\treturn -1;\n+\t\treturn rte_thread_translate_win32_error(GetLastError());\n \t}\n \tfree(key);\n \treturn 0;\n@@ -50,7 +537,7 @@ rte_thread_tls_value_set(rte_tls_key key, const void *value)\n {\n \tchar *p;\n \n-\tif (!key) {\n+\tif (key == NULL) {\n \t\tRTE_LOG(DEBUG, EAL, \"Invalid TLS key.\\n\");\n \t\treturn -1;\n \t}\n@@ -58,7 +545,7 @@ rte_thread_tls_value_set(rte_tls_key key, const void *value)\n \tp = (char *) (uintptr_t) value;\n \tif (!TlsSetValue(key->thread_index, p)) {\n \t\tRTE_LOG_WIN32_ERR(\"TlsSetValue()\");\n-\t\treturn -1;\n+\t\treturn rte_thread_translate_win32_error(GetLastError());\n \t}\n \treturn 0;\n }\n@@ -68,7 +555,7 @@ rte_thread_tls_value_get(rte_tls_key key)\n {\n \tvoid *output;\n \n-\tif (!key) {\n+\tif (key == NULL) {\n \t\tRTE_LOG(DEBUG, EAL, \"Invalid TLS key.\\n\");\n \t\trte_errno = EINVAL;\n \t\treturn NULL;\n",
    "prefixes": [
        "1/3"
    ]
}