1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2014 Intel Corporation 3 */ 4 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <stdint.h> 8 #include <unistd.h> 9 #include <pthread.h> 10 #include <signal.h> 11 #include <sched.h> 12 #include <assert.h> 13 #include <string.h> 14 15 #include <rte_lcore.h> 16 #include <rte_memory.h> 17 #include <rte_log.h> 18 19 #include "eal_private.h" 20 #include "eal_thread.h" 21 22 RTE_DECLARE_PER_LCORE(unsigned , _socket_id); 23 24 unsigned rte_socket_id(void) 25 { 26 return RTE_PER_LCORE(_socket_id); 27 } 28 29 int 30 rte_lcore_has_role(unsigned int lcore_id, enum rte_lcore_role_t role) 31 { 32 struct rte_config *cfg = rte_eal_get_configuration(); 33 34 if (lcore_id >= RTE_MAX_LCORE) 35 return -EINVAL; 36 37 return cfg->lcore_role[lcore_id] == role; 38 } 39 40 int eal_cpuset_socket_id(rte_cpuset_t *cpusetp) 41 { 42 unsigned cpu = 0; 43 int socket_id = SOCKET_ID_ANY; 44 int sid; 45 46 if (cpusetp == NULL) 47 return SOCKET_ID_ANY; 48 49 do { 50 if (!CPU_ISSET(cpu, cpusetp)) 51 continue; 52 53 if (socket_id == SOCKET_ID_ANY) 54 socket_id = eal_cpu_socket_id(cpu); 55 56 sid = eal_cpu_socket_id(cpu); 57 if (socket_id != sid) { 58 socket_id = SOCKET_ID_ANY; 59 break; 60 } 61 62 } while (++cpu < RTE_MAX_LCORE); 63 64 return socket_id; 65 } 66 67 int 68 rte_thread_set_affinity(rte_cpuset_t *cpusetp) 69 { 70 int s; 71 unsigned lcore_id; 72 pthread_t tid; 73 74 tid = pthread_self(); 75 76 s = pthread_setaffinity_np(tid, sizeof(rte_cpuset_t), cpusetp); 77 if (s != 0) { 78 RTE_LOG(ERR, EAL, "pthread_setaffinity_np failed\n"); 79 return -1; 80 } 81 82 /* store socket_id in TLS for quick access */ 83 RTE_PER_LCORE(_socket_id) = 84 eal_cpuset_socket_id(cpusetp); 85 86 /* store cpuset in TLS for quick access */ 87 memmove(&RTE_PER_LCORE(_cpuset), cpusetp, 88 sizeof(rte_cpuset_t)); 89 90 lcore_id = rte_lcore_id(); 91 if (lcore_id != (unsigned)LCORE_ID_ANY) { 92 /* EAL thread will update lcore_config */ 93 lcore_config[lcore_id].socket_id = RTE_PER_LCORE(_socket_id); 94 memmove(&lcore_config[lcore_id].cpuset, cpusetp, 95 sizeof(rte_cpuset_t)); 96 } 97 98 return 0; 99 } 100 101 void 102 rte_thread_get_affinity(rte_cpuset_t *cpusetp) 103 { 104 assert(cpusetp); 105 memmove(cpusetp, &RTE_PER_LCORE(_cpuset), 106 sizeof(rte_cpuset_t)); 107 } 108 109 int 110 eal_thread_dump_affinity(char *str, unsigned size) 111 { 112 rte_cpuset_t cpuset; 113 unsigned cpu; 114 int ret; 115 unsigned int out = 0; 116 117 rte_thread_get_affinity(&cpuset); 118 119 for (cpu = 0; cpu < RTE_MAX_LCORE; cpu++) { 120 if (!CPU_ISSET(cpu, &cpuset)) 121 continue; 122 123 ret = snprintf(str + out, 124 size - out, "%u,", cpu); 125 if (ret < 0 || (unsigned)ret >= size - out) { 126 /* string will be truncated */ 127 ret = -1; 128 goto exit; 129 } 130 131 out += ret; 132 } 133 134 ret = 0; 135 exit: 136 /* remove the last separator */ 137 if (out > 0) 138 str[out - 1] = '\0'; 139 140 return ret; 141 } 142 143 144 struct rte_thread_ctrl_params { 145 void *(*start_routine)(void *); 146 void *arg; 147 pthread_barrier_t configured; 148 }; 149 150 static void *rte_thread_init(void *arg) 151 { 152 int ret; 153 struct rte_thread_ctrl_params *params = arg; 154 void *(*start_routine)(void *) = params->start_routine; 155 void *routine_arg = params->arg; 156 157 ret = pthread_barrier_wait(¶ms->configured); 158 if (ret == PTHREAD_BARRIER_SERIAL_THREAD) { 159 pthread_barrier_destroy(¶ms->configured); 160 free(params); 161 } 162 163 return start_routine(routine_arg); 164 } 165 166 __rte_experimental int 167 rte_ctrl_thread_create(pthread_t *thread, const char *name, 168 const pthread_attr_t *attr, 169 void *(*start_routine)(void *), void *arg) 170 { 171 struct rte_thread_ctrl_params *params; 172 unsigned int lcore_id; 173 rte_cpuset_t cpuset; 174 int cpu_found, ret; 175 176 params = malloc(sizeof(*params)); 177 if (!params) 178 return -ENOMEM; 179 180 params->start_routine = start_routine; 181 params->arg = arg; 182 183 pthread_barrier_init(¶ms->configured, NULL, 2); 184 185 ret = pthread_create(thread, attr, rte_thread_init, (void *)params); 186 if (ret != 0) { 187 free(params); 188 return -ret; 189 } 190 191 if (name != NULL) { 192 ret = rte_thread_setname(*thread, name); 193 if (ret < 0) 194 RTE_LOG(DEBUG, EAL, 195 "Cannot set name for ctrl thread\n"); 196 } 197 198 cpu_found = 0; 199 CPU_ZERO(&cpuset); 200 for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { 201 if (eal_cpu_detected(lcore_id) && 202 rte_lcore_has_role(lcore_id, ROLE_OFF)) { 203 CPU_SET(lcore_id, &cpuset); 204 cpu_found = 1; 205 } 206 } 207 /* if no detected cpu is off, use master core */ 208 if (!cpu_found) 209 CPU_SET(rte_get_master_lcore(), &cpuset); 210 211 ret = pthread_setaffinity_np(*thread, sizeof(cpuset), &cpuset); 212 if (ret < 0) 213 goto fail; 214 215 ret = pthread_barrier_wait(¶ms->configured); 216 if (ret == PTHREAD_BARRIER_SERIAL_THREAD) { 217 pthread_barrier_destroy(¶ms->configured); 218 free(params); 219 } 220 221 return 0; 222 223 fail: 224 if (PTHREAD_BARRIER_SERIAL_THREAD == 225 pthread_barrier_wait(¶ms->configured)) { 226 pthread_barrier_destroy(¶ms->configured); 227 free(params); 228 } 229 pthread_cancel(*thread); 230 pthread_join(*thread, NULL); 231 return -ret; 232 } 233