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> 899a2dd95SBruce Richardson #include <stdlib.h> 999a2dd95SBruce Richardson #include <string.h> 1099a2dd95SBruce Richardson 1199a2dd95SBruce Richardson #include <rte_errno.h> 1299a2dd95SBruce Richardson #include <rte_log.h> 1399a2dd95SBruce Richardson #include <rte_thread.h> 1499a2dd95SBruce Richardson 1599a2dd95SBruce Richardson struct eal_tls_key { 1699a2dd95SBruce Richardson pthread_key_t thread_index; 1799a2dd95SBruce Richardson }; 1899a2dd95SBruce Richardson 19*ca04c78bSTyler Retzlaff static int 20*ca04c78bSTyler Retzlaff thread_map_priority_to_os_value(enum rte_thread_priority eal_pri, int *os_pri, 21*ca04c78bSTyler Retzlaff int *pol) 22*ca04c78bSTyler Retzlaff { 23*ca04c78bSTyler Retzlaff /* Clear the output parameters. */ 24*ca04c78bSTyler Retzlaff *os_pri = sched_get_priority_min(SCHED_OTHER) - 1; 25*ca04c78bSTyler Retzlaff *pol = -1; 26*ca04c78bSTyler Retzlaff 27*ca04c78bSTyler Retzlaff switch (eal_pri) { 28*ca04c78bSTyler Retzlaff case RTE_THREAD_PRIORITY_NORMAL: 29*ca04c78bSTyler Retzlaff *pol = SCHED_OTHER; 30*ca04c78bSTyler Retzlaff 31*ca04c78bSTyler Retzlaff /* 32*ca04c78bSTyler Retzlaff * Choose the middle of the range to represent the priority 33*ca04c78bSTyler Retzlaff * 'normal'. 34*ca04c78bSTyler Retzlaff * On Linux, this should be 0, since both 35*ca04c78bSTyler Retzlaff * sched_get_priority_min/_max return 0 for SCHED_OTHER. 36*ca04c78bSTyler Retzlaff */ 37*ca04c78bSTyler Retzlaff *os_pri = (sched_get_priority_min(SCHED_OTHER) + 38*ca04c78bSTyler Retzlaff sched_get_priority_max(SCHED_OTHER)) / 2; 39*ca04c78bSTyler Retzlaff break; 40*ca04c78bSTyler Retzlaff case RTE_THREAD_PRIORITY_REALTIME_CRITICAL: 41*ca04c78bSTyler Retzlaff *pol = SCHED_RR; 42*ca04c78bSTyler Retzlaff *os_pri = sched_get_priority_max(SCHED_RR); 43*ca04c78bSTyler Retzlaff break; 44*ca04c78bSTyler Retzlaff default: 45*ca04c78bSTyler Retzlaff RTE_LOG(DEBUG, EAL, "The requested priority value is invalid.\n"); 46*ca04c78bSTyler Retzlaff return EINVAL; 47*ca04c78bSTyler Retzlaff } 48*ca04c78bSTyler Retzlaff 49*ca04c78bSTyler Retzlaff return 0; 50*ca04c78bSTyler Retzlaff } 51*ca04c78bSTyler Retzlaff 52*ca04c78bSTyler Retzlaff static int 53*ca04c78bSTyler Retzlaff thread_map_os_priority_to_eal_priority(int policy, int os_pri, 54*ca04c78bSTyler Retzlaff enum rte_thread_priority *eal_pri) 55*ca04c78bSTyler Retzlaff { 56*ca04c78bSTyler Retzlaff switch (policy) { 57*ca04c78bSTyler Retzlaff case SCHED_OTHER: 58*ca04c78bSTyler Retzlaff if (os_pri == (sched_get_priority_min(SCHED_OTHER) + 59*ca04c78bSTyler Retzlaff sched_get_priority_max(SCHED_OTHER)) / 2) { 60*ca04c78bSTyler Retzlaff *eal_pri = RTE_THREAD_PRIORITY_NORMAL; 61*ca04c78bSTyler Retzlaff return 0; 62*ca04c78bSTyler Retzlaff } 63*ca04c78bSTyler Retzlaff break; 64*ca04c78bSTyler Retzlaff case SCHED_RR: 65*ca04c78bSTyler Retzlaff if (os_pri == sched_get_priority_max(SCHED_RR)) { 66*ca04c78bSTyler Retzlaff *eal_pri = RTE_THREAD_PRIORITY_REALTIME_CRITICAL; 67*ca04c78bSTyler Retzlaff return 0; 68*ca04c78bSTyler Retzlaff } 69*ca04c78bSTyler Retzlaff break; 70*ca04c78bSTyler Retzlaff default: 71*ca04c78bSTyler Retzlaff RTE_LOG(DEBUG, EAL, "The OS priority value does not map to an EAL-defined priority.\n"); 72*ca04c78bSTyler Retzlaff return EINVAL; 73*ca04c78bSTyler Retzlaff } 74*ca04c78bSTyler Retzlaff 75*ca04c78bSTyler Retzlaff return 0; 76*ca04c78bSTyler Retzlaff } 77*ca04c78bSTyler Retzlaff 7856539289STyler Retzlaff rte_thread_t 7956539289STyler Retzlaff rte_thread_self(void) 8056539289STyler Retzlaff { 8156539289STyler Retzlaff RTE_BUILD_BUG_ON(sizeof(pthread_t) > sizeof(uintptr_t)); 8256539289STyler Retzlaff 8356539289STyler Retzlaff rte_thread_t thread_id; 8456539289STyler Retzlaff 8556539289STyler Retzlaff thread_id.opaque_id = (uintptr_t)pthread_self(); 8656539289STyler Retzlaff 8756539289STyler Retzlaff return thread_id; 8856539289STyler Retzlaff } 8956539289STyler Retzlaff 9099a2dd95SBruce Richardson int 91*ca04c78bSTyler Retzlaff rte_thread_get_priority(rte_thread_t thread_id, 92*ca04c78bSTyler Retzlaff enum rte_thread_priority *priority) 93*ca04c78bSTyler Retzlaff { 94*ca04c78bSTyler Retzlaff struct sched_param param; 95*ca04c78bSTyler Retzlaff int policy; 96*ca04c78bSTyler Retzlaff int ret; 97*ca04c78bSTyler Retzlaff 98*ca04c78bSTyler Retzlaff ret = pthread_getschedparam((pthread_t)thread_id.opaque_id, &policy, 99*ca04c78bSTyler Retzlaff ¶m); 100*ca04c78bSTyler Retzlaff if (ret != 0) { 101*ca04c78bSTyler Retzlaff RTE_LOG(DEBUG, EAL, "pthread_getschedparam failed\n"); 102*ca04c78bSTyler Retzlaff goto cleanup; 103*ca04c78bSTyler Retzlaff } 104*ca04c78bSTyler Retzlaff 105*ca04c78bSTyler Retzlaff return thread_map_os_priority_to_eal_priority(policy, 106*ca04c78bSTyler Retzlaff param.sched_priority, priority); 107*ca04c78bSTyler Retzlaff 108*ca04c78bSTyler Retzlaff cleanup: 109*ca04c78bSTyler Retzlaff return ret; 110*ca04c78bSTyler Retzlaff } 111*ca04c78bSTyler Retzlaff 112*ca04c78bSTyler Retzlaff int 113*ca04c78bSTyler Retzlaff rte_thread_set_priority(rte_thread_t thread_id, 114*ca04c78bSTyler Retzlaff enum rte_thread_priority priority) 115*ca04c78bSTyler Retzlaff { 116*ca04c78bSTyler Retzlaff struct sched_param param; 117*ca04c78bSTyler Retzlaff int policy; 118*ca04c78bSTyler Retzlaff int ret; 119*ca04c78bSTyler Retzlaff 120*ca04c78bSTyler Retzlaff /* Realtime priority can cause crashes on non-Windows platforms. */ 121*ca04c78bSTyler Retzlaff if (priority == RTE_THREAD_PRIORITY_REALTIME_CRITICAL) 122*ca04c78bSTyler Retzlaff return ENOTSUP; 123*ca04c78bSTyler Retzlaff 124*ca04c78bSTyler Retzlaff ret = thread_map_priority_to_os_value(priority, ¶m.sched_priority, 125*ca04c78bSTyler Retzlaff &policy); 126*ca04c78bSTyler Retzlaff if (ret != 0) 127*ca04c78bSTyler Retzlaff return ret; 128*ca04c78bSTyler Retzlaff 129*ca04c78bSTyler Retzlaff return pthread_setschedparam((pthread_t)thread_id.opaque_id, policy, 130*ca04c78bSTyler Retzlaff ¶m); 131*ca04c78bSTyler Retzlaff } 132*ca04c78bSTyler Retzlaff 133*ca04c78bSTyler Retzlaff int 13499a2dd95SBruce Richardson rte_thread_key_create(rte_thread_key *key, void (*destructor)(void *)) 13599a2dd95SBruce Richardson { 13699a2dd95SBruce Richardson int err; 13799a2dd95SBruce Richardson 13899a2dd95SBruce Richardson *key = malloc(sizeof(**key)); 13999a2dd95SBruce Richardson if ((*key) == NULL) { 14099a2dd95SBruce Richardson RTE_LOG(DEBUG, EAL, "Cannot allocate TLS key.\n"); 14199a2dd95SBruce Richardson rte_errno = ENOMEM; 14299a2dd95SBruce Richardson return -1; 14399a2dd95SBruce Richardson } 14499a2dd95SBruce Richardson err = pthread_key_create(&((*key)->thread_index), destructor); 14599a2dd95SBruce Richardson if (err) { 14699a2dd95SBruce Richardson RTE_LOG(DEBUG, EAL, "pthread_key_create failed: %s\n", 14799a2dd95SBruce Richardson strerror(err)); 14899a2dd95SBruce Richardson free(*key); 14999a2dd95SBruce Richardson rte_errno = ENOEXEC; 15099a2dd95SBruce Richardson return -1; 15199a2dd95SBruce Richardson } 15299a2dd95SBruce Richardson return 0; 15399a2dd95SBruce Richardson } 15499a2dd95SBruce Richardson 15599a2dd95SBruce Richardson int 15699a2dd95SBruce Richardson rte_thread_key_delete(rte_thread_key key) 15799a2dd95SBruce Richardson { 15899a2dd95SBruce Richardson int err; 15999a2dd95SBruce Richardson 16099a2dd95SBruce Richardson if (!key) { 16199a2dd95SBruce Richardson RTE_LOG(DEBUG, EAL, "Invalid TLS key.\n"); 16299a2dd95SBruce Richardson rte_errno = EINVAL; 16399a2dd95SBruce Richardson return -1; 16499a2dd95SBruce Richardson } 16599a2dd95SBruce Richardson err = pthread_key_delete(key->thread_index); 16699a2dd95SBruce Richardson if (err) { 16799a2dd95SBruce Richardson RTE_LOG(DEBUG, EAL, "pthread_key_delete failed: %s\n", 16899a2dd95SBruce Richardson strerror(err)); 16999a2dd95SBruce Richardson free(key); 17099a2dd95SBruce Richardson rte_errno = ENOEXEC; 17199a2dd95SBruce Richardson return -1; 17299a2dd95SBruce Richardson } 17399a2dd95SBruce Richardson free(key); 17499a2dd95SBruce Richardson return 0; 17599a2dd95SBruce Richardson } 17699a2dd95SBruce Richardson 17799a2dd95SBruce Richardson int 17899a2dd95SBruce Richardson rte_thread_value_set(rte_thread_key key, const void *value) 17999a2dd95SBruce Richardson { 18099a2dd95SBruce Richardson int err; 18199a2dd95SBruce Richardson 18299a2dd95SBruce Richardson if (!key) { 18399a2dd95SBruce Richardson RTE_LOG(DEBUG, EAL, "Invalid TLS key.\n"); 18499a2dd95SBruce Richardson rte_errno = EINVAL; 18599a2dd95SBruce Richardson return -1; 18699a2dd95SBruce Richardson } 18799a2dd95SBruce Richardson err = pthread_setspecific(key->thread_index, value); 18899a2dd95SBruce Richardson if (err) { 18999a2dd95SBruce Richardson RTE_LOG(DEBUG, EAL, "pthread_setspecific failed: %s\n", 19099a2dd95SBruce Richardson strerror(err)); 19199a2dd95SBruce Richardson rte_errno = ENOEXEC; 19299a2dd95SBruce Richardson return -1; 19399a2dd95SBruce Richardson } 19499a2dd95SBruce Richardson return 0; 19599a2dd95SBruce Richardson } 19699a2dd95SBruce Richardson 19799a2dd95SBruce Richardson void * 19899a2dd95SBruce Richardson rte_thread_value_get(rte_thread_key key) 19999a2dd95SBruce Richardson { 20099a2dd95SBruce Richardson if (!key) { 20199a2dd95SBruce Richardson RTE_LOG(DEBUG, EAL, "Invalid TLS key.\n"); 20299a2dd95SBruce Richardson rte_errno = EINVAL; 20399a2dd95SBruce Richardson return NULL; 20499a2dd95SBruce Richardson } 20599a2dd95SBruce Richardson return pthread_getspecific(key->thread_index); 20699a2dd95SBruce Richardson } 207b70a9b78STyler Retzlaff 208b70a9b78STyler Retzlaff int 209b70a9b78STyler Retzlaff rte_thread_set_affinity_by_id(rte_thread_t thread_id, 210b70a9b78STyler Retzlaff const rte_cpuset_t *cpuset) 211b70a9b78STyler Retzlaff { 212b70a9b78STyler Retzlaff return pthread_setaffinity_np((pthread_t)thread_id.opaque_id, 213b70a9b78STyler Retzlaff sizeof(*cpuset), cpuset); 214b70a9b78STyler Retzlaff } 215b70a9b78STyler Retzlaff 216b70a9b78STyler Retzlaff int 217b70a9b78STyler Retzlaff rte_thread_get_affinity_by_id(rte_thread_t thread_id, 218b70a9b78STyler Retzlaff rte_cpuset_t *cpuset) 219b70a9b78STyler Retzlaff { 220b70a9b78STyler Retzlaff return pthread_getaffinity_np((pthread_t)thread_id.opaque_id, 221b70a9b78STyler Retzlaff sizeof(*cpuset), cpuset); 222b70a9b78STyler Retzlaff } 223