eal: promote some experimental functions as stable
[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 int eal_cpuset_socket_id(rte_cpuset_t *cpusetp)
42 {
43         unsigned cpu = 0;
44         int socket_id = SOCKET_ID_ANY;
45         int sid;
46
47         if (cpusetp == NULL)
48                 return SOCKET_ID_ANY;
49
50         do {
51                 if (!CPU_ISSET(cpu, cpusetp))
52                         continue;
53
54                 if (socket_id == SOCKET_ID_ANY)
55                         socket_id = eal_cpu_socket_id(cpu);
56
57                 sid = eal_cpu_socket_id(cpu);
58                 if (socket_id != sid) {
59                         socket_id = SOCKET_ID_ANY;
60                         break;
61                 }
62
63         } while (++cpu < RTE_MAX_LCORE);
64
65         return socket_id;
66 }
67
68 int
69 rte_thread_set_affinity(rte_cpuset_t *cpusetp)
70 {
71         int s;
72         unsigned lcore_id;
73         pthread_t tid;
74
75         tid = pthread_self();
76
77         s = pthread_setaffinity_np(tid, sizeof(rte_cpuset_t), cpusetp);
78         if (s != 0) {
79                 RTE_LOG(ERR, EAL, "pthread_setaffinity_np failed\n");
80                 return -1;
81         }
82
83         /* store socket_id in TLS for quick access */
84         RTE_PER_LCORE(_socket_id) =
85                 eal_cpuset_socket_id(cpusetp);
86
87         /* store cpuset in TLS for quick access */
88         memmove(&RTE_PER_LCORE(_cpuset), cpusetp,
89                 sizeof(rte_cpuset_t));
90
91         lcore_id = rte_lcore_id();
92         if (lcore_id != (unsigned)LCORE_ID_ANY) {
93                 /* EAL thread will update lcore_config */
94                 lcore_config[lcore_id].socket_id = RTE_PER_LCORE(_socket_id);
95                 memmove(&lcore_config[lcore_id].cpuset, cpusetp,
96                         sizeof(rte_cpuset_t));
97         }
98
99         return 0;
100 }
101
102 void
103 rte_thread_get_affinity(rte_cpuset_t *cpusetp)
104 {
105         assert(cpusetp);
106         memmove(cpusetp, &RTE_PER_LCORE(_cpuset),
107                 sizeof(rte_cpuset_t));
108 }
109
110 int
111 eal_thread_dump_affinity(char *str, unsigned size)
112 {
113         rte_cpuset_t cpuset;
114         unsigned cpu;
115         int ret;
116         unsigned int out = 0;
117
118         rte_thread_get_affinity(&cpuset);
119
120         for (cpu = 0; cpu < RTE_MAX_LCORE; cpu++) {
121                 if (!CPU_ISSET(cpu, &cpuset))
122                         continue;
123
124                 ret = snprintf(str + out,
125                                size - out, "%u,", cpu);
126                 if (ret < 0 || (unsigned)ret >= size - out) {
127                         /* string will be truncated */
128                         ret = -1;
129                         goto exit;
130                 }
131
132                 out += ret;
133         }
134
135         ret = 0;
136 exit:
137         /* remove the last separator */
138         if (out > 0)
139                 str[out - 1] = '\0';
140
141         return ret;
142 }
143
144
145 struct rte_thread_ctrl_params {
146         void *(*start_routine)(void *);
147         void *arg;
148         pthread_barrier_t configured;
149 };
150
151 static void *rte_thread_init(void *arg)
152 {
153         int ret;
154         struct rte_thread_ctrl_params *params = arg;
155         void *(*start_routine)(void *) = params->start_routine;
156         void *routine_arg = params->arg;
157
158         ret = pthread_barrier_wait(&params->configured);
159         if (ret == PTHREAD_BARRIER_SERIAL_THREAD) {
160                 pthread_barrier_destroy(&params->configured);
161                 free(params);
162         }
163
164         return start_routine(routine_arg);
165 }
166
167 int
168 rte_ctrl_thread_create(pthread_t *thread, const char *name,
169                 const pthread_attr_t *attr,
170                 void *(*start_routine)(void *), void *arg)
171 {
172         rte_cpuset_t *cpuset = &internal_config.ctrl_cpuset;
173         struct rte_thread_ctrl_params *params;
174         int 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         ret = pthread_setaffinity_np(*thread, sizeof(*cpuset), cpuset);
199         if (ret)
200                 goto fail;
201
202         ret = pthread_barrier_wait(&params->configured);
203         if (ret == PTHREAD_BARRIER_SERIAL_THREAD) {
204                 pthread_barrier_destroy(&params->configured);
205                 free(params);
206         }
207
208         return 0;
209
210 fail:
211         if (PTHREAD_BARRIER_SERIAL_THREAD ==
212             pthread_barrier_wait(&params->configured)) {
213                 pthread_barrier_destroy(&params->configured);
214                 free(params);
215         }
216         pthread_cancel(*thread);
217         pthread_join(*thread, NULL);
218         return -ret;
219 }