1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright 2021 Mellanox Technologies, Ltd 3 * Copyright (C) 2022 Microsoft Corporation 4 */ 5 6 #include <errno.h> 7 #include <pthread.h> 8 #include <stdlib.h> 9 #include <string.h> 10 11 #include <rte_errno.h> 12 #include <rte_log.h> 13 #include <rte_thread.h> 14 15 struct eal_tls_key { 16 pthread_key_t thread_index; 17 }; 18 19 static int 20 thread_map_priority_to_os_value(enum rte_thread_priority eal_pri, int *os_pri, 21 int *pol) 22 { 23 /* Clear the output parameters. */ 24 *os_pri = sched_get_priority_min(SCHED_OTHER) - 1; 25 *pol = -1; 26 27 switch (eal_pri) { 28 case RTE_THREAD_PRIORITY_NORMAL: 29 *pol = SCHED_OTHER; 30 31 /* 32 * Choose the middle of the range to represent the priority 33 * 'normal'. 34 * On Linux, this should be 0, since both 35 * sched_get_priority_min/_max return 0 for SCHED_OTHER. 36 */ 37 *os_pri = (sched_get_priority_min(SCHED_OTHER) + 38 sched_get_priority_max(SCHED_OTHER)) / 2; 39 break; 40 case RTE_THREAD_PRIORITY_REALTIME_CRITICAL: 41 *pol = SCHED_RR; 42 *os_pri = sched_get_priority_max(SCHED_RR); 43 break; 44 default: 45 RTE_LOG(DEBUG, EAL, "The requested priority value is invalid.\n"); 46 return EINVAL; 47 } 48 49 return 0; 50 } 51 52 static int 53 thread_map_os_priority_to_eal_priority(int policy, int os_pri, 54 enum rte_thread_priority *eal_pri) 55 { 56 switch (policy) { 57 case SCHED_OTHER: 58 if (os_pri == (sched_get_priority_min(SCHED_OTHER) + 59 sched_get_priority_max(SCHED_OTHER)) / 2) { 60 *eal_pri = RTE_THREAD_PRIORITY_NORMAL; 61 return 0; 62 } 63 break; 64 case SCHED_RR: 65 if (os_pri == sched_get_priority_max(SCHED_RR)) { 66 *eal_pri = RTE_THREAD_PRIORITY_REALTIME_CRITICAL; 67 return 0; 68 } 69 break; 70 default: 71 RTE_LOG(DEBUG, EAL, "The OS priority value does not map to an EAL-defined priority.\n"); 72 return EINVAL; 73 } 74 75 return 0; 76 } 77 78 rte_thread_t 79 rte_thread_self(void) 80 { 81 RTE_BUILD_BUG_ON(sizeof(pthread_t) > sizeof(uintptr_t)); 82 83 rte_thread_t thread_id; 84 85 thread_id.opaque_id = (uintptr_t)pthread_self(); 86 87 return thread_id; 88 } 89 90 int 91 rte_thread_get_priority(rte_thread_t thread_id, 92 enum rte_thread_priority *priority) 93 { 94 struct sched_param param; 95 int policy; 96 int ret; 97 98 ret = pthread_getschedparam((pthread_t)thread_id.opaque_id, &policy, 99 ¶m); 100 if (ret != 0) { 101 RTE_LOG(DEBUG, EAL, "pthread_getschedparam failed\n"); 102 goto cleanup; 103 } 104 105 return thread_map_os_priority_to_eal_priority(policy, 106 param.sched_priority, priority); 107 108 cleanup: 109 return ret; 110 } 111 112 int 113 rte_thread_set_priority(rte_thread_t thread_id, 114 enum rte_thread_priority priority) 115 { 116 struct sched_param param; 117 int policy; 118 int ret; 119 120 /* Realtime priority can cause crashes on non-Windows platforms. */ 121 if (priority == RTE_THREAD_PRIORITY_REALTIME_CRITICAL) 122 return ENOTSUP; 123 124 ret = thread_map_priority_to_os_value(priority, ¶m.sched_priority, 125 &policy); 126 if (ret != 0) 127 return ret; 128 129 return pthread_setschedparam((pthread_t)thread_id.opaque_id, policy, 130 ¶m); 131 } 132 133 int 134 rte_thread_key_create(rte_thread_key *key, void (*destructor)(void *)) 135 { 136 int err; 137 138 *key = malloc(sizeof(**key)); 139 if ((*key) == NULL) { 140 RTE_LOG(DEBUG, EAL, "Cannot allocate TLS key.\n"); 141 rte_errno = ENOMEM; 142 return -1; 143 } 144 err = pthread_key_create(&((*key)->thread_index), destructor); 145 if (err) { 146 RTE_LOG(DEBUG, EAL, "pthread_key_create failed: %s\n", 147 strerror(err)); 148 free(*key); 149 rte_errno = ENOEXEC; 150 return -1; 151 } 152 return 0; 153 } 154 155 int 156 rte_thread_key_delete(rte_thread_key key) 157 { 158 int err; 159 160 if (!key) { 161 RTE_LOG(DEBUG, EAL, "Invalid TLS key.\n"); 162 rte_errno = EINVAL; 163 return -1; 164 } 165 err = pthread_key_delete(key->thread_index); 166 if (err) { 167 RTE_LOG(DEBUG, EAL, "pthread_key_delete failed: %s\n", 168 strerror(err)); 169 free(key); 170 rte_errno = ENOEXEC; 171 return -1; 172 } 173 free(key); 174 return 0; 175 } 176 177 int 178 rte_thread_value_set(rte_thread_key key, const void *value) 179 { 180 int err; 181 182 if (!key) { 183 RTE_LOG(DEBUG, EAL, "Invalid TLS key.\n"); 184 rte_errno = EINVAL; 185 return -1; 186 } 187 err = pthread_setspecific(key->thread_index, value); 188 if (err) { 189 RTE_LOG(DEBUG, EAL, "pthread_setspecific failed: %s\n", 190 strerror(err)); 191 rte_errno = ENOEXEC; 192 return -1; 193 } 194 return 0; 195 } 196 197 void * 198 rte_thread_value_get(rte_thread_key key) 199 { 200 if (!key) { 201 RTE_LOG(DEBUG, EAL, "Invalid TLS key.\n"); 202 rte_errno = EINVAL; 203 return NULL; 204 } 205 return pthread_getspecific(key->thread_index); 206 } 207 208 int 209 rte_thread_set_affinity_by_id(rte_thread_t thread_id, 210 const rte_cpuset_t *cpuset) 211 { 212 return pthread_setaffinity_np((pthread_t)thread_id.opaque_id, 213 sizeof(*cpuset), cpuset); 214 } 215 216 int 217 rte_thread_get_affinity_by_id(rte_thread_t thread_id, 218 rte_cpuset_t *cpuset) 219 { 220 return pthread_getaffinity_np((pthread_t)thread_id.opaque_id, 221 sizeof(*cpuset), cpuset); 222 } 223