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