fb06f8f802785907054520e2f4cc91c8bc444d04
[dpdk.git] / 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 #include <rte_trace_point.h>
19
20 #include "eal_internal_cfg.h"
21 #include "eal_private.h"
22 #include "eal_thread.h"
23
24 RTE_DEFINE_PER_LCORE(unsigned int, _lcore_id) = LCORE_ID_ANY;
25 RTE_DEFINE_PER_LCORE(int, _thread_id) = -1;
26 static RTE_DEFINE_PER_LCORE(unsigned int, _socket_id) =
27         (unsigned int)SOCKET_ID_ANY;
28 static RTE_DEFINE_PER_LCORE(rte_cpuset_t, _cpuset);
29
30 unsigned rte_socket_id(void)
31 {
32         return RTE_PER_LCORE(_socket_id);
33 }
34
35 int
36 rte_lcore_has_role(unsigned int lcore_id, enum rte_lcore_role_t role)
37 {
38         struct rte_config *cfg = rte_eal_get_configuration();
39
40         if (lcore_id >= RTE_MAX_LCORE)
41                 return -EINVAL;
42
43         return cfg->lcore_role[lcore_id] == role;
44 }
45
46 static int
47 eal_cpuset_socket_id(rte_cpuset_t *cpusetp)
48 {
49         unsigned cpu = 0;
50         int socket_id = SOCKET_ID_ANY;
51         int sid;
52
53         if (cpusetp == NULL)
54                 return SOCKET_ID_ANY;
55
56         do {
57                 if (!CPU_ISSET(cpu, cpusetp))
58                         continue;
59
60                 if (socket_id == SOCKET_ID_ANY)
61                         socket_id = eal_cpu_socket_id(cpu);
62
63                 sid = eal_cpu_socket_id(cpu);
64                 if (socket_id != sid) {
65                         socket_id = SOCKET_ID_ANY;
66                         break;
67                 }
68
69         } while (++cpu < CPU_SETSIZE);
70
71         return socket_id;
72 }
73
74 static void
75 thread_update_affinity(rte_cpuset_t *cpusetp)
76 {
77         unsigned int lcore_id = rte_lcore_id();
78
79         /* store socket_id in TLS for quick access */
80         RTE_PER_LCORE(_socket_id) =
81                 eal_cpuset_socket_id(cpusetp);
82
83         /* store cpuset in TLS for quick access */
84         memmove(&RTE_PER_LCORE(_cpuset), cpusetp,
85                 sizeof(rte_cpuset_t));
86
87         if (lcore_id != (unsigned)LCORE_ID_ANY) {
88                 /* EAL thread will update lcore_config */
89                 lcore_config[lcore_id].socket_id = RTE_PER_LCORE(_socket_id);
90                 memmove(&lcore_config[lcore_id].cpuset, cpusetp,
91                         sizeof(rte_cpuset_t));
92         }
93 }
94
95 int
96 rte_thread_set_affinity(rte_cpuset_t *cpusetp)
97 {
98         if (pthread_setaffinity_np(pthread_self(), sizeof(rte_cpuset_t),
99                         cpusetp) != 0) {
100                 RTE_LOG(ERR, EAL, "pthread_setaffinity_np failed\n");
101                 return -1;
102         }
103
104         thread_update_affinity(cpusetp);
105         return 0;
106 }
107
108 void
109 rte_thread_get_affinity(rte_cpuset_t *cpusetp)
110 {
111         assert(cpusetp);
112         memmove(cpusetp, &RTE_PER_LCORE(_cpuset),
113                 sizeof(rte_cpuset_t));
114 }
115
116 int
117 eal_thread_dump_affinity(char *str, unsigned size)
118 {
119         rte_cpuset_t cpuset;
120         unsigned cpu;
121         int ret;
122         unsigned int out = 0;
123
124         rte_thread_get_affinity(&cpuset);
125
126         for (cpu = 0; cpu < CPU_SETSIZE; cpu++) {
127                 if (!CPU_ISSET(cpu, &cpuset))
128                         continue;
129
130                 ret = snprintf(str + out,
131                                size - out, "%u,", cpu);
132                 if (ret < 0 || (unsigned)ret >= size - out) {
133                         /* string will be truncated */
134                         ret = -1;
135                         goto exit;
136                 }
137
138                 out += ret;
139         }
140
141         ret = 0;
142 exit:
143         /* remove the last separator */
144         if (out > 0)
145                 str[out - 1] = '\0';
146
147         return ret;
148 }
149
150 void
151 __rte_thread_init(unsigned int lcore_id, rte_cpuset_t *cpuset)
152 {
153         /* set the lcore ID in per-lcore memory area */
154         RTE_PER_LCORE(_lcore_id) = lcore_id;
155
156         /* acquire system unique id */
157         rte_gettid();
158
159         thread_update_affinity(cpuset);
160
161         __rte_trace_mem_per_thread_alloc();
162 }
163
164 struct rte_thread_ctrl_params {
165         void *(*start_routine)(void *);
166         void *arg;
167         pthread_barrier_t configured;
168 };
169
170 static void *ctrl_thread_init(void *arg)
171 {
172         int ret;
173         struct internal_config *internal_conf =
174                 eal_get_internal_configuration();
175         rte_cpuset_t *cpuset = &internal_conf->ctrl_cpuset;
176         struct rte_thread_ctrl_params *params = arg;
177         void *(*start_routine)(void *) = params->start_routine;
178         void *routine_arg = params->arg;
179
180         __rte_thread_init(rte_lcore_id(), cpuset);
181
182         ret = pthread_barrier_wait(&params->configured);
183         if (ret == PTHREAD_BARRIER_SERIAL_THREAD) {
184                 pthread_barrier_destroy(&params->configured);
185                 free(params);
186         }
187
188         return start_routine(routine_arg);
189 }
190
191 int
192 rte_ctrl_thread_create(pthread_t *thread, const char *name,
193                 const pthread_attr_t *attr,
194                 void *(*start_routine)(void *), void *arg)
195 {
196         struct internal_config *internal_conf =
197                 eal_get_internal_configuration();
198         rte_cpuset_t *cpuset = &internal_conf->ctrl_cpuset;
199         struct rte_thread_ctrl_params *params;
200         int ret;
201
202         params = malloc(sizeof(*params));
203         if (!params)
204                 return -ENOMEM;
205
206         params->start_routine = start_routine;
207         params->arg = arg;
208
209         pthread_barrier_init(&params->configured, NULL, 2);
210
211         ret = pthread_create(thread, attr, ctrl_thread_init, (void *)params);
212         if (ret != 0) {
213                 free(params);
214                 return -ret;
215         }
216
217         if (name != NULL) {
218                 ret = rte_thread_setname(*thread, name);
219                 if (ret < 0)
220                         RTE_LOG(DEBUG, EAL,
221                                 "Cannot set name for ctrl thread\n");
222         }
223
224         ret = pthread_setaffinity_np(*thread, sizeof(*cpuset), cpuset);
225         if (ret)
226                 goto fail;
227
228         ret = pthread_barrier_wait(&params->configured);
229         if (ret == PTHREAD_BARRIER_SERIAL_THREAD) {
230                 pthread_barrier_destroy(&params->configured);
231                 free(params);
232         }
233
234         return 0;
235
236 fail:
237         if (PTHREAD_BARRIER_SERIAL_THREAD ==
238             pthread_barrier_wait(&params->configured)) {
239                 pthread_barrier_destroy(&params->configured);
240                 free(params);
241         }
242         pthread_cancel(*thread);
243         pthread_join(*thread, NULL);
244         return -ret;
245 }