New upstream version 18.08
[deb_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         int ret;
153         struct rte_thread_ctrl_params *params = arg;
154         void *(*start_routine)(void *) = params->start_routine;
155         void *routine_arg = params->arg;
156
157         ret = pthread_barrier_wait(&params->configured);
158         if (ret == PTHREAD_BARRIER_SERIAL_THREAD) {
159                 pthread_barrier_destroy(&params->configured);
160                 free(params);
161         }
162
163         return start_routine(routine_arg);
164 }
165
166 __rte_experimental int
167 rte_ctrl_thread_create(pthread_t *thread, const char *name,
168                 const pthread_attr_t *attr,
169                 void *(*start_routine)(void *), void *arg)
170 {
171         struct rte_thread_ctrl_params *params;
172         unsigned int lcore_id;
173         rte_cpuset_t cpuset;
174         int cpu_found, ret;
175
176         params = malloc(sizeof(*params));
177         if (!params)
178                 return -ENOMEM;
179
180         params->start_routine = start_routine;
181         params->arg = arg;
182
183         pthread_barrier_init(&params->configured, NULL, 2);
184
185         ret = pthread_create(thread, attr, rte_thread_init, (void *)params);
186         if (ret != 0) {
187                 free(params);
188                 return -ret;
189         }
190
191         if (name != NULL) {
192                 ret = rte_thread_setname(*thread, name);
193                 if (ret < 0)
194                         RTE_LOG(DEBUG, EAL,
195                                 "Cannot set name for ctrl thread\n");
196         }
197
198         cpu_found = 0;
199         CPU_ZERO(&cpuset);
200         for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
201                 if (eal_cpu_detected(lcore_id) &&
202                                 rte_lcore_has_role(lcore_id, ROLE_OFF)) {
203                         CPU_SET(lcore_id, &cpuset);
204                         cpu_found = 1;
205                 }
206         }
207         /* if no detected cpu is off, use master core */
208         if (!cpu_found)
209                 CPU_SET(rte_get_master_lcore(), &cpuset);
210
211         ret = pthread_setaffinity_np(*thread, sizeof(cpuset), &cpuset);
212         if (ret < 0)
213                 goto fail;
214
215         ret = pthread_barrier_wait(&params->configured);
216         if (ret == PTHREAD_BARRIER_SERIAL_THREAD) {
217                 pthread_barrier_destroy(&params->configured);
218                 free(params);
219         }
220
221         return 0;
222
223 fail:
224         if (PTHREAD_BARRIER_SERIAL_THREAD ==
225             pthread_barrier_wait(&params->configured)) {
226                 pthread_barrier_destroy(&params->configured);
227                 free(params);
228         }
229         pthread_cancel(*thread);
230         pthread_join(*thread, NULL);
231         return -ret;
232 }