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