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