Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2014 Intel Corporation
3 : : */
4 : :
5 : : #include <errno.h>
6 : : #include <stdio.h>
7 : : #include <stdlib.h>
8 : : #include <pthread.h>
9 : : #include <sched.h>
10 : : #include <assert.h>
11 : : #include <string.h>
12 : :
13 : : #include <eal_export.h>
14 : : #include <eal_trace_internal.h>
15 : : #include <rte_errno.h>
16 : : #include <rte_lcore.h>
17 : : #include <rte_log.h>
18 : : #include <rte_memory.h>
19 : : #include <rte_trace_point.h>
20 : :
21 : : #include "eal_internal_cfg.h"
22 : : #include "eal_private.h"
23 : : #include "eal_thread.h"
24 : : #include "eal_trace.h"
25 : :
26 : : RTE_EXPORT_SYMBOL(per_lcore__lcore_id)
27 : : RTE_DEFINE_PER_LCORE(unsigned int, _lcore_id) = LCORE_ID_ANY;
28 : : RTE_EXPORT_SYMBOL(per_lcore__thread_id)
29 : : RTE_DEFINE_PER_LCORE(int, _thread_id) = -1;
30 : : static RTE_DEFINE_PER_LCORE(unsigned int, _numa_id) =
31 : : (unsigned int)SOCKET_ID_ANY;
32 : : static RTE_DEFINE_PER_LCORE(rte_cpuset_t, _cpuset);
33 : :
34 : : RTE_EXPORT_SYMBOL(rte_socket_id)
35 : 109061 : unsigned rte_socket_id(void)
36 : : {
37 : 109061 : return RTE_PER_LCORE(_numa_id);
38 : : }
39 : :
40 : : static int
41 : 801 : eal_cpuset_socket_id(rte_cpuset_t *cpusetp)
42 : : {
43 : : unsigned cpu = 0;
44 : : int socket_id = SOCKET_ID_ANY;
45 : : int sid;
46 : :
47 [ + - ]: 801 : if (cpusetp == NULL)
48 : : return SOCKET_ID_ANY;
49 : :
50 : : do {
51 [ + + ]: 820224 : if (!CPU_ISSET(cpu, cpusetp))
52 : 819423 : continue;
53 : :
54 [ + - ]: 801 : if (socket_id == SOCKET_ID_ANY)
55 : 801 : socket_id = eal_cpu_socket_id(cpu);
56 : :
57 : 801 : sid = eal_cpu_socket_id(cpu);
58 [ + - ]: 801 : if (socket_id != sid) {
59 : : socket_id = SOCKET_ID_ANY;
60 : : break;
61 : : }
62 : :
63 [ + + ]: 820224 : } while (++cpu < CPU_SETSIZE);
64 : :
65 : : return socket_id;
66 : : }
67 : :
68 : : static void
69 : 801 : thread_update_affinity(rte_cpuset_t *cpusetp)
70 : : {
71 : : unsigned int lcore_id = rte_lcore_id();
72 : :
73 : : /* store numa_id in TLS for quick access */
74 : 801 : RTE_PER_LCORE(_numa_id) =
75 [ + + ]: 801 : eal_cpuset_socket_id(cpusetp);
76 : :
77 : : /* store cpuset in TLS for quick access */
78 : : memmove(&RTE_PER_LCORE(_cpuset), cpusetp,
79 : : sizeof(rte_cpuset_t));
80 : :
81 [ + + ]: 801 : if (lcore_id != (unsigned)LCORE_ID_ANY) {
82 : : /* EAL thread will update lcore_config */
83 : 432 : lcore_config[lcore_id].numa_id = RTE_PER_LCORE(_numa_id);
84 : 432 : memmove(&lcore_config[lcore_id].cpuset, cpusetp,
85 : : sizeof(rte_cpuset_t));
86 : : }
87 : 801 : }
88 : :
89 : : RTE_EXPORT_SYMBOL(rte_thread_set_affinity)
90 : : int
91 : 0 : rte_thread_set_affinity(rte_cpuset_t *cpusetp)
92 : : {
93 [ # # ]: 0 : if (rte_thread_set_affinity_by_id(rte_thread_self(), cpusetp) != 0) {
94 : 0 : EAL_LOG(ERR, "rte_thread_set_affinity_by_id failed");
95 : 0 : return -1;
96 : : }
97 : :
98 : 0 : thread_update_affinity(cpusetp);
99 : 0 : return 0;
100 : : }
101 : :
102 : : RTE_EXPORT_SYMBOL(rte_thread_get_affinity)
103 : : void
104 : 305 : rte_thread_get_affinity(rte_cpuset_t *cpusetp)
105 : : {
106 [ - + ]: 305 : assert(cpusetp);
107 : : memmove(cpusetp, &RTE_PER_LCORE(_cpuset),
108 : : sizeof(rte_cpuset_t));
109 : 305 : }
110 : :
111 : : int
112 : 305 : eal_thread_dump_current_affinity(char *str, unsigned int size)
113 : : {
114 : : rte_cpuset_t cpuset;
115 : : char *cpuset_str;
116 : : int ret;
117 : :
118 : 305 : rte_thread_get_affinity(&cpuset);
119 : 305 : cpuset_str = eal_cpuset_to_str(&cpuset);
120 [ + - ]: 305 : if (cpuset_str == NULL)
121 : : return -1;
122 : :
123 [ - + ]: 305 : ret = snprintf(str, size, "%s", cpuset_str);
124 : 305 : free(cpuset_str);
125 : :
126 [ - + ]: 305 : if (ret < 0 || (unsigned int)ret >= size)
127 : 0 : return -1;
128 : :
129 : : return 0;
130 : : }
131 : :
132 : : void
133 : 801 : __rte_thread_init(unsigned int lcore_id, rte_cpuset_t *cpuset)
134 : : {
135 : : /* set the lcore ID in per-lcore memory area */
136 [ + + ]: 801 : RTE_PER_LCORE(_lcore_id) = lcore_id;
137 : :
138 : : /* acquire system unique id */
139 : : rte_gettid();
140 : :
141 : 801 : thread_update_affinity(cpuset);
142 : :
143 : 801 : __rte_trace_mem_per_thread_alloc();
144 : 801 : }
145 : :
146 : : void
147 : 129 : __rte_thread_uninit(void)
148 : : {
149 : 129 : trace_mem_per_thread_free();
150 : :
151 : 129 : RTE_PER_LCORE(_lcore_id) = LCORE_ID_ANY;
152 : 129 : }
153 : :
154 : : /* main loop of threads */
155 : : __rte_noreturn uint32_t
156 : 124 : eal_thread_loop(void *arg)
157 : : {
158 : 124 : unsigned int lcore_id = (uintptr_t)arg;
159 : : char cpuset[RTE_CPU_AFFINITY_STR_LEN];
160 : : int ret;
161 : :
162 : 124 : __rte_thread_init(lcore_id, &lcore_config[lcore_id].cpuset);
163 : :
164 : 124 : ret = eal_thread_dump_current_affinity(cpuset, sizeof(cpuset));
165 [ - + ]: 124 : EAL_LOG(DEBUG, "lcore %u is ready (tid=%zx;cpuset=[%s%s])",
166 : : lcore_id, rte_thread_self().opaque_id, cpuset,
167 : : ret == 0 ? "" : "...");
168 : :
169 : 124 : rte_eal_trace_thread_lcore_ready(lcore_id, cpuset);
170 : :
171 : : /* read on our pipe to get commands */
172 : 191 : while (1) {
173 : : lcore_function_t *f;
174 : : void *fct_arg;
175 : :
176 : 315 : eal_thread_wait_command();
177 : :
178 : : /* Set the state to 'RUNNING'. Use release order
179 : : * since 'state' variable is used as the guard variable.
180 : : */
181 : 191 : rte_atomic_store_explicit(&lcore_config[lcore_id].state, RUNNING,
182 : : rte_memory_order_release);
183 : :
184 : 191 : eal_thread_ack_command();
185 : :
186 : : /* Load 'f' with acquire order to ensure that
187 : : * the memory operations from the main thread
188 : : * are accessed only after update to 'f' is visible.
189 : : * Wait till the update to 'f' is visible to the worker.
190 : : */
191 : 191 : while ((f = rte_atomic_load_explicit(&lcore_config[lcore_id].f,
192 [ - + ]: 191 : rte_memory_order_acquire)) == NULL)
193 : : rte_pause();
194 : :
195 : 191 : rte_eal_trace_thread_lcore_running(lcore_id, f);
196 : :
197 : : /* call the function and store the return value */
198 : 191 : fct_arg = lcore_config[lcore_id].arg;
199 : 191 : ret = f(fct_arg);
200 : 191 : lcore_config[lcore_id].ret = ret;
201 : 191 : lcore_config[lcore_id].f = NULL;
202 : 191 : lcore_config[lcore_id].arg = NULL;
203 : :
204 : : /* Store the state with release order to ensure that
205 : : * the memory operations from the worker thread
206 : : * are completed before the state is updated.
207 : : * Use 'state' as the guard variable.
208 : : */
209 [ + + ]: 191 : rte_atomic_store_explicit(&lcore_config[lcore_id].state, WAIT,
210 : : rte_memory_order_release);
211 : :
212 : 191 : rte_eal_trace_thread_lcore_stopped(lcore_id);
213 : : }
214 : :
215 : : /* never reached */
216 : : /* return 0; */
217 : : }
218 : :
219 : : enum __rte_ctrl_thread_status {
220 : : CTRL_THREAD_LAUNCHING, /* Yet to call pthread_create function */
221 : : CTRL_THREAD_RUNNING, /* Control thread is running successfully */
222 : : CTRL_THREAD_ERROR /* Control thread encountered an error */
223 : : };
224 : :
225 : : struct control_thread_params {
226 : : rte_thread_func start_routine;
227 : : void *arg;
228 : : int ret;
229 : : /* Control thread status.
230 : : * If the status is CTRL_THREAD_ERROR, 'ret' has the error code.
231 : : */
232 : : RTE_ATOMIC(enum __rte_ctrl_thread_status) status;
233 : : };
234 : :
235 : 367 : static int control_thread_init(void *arg)
236 : : {
237 : : struct internal_config *internal_conf =
238 : 367 : eal_get_internal_configuration();
239 : 367 : rte_cpuset_t *cpuset = &internal_conf->ctrl_cpuset;
240 : : struct control_thread_params *params = arg;
241 : :
242 : 367 : __rte_thread_init(rte_lcore_id(), cpuset);
243 : : /* Set control thread socket ID to SOCKET_ID_ANY
244 : : * as control threads may be scheduled on any NUMA node.
245 : : */
246 : 367 : RTE_PER_LCORE(_numa_id) = SOCKET_ID_ANY;
247 : 367 : params->ret = rte_thread_set_affinity_by_id(rte_thread_self(), cpuset);
248 [ - + ]: 367 : if (params->ret != 0) {
249 : 0 : rte_atomic_store_explicit(¶ms->status,
250 : : CTRL_THREAD_ERROR, rte_memory_order_release);
251 : 0 : return 1;
252 : : }
253 : :
254 : 367 : rte_atomic_store_explicit(¶ms->status,
255 : : CTRL_THREAD_RUNNING, rte_memory_order_release);
256 : :
257 : 367 : return 0;
258 : : }
259 : :
260 : 367 : static uint32_t control_thread_start(void *arg)
261 : : {
262 : : struct control_thread_params *params = arg;
263 : 367 : void *start_arg = params->arg;
264 : 367 : rte_thread_func start_routine = params->start_routine;
265 : :
266 [ + - ]: 367 : if (control_thread_init(arg) != 0)
267 : : return 0;
268 : :
269 : 367 : return start_routine(start_arg);
270 : : }
271 : :
272 : : RTE_EXPORT_SYMBOL(rte_thread_create_control)
273 : : int
274 : 367 : rte_thread_create_control(rte_thread_t *thread, const char *name,
275 : : rte_thread_func start_routine, void *arg)
276 : : {
277 : : struct control_thread_params *params;
278 : : enum __rte_ctrl_thread_status ctrl_thread_status;
279 : : int ret;
280 : :
281 : 367 : params = malloc(sizeof(*params));
282 [ + - ]: 367 : if (params == NULL)
283 : : return -ENOMEM;
284 : :
285 : 367 : params->start_routine = start_routine;
286 : 367 : params->arg = arg;
287 : 367 : params->ret = 0;
288 : 367 : params->status = CTRL_THREAD_LAUNCHING;
289 : :
290 : 367 : ret = rte_thread_create(thread, NULL, control_thread_start, params);
291 [ - + ]: 367 : if (ret != 0) {
292 : 0 : free(params);
293 : 0 : return -ret;
294 : : }
295 : :
296 [ + - ]: 367 : if (name != NULL)
297 : 367 : rte_thread_set_name(*thread, name);
298 : :
299 : : /* Wait for the control thread to initialize successfully */
300 : : while ((ctrl_thread_status =
301 : 868 : rte_atomic_load_explicit(¶ms->status,
302 [ + + ]: 868 : rte_memory_order_acquire)) == CTRL_THREAD_LAUNCHING) {
303 : 501 : rte_delay_us_sleep(1);
304 : : }
305 : :
306 : : /* Check if the control thread encountered an error */
307 [ - + ]: 367 : if (ctrl_thread_status == CTRL_THREAD_ERROR) {
308 : : /* ctrl thread is exiting */
309 : 0 : rte_thread_join(*thread, NULL);
310 : : }
311 : :
312 : 367 : ret = params->ret;
313 : 367 : free(params);
314 : :
315 : 367 : return ret;
316 : : }
317 : :
318 : : static void
319 : 365 : add_internal_prefix(char *prefixed_name, const char *name, size_t size)
320 : : {
321 : : size_t prefixlen;
322 : :
323 : : /* Check RTE_THREAD_INTERNAL_NAME_SIZE definition. */
324 : : RTE_BUILD_BUG_ON(RTE_THREAD_INTERNAL_NAME_SIZE !=
325 : : RTE_THREAD_NAME_SIZE - sizeof(RTE_THREAD_INTERNAL_PREFIX) + 1);
326 : :
327 : : prefixlen = strlen(RTE_THREAD_INTERNAL_PREFIX);
328 : : strlcpy(prefixed_name, RTE_THREAD_INTERNAL_PREFIX, size);
329 : 365 : strlcpy(prefixed_name + prefixlen, name, size - prefixlen);
330 : 365 : }
331 : :
332 : : RTE_EXPORT_INTERNAL_SYMBOL(rte_thread_create_internal_control)
333 : : int
334 : 365 : rte_thread_create_internal_control(rte_thread_t *id, const char *name,
335 : : rte_thread_func func, void *arg)
336 : : {
337 : : char prefixed_name[RTE_THREAD_NAME_SIZE];
338 : :
339 : 365 : add_internal_prefix(prefixed_name, name, sizeof(prefixed_name));
340 : 365 : return rte_thread_create_control(id, prefixed_name, func, arg);
341 : : }
342 : :
343 : : RTE_EXPORT_INTERNAL_SYMBOL(rte_thread_set_prefixed_name)
344 : : void
345 : 0 : rte_thread_set_prefixed_name(rte_thread_t id, const char *name)
346 : : {
347 : : char prefixed_name[RTE_THREAD_NAME_SIZE];
348 : :
349 : 0 : add_internal_prefix(prefixed_name, name, sizeof(prefixed_name));
350 : 0 : rte_thread_set_name(id, prefixed_name);
351 : 0 : }
352 : :
353 : : RTE_EXPORT_SYMBOL(rte_thread_register)
354 : : int
355 : 129 : rte_thread_register(void)
356 : : {
357 : : unsigned int lcore_id;
358 : : rte_cpuset_t cpuset;
359 : :
360 : : /* EAL init flushes all lcores, we can't register before. */
361 [ - + ]: 129 : if (eal_get_internal_configuration()->init_complete != 1) {
362 : 0 : EAL_LOG(DEBUG, "Called %s before EAL init.", __func__);
363 : 0 : rte_errno = EINVAL;
364 : 0 : return -1;
365 : : }
366 [ - + ]: 129 : if (!rte_mp_disable()) {
367 : 0 : EAL_LOG(ERR, "Multiprocess in use, registering non-EAL threads is not supported.");
368 : 0 : rte_errno = EINVAL;
369 : 0 : return -1;
370 : : }
371 [ - + ]: 129 : if (rte_thread_get_affinity_by_id(rte_thread_self(), &cpuset) != 0)
372 : 0 : CPU_ZERO(&cpuset);
373 : 129 : lcore_id = eal_lcore_non_eal_allocate();
374 [ + + ]: 129 : if (lcore_id >= RTE_MAX_LCORE)
375 : : lcore_id = LCORE_ID_ANY;
376 : 129 : __rte_thread_init(lcore_id, &cpuset);
377 [ + + ]: 129 : if (lcore_id == LCORE_ID_ANY) {
378 : 2 : rte_errno = ENOMEM;
379 : 2 : return -1;
380 : : }
381 : 127 : EAL_LOG(DEBUG, "Registered non-EAL thread as lcore %u.",
382 : : lcore_id);
383 : 127 : return 0;
384 : : }
385 : :
386 : : RTE_EXPORT_SYMBOL(rte_thread_unregister)
387 : : void
388 [ + + ]: 129 : rte_thread_unregister(void)
389 : : {
390 : : unsigned int lcore_id = rte_lcore_id();
391 : :
392 [ + + ]: 129 : if (lcore_id != LCORE_ID_ANY)
393 : 127 : eal_lcore_non_eal_release(lcore_id);
394 : 129 : __rte_thread_uninit();
395 [ + + ]: 129 : if (lcore_id != LCORE_ID_ANY)
396 : 127 : EAL_LOG(DEBUG, "Unregistered non-EAL thread (was lcore %u).",
397 : : lcore_id);
398 : 129 : }
399 : :
400 : : RTE_EXPORT_SYMBOL(rte_thread_attr_init)
401 : : int
402 : 2 : rte_thread_attr_init(rte_thread_attr_t *attr)
403 : : {
404 [ + - ]: 2 : if (attr == NULL)
405 : : return EINVAL;
406 : :
407 : 2 : CPU_ZERO(&attr->cpuset);
408 : 2 : attr->priority = RTE_THREAD_PRIORITY_NORMAL;
409 : :
410 : 2 : return 0;
411 : : }
412 : :
413 : : RTE_EXPORT_SYMBOL(rte_thread_attr_set_priority)
414 : : int
415 : 1 : rte_thread_attr_set_priority(rte_thread_attr_t *thread_attr,
416 : : enum rte_thread_priority priority)
417 : : {
418 [ + - ]: 1 : if (thread_attr == NULL)
419 : : return EINVAL;
420 : :
421 : 1 : thread_attr->priority = priority;
422 : :
423 : 1 : return 0;
424 : : }
425 : :
426 : : RTE_EXPORT_SYMBOL(rte_thread_attr_set_affinity)
427 : : int
428 : 1 : rte_thread_attr_set_affinity(rte_thread_attr_t *thread_attr,
429 : : rte_cpuset_t *cpuset)
430 : : {
431 [ + - ]: 1 : if (thread_attr == NULL)
432 : : return EINVAL;
433 : :
434 [ + - ]: 1 : if (cpuset == NULL)
435 : : return EINVAL;
436 : :
437 : 1 : thread_attr->cpuset = *cpuset;
438 : :
439 : 1 : return 0;
440 : : }
441 : :
442 : : RTE_EXPORT_SYMBOL(rte_thread_attr_get_affinity)
443 : : int
444 : 1 : rte_thread_attr_get_affinity(rte_thread_attr_t *thread_attr,
445 : : rte_cpuset_t *cpuset)
446 : : {
447 [ + - ]: 1 : if (thread_attr == NULL)
448 : : return EINVAL;
449 : :
450 [ + - ]: 1 : if (cpuset == NULL)
451 : : return EINVAL;
452 : :
453 : 1 : *cpuset = thread_attr->cpuset;
454 : :
455 : 1 : return 0;
456 : : }
|