]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/dpdk/lib/librte_eal/common/eal_common_thread.c
48ef4d6de6308efa993d3d2135c206d720c28f6a
[ceph.git] / ceph / src / spdk / dpdk / lib / librte_eal / common / eal_common_thread.c
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(&params->configured);
158 if (ret == PTHREAD_BARRIER_SERIAL_THREAD) {
159 pthread_barrier_destroy(&params->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(&params->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(&params->configured);
216 if (ret == PTHREAD_BARRIER_SERIAL_THREAD) {
217 pthread_barrier_destroy(&params->configured);
218 free(params);
219 }
220
221 return 0;
222
223 fail:
224 if (PTHREAD_BARRIER_SERIAL_THREAD ==
225 pthread_barrier_wait(&params->configured)) {
226 pthread_barrier_destroy(&params->configured);
227 free(params);
228 }
229 pthread_cancel(*thread);
230 pthread_join(*thread, NULL);
231 return -ret;
232 }