199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 299a2dd95SBruce Richardson * Copyright 2021 Mellanox Technologies, Ltd 356539289STyler Retzlaff * Copyright (C) 2022 Microsoft Corporation 499a2dd95SBruce Richardson */ 599a2dd95SBruce Richardson 699a2dd95SBruce Richardson #include <errno.h> 799a2dd95SBruce Richardson #include <pthread.h> 8b28c6196STyler Retzlaff #include <stdbool.h> 999a2dd95SBruce Richardson #include <stdlib.h> 1099a2dd95SBruce Richardson #include <string.h> 1199a2dd95SBruce Richardson 1299a2dd95SBruce Richardson #include <rte_errno.h> 1399a2dd95SBruce Richardson #include <rte_log.h> 1499a2dd95SBruce Richardson #include <rte_thread.h> 1599a2dd95SBruce Richardson 16*ae67895bSDavid Marchand #include "eal_private.h" 17*ae67895bSDavid Marchand 1899a2dd95SBruce Richardson struct eal_tls_key { 1999a2dd95SBruce Richardson pthread_key_t thread_index; 2099a2dd95SBruce Richardson }; 2199a2dd95SBruce Richardson 22b28c6196STyler Retzlaff struct thread_start_context { 23ce6e911dSTyler Retzlaff rte_thread_func thread_func; 24b28c6196STyler Retzlaff void *thread_args; 25b28c6196STyler Retzlaff const rte_thread_attr_t *thread_attr; 26b28c6196STyler Retzlaff pthread_mutex_t wrapper_mutex; 27b28c6196STyler Retzlaff pthread_cond_t wrapper_cond; 28b28c6196STyler Retzlaff int wrapper_ret; 29b28c6196STyler Retzlaff bool wrapper_done; 30ce6e911dSTyler Retzlaff }; 31ce6e911dSTyler Retzlaff 32ca04c78bSTyler Retzlaff static int 33ca04c78bSTyler Retzlaff thread_map_priority_to_os_value(enum rte_thread_priority eal_pri, int *os_pri, 34ca04c78bSTyler Retzlaff int *pol) 35ca04c78bSTyler Retzlaff { 36ca04c78bSTyler Retzlaff /* Clear the output parameters. */ 37ca04c78bSTyler Retzlaff *os_pri = sched_get_priority_min(SCHED_OTHER) - 1; 38ca04c78bSTyler Retzlaff *pol = -1; 39ca04c78bSTyler Retzlaff 40ca04c78bSTyler Retzlaff switch (eal_pri) { 41ca04c78bSTyler Retzlaff case RTE_THREAD_PRIORITY_NORMAL: 42ca04c78bSTyler Retzlaff *pol = SCHED_OTHER; 43ca04c78bSTyler Retzlaff 44ca04c78bSTyler Retzlaff /* 45ca04c78bSTyler Retzlaff * Choose the middle of the range to represent the priority 46ca04c78bSTyler Retzlaff * 'normal'. 47ca04c78bSTyler Retzlaff * On Linux, this should be 0, since both 48ca04c78bSTyler Retzlaff * sched_get_priority_min/_max return 0 for SCHED_OTHER. 49ca04c78bSTyler Retzlaff */ 50ca04c78bSTyler Retzlaff *os_pri = (sched_get_priority_min(SCHED_OTHER) + 51ca04c78bSTyler Retzlaff sched_get_priority_max(SCHED_OTHER)) / 2; 52ca04c78bSTyler Retzlaff break; 53ca04c78bSTyler Retzlaff case RTE_THREAD_PRIORITY_REALTIME_CRITICAL: 54ca04c78bSTyler Retzlaff *pol = SCHED_RR; 55ca04c78bSTyler Retzlaff *os_pri = sched_get_priority_max(SCHED_RR); 56ca04c78bSTyler Retzlaff break; 57ca04c78bSTyler Retzlaff default: 58*ae67895bSDavid Marchand EAL_LOG(DEBUG, "The requested priority value is invalid."); 59ca04c78bSTyler Retzlaff return EINVAL; 60ca04c78bSTyler Retzlaff } 61ca04c78bSTyler Retzlaff 62ca04c78bSTyler Retzlaff return 0; 63ca04c78bSTyler Retzlaff } 64ca04c78bSTyler Retzlaff 65ca04c78bSTyler Retzlaff static int 66ca04c78bSTyler Retzlaff thread_map_os_priority_to_eal_priority(int policy, int os_pri, 67ca04c78bSTyler Retzlaff enum rte_thread_priority *eal_pri) 68ca04c78bSTyler Retzlaff { 69ca04c78bSTyler Retzlaff switch (policy) { 70ca04c78bSTyler Retzlaff case SCHED_OTHER: 71ca04c78bSTyler Retzlaff if (os_pri == (sched_get_priority_min(SCHED_OTHER) + 72ca04c78bSTyler Retzlaff sched_get_priority_max(SCHED_OTHER)) / 2) { 73ca04c78bSTyler Retzlaff *eal_pri = RTE_THREAD_PRIORITY_NORMAL; 74ca04c78bSTyler Retzlaff return 0; 75ca04c78bSTyler Retzlaff } 76ca04c78bSTyler Retzlaff break; 77ca04c78bSTyler Retzlaff case SCHED_RR: 78ca04c78bSTyler Retzlaff if (os_pri == sched_get_priority_max(SCHED_RR)) { 79ca04c78bSTyler Retzlaff *eal_pri = RTE_THREAD_PRIORITY_REALTIME_CRITICAL; 80ca04c78bSTyler Retzlaff return 0; 81ca04c78bSTyler Retzlaff } 82ca04c78bSTyler Retzlaff break; 83ca04c78bSTyler Retzlaff default: 84*ae67895bSDavid Marchand EAL_LOG(DEBUG, "The OS priority value does not map to an EAL-defined priority."); 85ca04c78bSTyler Retzlaff return EINVAL; 86ca04c78bSTyler Retzlaff } 87ca04c78bSTyler Retzlaff 88ca04c78bSTyler Retzlaff return 0; 89ca04c78bSTyler Retzlaff } 90ca04c78bSTyler Retzlaff 91ce6e911dSTyler Retzlaff static void * 92b28c6196STyler Retzlaff thread_start_wrapper(void *arg) 93ce6e911dSTyler Retzlaff { 94b28c6196STyler Retzlaff struct thread_start_context *ctx = (struct thread_start_context *)arg; 95b28c6196STyler Retzlaff rte_thread_func thread_func = ctx->thread_func; 96b28c6196STyler Retzlaff void *thread_args = ctx->thread_args; 97b28c6196STyler Retzlaff int ret = 0; 98ce6e911dSTyler Retzlaff 99b28c6196STyler Retzlaff if (ctx->thread_attr != NULL && CPU_COUNT(&ctx->thread_attr->cpuset) > 0) { 100b28c6196STyler Retzlaff ret = rte_thread_set_affinity_by_id(rte_thread_self(), &ctx->thread_attr->cpuset); 101b28c6196STyler Retzlaff if (ret != 0) 102*ae67895bSDavid Marchand EAL_LOG(DEBUG, "rte_thread_set_affinity_by_id failed"); 103b28c6196STyler Retzlaff } 104ce6e911dSTyler Retzlaff 105b28c6196STyler Retzlaff pthread_mutex_lock(&ctx->wrapper_mutex); 106b28c6196STyler Retzlaff ctx->wrapper_ret = ret; 107b28c6196STyler Retzlaff ctx->wrapper_done = true; 108b28c6196STyler Retzlaff pthread_cond_signal(&ctx->wrapper_cond); 109b28c6196STyler Retzlaff pthread_mutex_unlock(&ctx->wrapper_mutex); 110b28c6196STyler Retzlaff 111b28c6196STyler Retzlaff if (ret != 0) 112b28c6196STyler Retzlaff return NULL; 113b28c6196STyler Retzlaff 114b28c6196STyler Retzlaff return (void *)(uintptr_t)thread_func(thread_args); 115ce6e911dSTyler Retzlaff } 116ce6e911dSTyler Retzlaff 117ce6e911dSTyler Retzlaff int 118ce6e911dSTyler Retzlaff rte_thread_create(rte_thread_t *thread_id, 119ce6e911dSTyler Retzlaff const rte_thread_attr_t *thread_attr, 120ce6e911dSTyler Retzlaff rte_thread_func thread_func, void *args) 121ce6e911dSTyler Retzlaff { 122ce6e911dSTyler Retzlaff int ret = 0; 123ce6e911dSTyler Retzlaff pthread_attr_t attr; 124ce6e911dSTyler Retzlaff pthread_attr_t *attrp = NULL; 125ce6e911dSTyler Retzlaff struct sched_param param = { 126ce6e911dSTyler Retzlaff .sched_priority = 0, 127ce6e911dSTyler Retzlaff }; 128ce6e911dSTyler Retzlaff int policy = SCHED_OTHER; 129b28c6196STyler Retzlaff struct thread_start_context ctx = { 130b28c6196STyler Retzlaff .thread_func = thread_func, 131b28c6196STyler Retzlaff .thread_args = args, 132b28c6196STyler Retzlaff .thread_attr = thread_attr, 133b28c6196STyler Retzlaff .wrapper_done = false, 134b28c6196STyler Retzlaff .wrapper_mutex = PTHREAD_MUTEX_INITIALIZER, 135b28c6196STyler Retzlaff .wrapper_cond = PTHREAD_COND_INITIALIZER, 136b28c6196STyler Retzlaff }; 137ce6e911dSTyler Retzlaff 138ce6e911dSTyler Retzlaff if (thread_attr != NULL) { 139ce6e911dSTyler Retzlaff ret = pthread_attr_init(&attr); 140ce6e911dSTyler Retzlaff if (ret != 0) { 141*ae67895bSDavid Marchand EAL_LOG(DEBUG, "pthread_attr_init failed"); 142ce6e911dSTyler Retzlaff goto cleanup; 143ce6e911dSTyler Retzlaff } 144ce6e911dSTyler Retzlaff 145ce6e911dSTyler Retzlaff attrp = &attr; 146ce6e911dSTyler Retzlaff 147ce6e911dSTyler Retzlaff /* 148ce6e911dSTyler Retzlaff * Set the inherit scheduler parameter to explicit, 149ce6e911dSTyler Retzlaff * otherwise the priority attribute is ignored. 150ce6e911dSTyler Retzlaff */ 151ce6e911dSTyler Retzlaff ret = pthread_attr_setinheritsched(attrp, 152ce6e911dSTyler Retzlaff PTHREAD_EXPLICIT_SCHED); 153ce6e911dSTyler Retzlaff if (ret != 0) { 154*ae67895bSDavid Marchand EAL_LOG(DEBUG, "pthread_attr_setinheritsched failed"); 155ce6e911dSTyler Retzlaff goto cleanup; 156ce6e911dSTyler Retzlaff } 157ce6e911dSTyler Retzlaff 158ce6e911dSTyler Retzlaff if (thread_attr->priority == 159ce6e911dSTyler Retzlaff RTE_THREAD_PRIORITY_REALTIME_CRITICAL) { 160ce6e911dSTyler Retzlaff ret = ENOTSUP; 161ce6e911dSTyler Retzlaff goto cleanup; 162ce6e911dSTyler Retzlaff } 163ce6e911dSTyler Retzlaff ret = thread_map_priority_to_os_value(thread_attr->priority, 164ce6e911dSTyler Retzlaff ¶m.sched_priority, &policy); 165ce6e911dSTyler Retzlaff if (ret != 0) 166ce6e911dSTyler Retzlaff goto cleanup; 167ce6e911dSTyler Retzlaff 168ce6e911dSTyler Retzlaff ret = pthread_attr_setschedpolicy(attrp, policy); 169ce6e911dSTyler Retzlaff if (ret != 0) { 170*ae67895bSDavid Marchand EAL_LOG(DEBUG, "pthread_attr_setschedpolicy failed"); 171ce6e911dSTyler Retzlaff goto cleanup; 172ce6e911dSTyler Retzlaff } 173ce6e911dSTyler Retzlaff 174ce6e911dSTyler Retzlaff ret = pthread_attr_setschedparam(attrp, ¶m); 175ce6e911dSTyler Retzlaff if (ret != 0) { 176*ae67895bSDavid Marchand EAL_LOG(DEBUG, "pthread_attr_setschedparam failed"); 177ce6e911dSTyler Retzlaff goto cleanup; 178ce6e911dSTyler Retzlaff } 179ce6e911dSTyler Retzlaff } 180ce6e911dSTyler Retzlaff 181ce6e911dSTyler Retzlaff ret = pthread_create((pthread_t *)&thread_id->opaque_id, attrp, 182b28c6196STyler Retzlaff thread_start_wrapper, &ctx); 183ce6e911dSTyler Retzlaff if (ret != 0) { 184*ae67895bSDavid Marchand EAL_LOG(DEBUG, "pthread_create failed"); 185ce6e911dSTyler Retzlaff goto cleanup; 186ce6e911dSTyler Retzlaff } 187ce6e911dSTyler Retzlaff 188b28c6196STyler Retzlaff pthread_mutex_lock(&ctx.wrapper_mutex); 189b28c6196STyler Retzlaff while (!ctx.wrapper_done) 190b28c6196STyler Retzlaff pthread_cond_wait(&ctx.wrapper_cond, &ctx.wrapper_mutex); 191b28c6196STyler Retzlaff ret = ctx.wrapper_ret; 192b28c6196STyler Retzlaff pthread_mutex_unlock(&ctx.wrapper_mutex); 193ce6e911dSTyler Retzlaff 194b28c6196STyler Retzlaff if (ret != 0) 1951c1abf17SThomas Monjalon rte_thread_join(*thread_id, NULL); 196b28c6196STyler Retzlaff 197ce6e911dSTyler Retzlaff cleanup: 198ce6e911dSTyler Retzlaff if (attrp != NULL) 199ce6e911dSTyler Retzlaff pthread_attr_destroy(&attr); 200ce6e911dSTyler Retzlaff 201ce6e911dSTyler Retzlaff return ret; 202ce6e911dSTyler Retzlaff } 203ce6e911dSTyler Retzlaff 204ce6e911dSTyler Retzlaff int 205ce6e911dSTyler Retzlaff rte_thread_join(rte_thread_t thread_id, uint32_t *value_ptr) 206ce6e911dSTyler Retzlaff { 207ce6e911dSTyler Retzlaff int ret = 0; 208ce6e911dSTyler Retzlaff void *res = (void *)(uintptr_t)0; 209ce6e911dSTyler Retzlaff void **pres = NULL; 210ce6e911dSTyler Retzlaff 211ce6e911dSTyler Retzlaff if (value_ptr != NULL) 212ce6e911dSTyler Retzlaff pres = &res; 213ce6e911dSTyler Retzlaff 214ce6e911dSTyler Retzlaff ret = pthread_join((pthread_t)thread_id.opaque_id, pres); 215ce6e911dSTyler Retzlaff if (ret != 0) { 216*ae67895bSDavid Marchand EAL_LOG(DEBUG, "pthread_join failed"); 217ce6e911dSTyler Retzlaff return ret; 218ce6e911dSTyler Retzlaff } 219ce6e911dSTyler Retzlaff 220ce6e911dSTyler Retzlaff if (value_ptr != NULL) 221ce6e911dSTyler Retzlaff *value_ptr = (uint32_t)(uintptr_t)res; 222ce6e911dSTyler Retzlaff 223ce6e911dSTyler Retzlaff return 0; 224ce6e911dSTyler Retzlaff } 225ce6e911dSTyler Retzlaff 226ce6e911dSTyler Retzlaff int 227ce6e911dSTyler Retzlaff rte_thread_detach(rte_thread_t thread_id) 228ce6e911dSTyler Retzlaff { 229ce6e911dSTyler Retzlaff return pthread_detach((pthread_t)thread_id.opaque_id); 230ce6e911dSTyler Retzlaff } 231ce6e911dSTyler Retzlaff 232a2e94ca8STyler Retzlaff int 233a2e94ca8STyler Retzlaff rte_thread_equal(rte_thread_t t1, rte_thread_t t2) 234a2e94ca8STyler Retzlaff { 235a2e94ca8STyler Retzlaff return pthread_equal((pthread_t)t1.opaque_id, (pthread_t)t2.opaque_id); 236a2e94ca8STyler Retzlaff } 237a2e94ca8STyler Retzlaff 23856539289STyler Retzlaff rte_thread_t 23956539289STyler Retzlaff rte_thread_self(void) 24056539289STyler Retzlaff { 24156539289STyler Retzlaff RTE_BUILD_BUG_ON(sizeof(pthread_t) > sizeof(uintptr_t)); 24256539289STyler Retzlaff 24356539289STyler Retzlaff rte_thread_t thread_id; 24456539289STyler Retzlaff 24556539289STyler Retzlaff thread_id.opaque_id = (uintptr_t)pthread_self(); 24656539289STyler Retzlaff 24756539289STyler Retzlaff return thread_id; 24856539289STyler Retzlaff } 24956539289STyler Retzlaff 25099a2dd95SBruce Richardson int 251ca04c78bSTyler Retzlaff rte_thread_get_priority(rte_thread_t thread_id, 252ca04c78bSTyler Retzlaff enum rte_thread_priority *priority) 253ca04c78bSTyler Retzlaff { 254ca04c78bSTyler Retzlaff struct sched_param param; 255ca04c78bSTyler Retzlaff int policy; 256ca04c78bSTyler Retzlaff int ret; 257ca04c78bSTyler Retzlaff 258ca04c78bSTyler Retzlaff ret = pthread_getschedparam((pthread_t)thread_id.opaque_id, &policy, 259ca04c78bSTyler Retzlaff ¶m); 260ca04c78bSTyler Retzlaff if (ret != 0) { 261*ae67895bSDavid Marchand EAL_LOG(DEBUG, "pthread_getschedparam failed"); 262ca04c78bSTyler Retzlaff goto cleanup; 263ca04c78bSTyler Retzlaff } 264ca04c78bSTyler Retzlaff 265ca04c78bSTyler Retzlaff return thread_map_os_priority_to_eal_priority(policy, 266ca04c78bSTyler Retzlaff param.sched_priority, priority); 267ca04c78bSTyler Retzlaff 268ca04c78bSTyler Retzlaff cleanup: 269ca04c78bSTyler Retzlaff return ret; 270ca04c78bSTyler Retzlaff } 271ca04c78bSTyler Retzlaff 272ca04c78bSTyler Retzlaff int 273ca04c78bSTyler Retzlaff rte_thread_set_priority(rte_thread_t thread_id, 274ca04c78bSTyler Retzlaff enum rte_thread_priority priority) 275ca04c78bSTyler Retzlaff { 276ca04c78bSTyler Retzlaff struct sched_param param; 277ca04c78bSTyler Retzlaff int policy; 278ca04c78bSTyler Retzlaff int ret; 279ca04c78bSTyler Retzlaff 280ca04c78bSTyler Retzlaff /* Realtime priority can cause crashes on non-Windows platforms. */ 281ca04c78bSTyler Retzlaff if (priority == RTE_THREAD_PRIORITY_REALTIME_CRITICAL) 282ca04c78bSTyler Retzlaff return ENOTSUP; 283ca04c78bSTyler Retzlaff 284ca04c78bSTyler Retzlaff ret = thread_map_priority_to_os_value(priority, ¶m.sched_priority, 285ca04c78bSTyler Retzlaff &policy); 286ca04c78bSTyler Retzlaff if (ret != 0) 287ca04c78bSTyler Retzlaff return ret; 288ca04c78bSTyler Retzlaff 289ca04c78bSTyler Retzlaff return pthread_setschedparam((pthread_t)thread_id.opaque_id, policy, 290ca04c78bSTyler Retzlaff ¶m); 291ca04c78bSTyler Retzlaff } 292ca04c78bSTyler Retzlaff 293ca04c78bSTyler Retzlaff int 29499a2dd95SBruce Richardson rte_thread_key_create(rte_thread_key *key, void (*destructor)(void *)) 29599a2dd95SBruce Richardson { 29699a2dd95SBruce Richardson int err; 29799a2dd95SBruce Richardson 29899a2dd95SBruce Richardson *key = malloc(sizeof(**key)); 29999a2dd95SBruce Richardson if ((*key) == NULL) { 300*ae67895bSDavid Marchand EAL_LOG(DEBUG, "Cannot allocate TLS key."); 30199a2dd95SBruce Richardson rte_errno = ENOMEM; 30299a2dd95SBruce Richardson return -1; 30399a2dd95SBruce Richardson } 30499a2dd95SBruce Richardson err = pthread_key_create(&((*key)->thread_index), destructor); 30599a2dd95SBruce Richardson if (err) { 306*ae67895bSDavid Marchand EAL_LOG(DEBUG, "pthread_key_create failed: %s", 30799a2dd95SBruce Richardson strerror(err)); 30899a2dd95SBruce Richardson free(*key); 30999a2dd95SBruce Richardson rte_errno = ENOEXEC; 31099a2dd95SBruce Richardson return -1; 31199a2dd95SBruce Richardson } 31299a2dd95SBruce Richardson return 0; 31399a2dd95SBruce Richardson } 31499a2dd95SBruce Richardson 31599a2dd95SBruce Richardson int 31699a2dd95SBruce Richardson rte_thread_key_delete(rte_thread_key key) 31799a2dd95SBruce Richardson { 31899a2dd95SBruce Richardson int err; 31999a2dd95SBruce Richardson 32099a2dd95SBruce Richardson if (!key) { 321*ae67895bSDavid Marchand EAL_LOG(DEBUG, "Invalid TLS key."); 32299a2dd95SBruce Richardson rte_errno = EINVAL; 32399a2dd95SBruce Richardson return -1; 32499a2dd95SBruce Richardson } 32599a2dd95SBruce Richardson err = pthread_key_delete(key->thread_index); 32699a2dd95SBruce Richardson if (err) { 327*ae67895bSDavid Marchand EAL_LOG(DEBUG, "pthread_key_delete failed: %s", 32899a2dd95SBruce Richardson strerror(err)); 32999a2dd95SBruce Richardson free(key); 33099a2dd95SBruce Richardson rte_errno = ENOEXEC; 33199a2dd95SBruce Richardson return -1; 33299a2dd95SBruce Richardson } 33399a2dd95SBruce Richardson free(key); 33499a2dd95SBruce Richardson return 0; 33599a2dd95SBruce Richardson } 33699a2dd95SBruce Richardson 33799a2dd95SBruce Richardson int 33899a2dd95SBruce Richardson rte_thread_value_set(rte_thread_key key, const void *value) 33999a2dd95SBruce Richardson { 34099a2dd95SBruce Richardson int err; 34199a2dd95SBruce Richardson 34299a2dd95SBruce Richardson if (!key) { 343*ae67895bSDavid Marchand EAL_LOG(DEBUG, "Invalid TLS key."); 34499a2dd95SBruce Richardson rte_errno = EINVAL; 34599a2dd95SBruce Richardson return -1; 34699a2dd95SBruce Richardson } 34799a2dd95SBruce Richardson err = pthread_setspecific(key->thread_index, value); 34899a2dd95SBruce Richardson if (err) { 349*ae67895bSDavid Marchand EAL_LOG(DEBUG, "pthread_setspecific failed: %s", 35099a2dd95SBruce Richardson strerror(err)); 35199a2dd95SBruce Richardson rte_errno = ENOEXEC; 35299a2dd95SBruce Richardson return -1; 35399a2dd95SBruce Richardson } 35499a2dd95SBruce Richardson return 0; 35599a2dd95SBruce Richardson } 35699a2dd95SBruce Richardson 35799a2dd95SBruce Richardson void * 35899a2dd95SBruce Richardson rte_thread_value_get(rte_thread_key key) 35999a2dd95SBruce Richardson { 36099a2dd95SBruce Richardson if (!key) { 361*ae67895bSDavid Marchand EAL_LOG(DEBUG, "Invalid TLS key."); 36299a2dd95SBruce Richardson rte_errno = EINVAL; 36399a2dd95SBruce Richardson return NULL; 36499a2dd95SBruce Richardson } 36599a2dd95SBruce Richardson return pthread_getspecific(key->thread_index); 36699a2dd95SBruce Richardson } 367b70a9b78STyler Retzlaff 368b70a9b78STyler Retzlaff int 369b70a9b78STyler Retzlaff rte_thread_set_affinity_by_id(rte_thread_t thread_id, 370b70a9b78STyler Retzlaff const rte_cpuset_t *cpuset) 371b70a9b78STyler Retzlaff { 372b70a9b78STyler Retzlaff return pthread_setaffinity_np((pthread_t)thread_id.opaque_id, 373b70a9b78STyler Retzlaff sizeof(*cpuset), cpuset); 374b70a9b78STyler Retzlaff } 375b70a9b78STyler Retzlaff 376b70a9b78STyler Retzlaff int 377b70a9b78STyler Retzlaff rte_thread_get_affinity_by_id(rte_thread_t thread_id, 378b70a9b78STyler Retzlaff rte_cpuset_t *cpuset) 379b70a9b78STyler Retzlaff { 380b70a9b78STyler Retzlaff return pthread_getaffinity_np((pthread_t)thread_id.opaque_id, 381b70a9b78STyler Retzlaff sizeof(*cpuset), cpuset); 382b70a9b78STyler Retzlaff } 383