eal: make semantics of lcore role function more intuitive
[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                 .start_routine = start_routine,
168                 .arg = arg,
169         };
170         unsigned int lcore_id;
171         rte_cpuset_t cpuset;
172         int cpu_found, ret;
173
174         pthread_barrier_init(&params.configured, NULL, 2);
175
176         ret = pthread_create(thread, attr, rte_thread_init, (void *)&params);
177         if (ret != 0)
178                 return ret;
179
180         if (name != NULL) {
181                 ret = rte_thread_setname(*thread, name);
182                 if (ret < 0)
183                         goto fail;
184         }
185
186         cpu_found = 0;
187         CPU_ZERO(&cpuset);
188         for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
189                 if (eal_cpu_detected(lcore_id) &&
190                                 rte_lcore_has_role(lcore_id, ROLE_OFF)) {
191                         CPU_SET(lcore_id, &cpuset);
192                         cpu_found = 1;
193                 }
194         }
195         /* if no detected cpu is off, use master core */
196         if (!cpu_found)
197                 CPU_SET(rte_get_master_lcore(), &cpuset);
198
199         ret = pthread_setaffinity_np(*thread, sizeof(cpuset), &cpuset);
200         if (ret < 0)
201                 goto fail;
202
203         pthread_barrier_wait(&params.configured);
204
205         return 0;
206
207 fail:
208         pthread_cancel(*thread);
209         pthread_join(*thread, NULL);
210         return ret;
211 }