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