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