xref: /dpdk/lib/eal/unix/rte_thread.c (revision 7b61f14edbc2aeebfba3b2d359359a76fae641f4)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2021 Mellanox Technologies, Ltd
3  * Copyright (C) 2022 Microsoft Corporation
4  */
5 
6 #include <errno.h>
7 #include <pthread.h>
8 #include <stdlib.h>
9 #include <string.h>
10 
11 #include <rte_errno.h>
12 #include <rte_log.h>
13 #include <rte_thread.h>
14 
15 struct eal_tls_key {
16 	pthread_key_t thread_index;
17 };
18 
19 static int
20 thread_map_priority_to_os_value(enum rte_thread_priority eal_pri, int *os_pri,
21 	int *pol)
22 {
23 	/* Clear the output parameters. */
24 	*os_pri = sched_get_priority_min(SCHED_OTHER) - 1;
25 	*pol = -1;
26 
27 	switch (eal_pri) {
28 	case RTE_THREAD_PRIORITY_NORMAL:
29 		*pol = SCHED_OTHER;
30 
31 		/*
32 		 * Choose the middle of the range to represent the priority
33 		 * 'normal'.
34 		 * On Linux, this should be 0, since both
35 		 * sched_get_priority_min/_max return 0 for SCHED_OTHER.
36 		 */
37 		*os_pri = (sched_get_priority_min(SCHED_OTHER) +
38 			sched_get_priority_max(SCHED_OTHER)) / 2;
39 		break;
40 	case RTE_THREAD_PRIORITY_REALTIME_CRITICAL:
41 		*pol = SCHED_RR;
42 		*os_pri = sched_get_priority_max(SCHED_RR);
43 		break;
44 	default:
45 		RTE_LOG(DEBUG, EAL, "The requested priority value is invalid.\n");
46 		return EINVAL;
47 	}
48 
49 	return 0;
50 }
51 
52 static int
53 thread_map_os_priority_to_eal_priority(int policy, int os_pri,
54 	enum rte_thread_priority *eal_pri)
55 {
56 	switch (policy) {
57 	case SCHED_OTHER:
58 		if (os_pri == (sched_get_priority_min(SCHED_OTHER) +
59 				sched_get_priority_max(SCHED_OTHER)) / 2) {
60 			*eal_pri = RTE_THREAD_PRIORITY_NORMAL;
61 			return 0;
62 		}
63 		break;
64 	case SCHED_RR:
65 		if (os_pri == sched_get_priority_max(SCHED_RR)) {
66 			*eal_pri = RTE_THREAD_PRIORITY_REALTIME_CRITICAL;
67 			return 0;
68 		}
69 		break;
70 	default:
71 		RTE_LOG(DEBUG, EAL, "The OS priority value does not map to an EAL-defined priority.\n");
72 		return EINVAL;
73 	}
74 
75 	return 0;
76 }
77 
78 rte_thread_t
79 rte_thread_self(void)
80 {
81 	RTE_BUILD_BUG_ON(sizeof(pthread_t) > sizeof(uintptr_t));
82 
83 	rte_thread_t thread_id;
84 
85 	thread_id.opaque_id = (uintptr_t)pthread_self();
86 
87 	return thread_id;
88 }
89 
90 int
91 rte_thread_get_priority(rte_thread_t thread_id,
92 	enum rte_thread_priority *priority)
93 {
94 	struct sched_param param;
95 	int policy;
96 	int ret;
97 
98 	ret = pthread_getschedparam((pthread_t)thread_id.opaque_id, &policy,
99 		&param);
100 	if (ret != 0) {
101 		RTE_LOG(DEBUG, EAL, "pthread_getschedparam failed\n");
102 		goto cleanup;
103 	}
104 
105 	return thread_map_os_priority_to_eal_priority(policy,
106 		param.sched_priority, priority);
107 
108 cleanup:
109 	return ret;
110 }
111 
112 int
113 rte_thread_set_priority(rte_thread_t thread_id,
114 	enum rte_thread_priority priority)
115 {
116 	struct sched_param param;
117 	int policy;
118 	int ret;
119 
120 	/* Realtime priority can cause crashes on non-Windows platforms. */
121 	if (priority == RTE_THREAD_PRIORITY_REALTIME_CRITICAL)
122 		return ENOTSUP;
123 
124 	ret = thread_map_priority_to_os_value(priority, &param.sched_priority,
125 		&policy);
126 	if (ret != 0)
127 		return ret;
128 
129 	return pthread_setschedparam((pthread_t)thread_id.opaque_id, policy,
130 		&param);
131 }
132 
133 int
134 rte_thread_key_create(rte_thread_key *key, void (*destructor)(void *))
135 {
136 	int err;
137 
138 	*key = malloc(sizeof(**key));
139 	if ((*key) == NULL) {
140 		RTE_LOG(DEBUG, EAL, "Cannot allocate TLS key.\n");
141 		rte_errno = ENOMEM;
142 		return -1;
143 	}
144 	err = pthread_key_create(&((*key)->thread_index), destructor);
145 	if (err) {
146 		RTE_LOG(DEBUG, EAL, "pthread_key_create failed: %s\n",
147 			strerror(err));
148 		free(*key);
149 		rte_errno = ENOEXEC;
150 		return -1;
151 	}
152 	return 0;
153 }
154 
155 int
156 rte_thread_key_delete(rte_thread_key key)
157 {
158 	int err;
159 
160 	if (!key) {
161 		RTE_LOG(DEBUG, EAL, "Invalid TLS key.\n");
162 		rte_errno = EINVAL;
163 		return -1;
164 	}
165 	err = pthread_key_delete(key->thread_index);
166 	if (err) {
167 		RTE_LOG(DEBUG, EAL, "pthread_key_delete failed: %s\n",
168 			strerror(err));
169 		free(key);
170 		rte_errno = ENOEXEC;
171 		return -1;
172 	}
173 	free(key);
174 	return 0;
175 }
176 
177 int
178 rte_thread_value_set(rte_thread_key key, const void *value)
179 {
180 	int err;
181 
182 	if (!key) {
183 		RTE_LOG(DEBUG, EAL, "Invalid TLS key.\n");
184 		rte_errno = EINVAL;
185 		return -1;
186 	}
187 	err = pthread_setspecific(key->thread_index, value);
188 	if (err) {
189 		RTE_LOG(DEBUG, EAL, "pthread_setspecific failed: %s\n",
190 			strerror(err));
191 		rte_errno = ENOEXEC;
192 		return -1;
193 	}
194 	return 0;
195 }
196 
197 void *
198 rte_thread_value_get(rte_thread_key key)
199 {
200 	if (!key) {
201 		RTE_LOG(DEBUG, EAL, "Invalid TLS key.\n");
202 		rte_errno = EINVAL;
203 		return NULL;
204 	}
205 	return pthread_getspecific(key->thread_index);
206 }
207 
208 int
209 rte_thread_set_affinity_by_id(rte_thread_t thread_id,
210 		const rte_cpuset_t *cpuset)
211 {
212 	return pthread_setaffinity_np((pthread_t)thread_id.opaque_id,
213 		sizeof(*cpuset), cpuset);
214 }
215 
216 int
217 rte_thread_get_affinity_by_id(rte_thread_t thread_id,
218 		rte_cpuset_t *cpuset)
219 {
220 	return pthread_getaffinity_np((pthread_t)thread_id.opaque_id,
221 		sizeof(*cpuset), cpuset);
222 }
223