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 }
233