1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2021 Mellanox Technologies, Ltd
3 * Copyright (C) 2022 Microsoft Corporation
4 */
5
6 #include <rte_common.h>
7 #include <rte_errno.h>
8 #include <rte_thread.h>
9
10 #include "eal_windows.h"
11
12 struct eal_tls_key {
13 DWORD thread_index;
14 };
15
16 /* Translates the most common error codes related to threads */
17 static int
thread_translate_win32_error(DWORD error)18 thread_translate_win32_error(DWORD error)
19 {
20 switch (error) {
21 case ERROR_SUCCESS:
22 return 0;
23
24 case ERROR_INVALID_PARAMETER:
25 return EINVAL;
26
27 case ERROR_INVALID_HANDLE:
28 return EFAULT;
29
30 case ERROR_NOT_ENOUGH_MEMORY:
31 /* FALLTHROUGH */
32 case ERROR_NO_SYSTEM_RESOURCES:
33 return ENOMEM;
34
35 case ERROR_PRIVILEGE_NOT_HELD:
36 /* FALLTHROUGH */
37 case ERROR_ACCESS_DENIED:
38 return EACCES;
39
40 case ERROR_ALREADY_EXISTS:
41 return EEXIST;
42
43 case ERROR_POSSIBLE_DEADLOCK:
44 return EDEADLK;
45
46 case ERROR_INVALID_FUNCTION:
47 /* FALLTHROUGH */
48 case ERROR_CALL_NOT_IMPLEMENTED:
49 return ENOSYS;
50 }
51
52 return EINVAL;
53 }
54
55 static int
thread_log_last_error(const char * message)56 thread_log_last_error(const char *message)
57 {
58 DWORD error = GetLastError();
59 RTE_LOG(DEBUG, EAL, "GetLastError()=%lu: %s\n", error, message);
60
61 return thread_translate_win32_error(error);
62 }
63
64 rte_thread_t
rte_thread_self(void)65 rte_thread_self(void)
66 {
67 rte_thread_t thread_id;
68
69 thread_id.opaque_id = GetCurrentThreadId();
70
71 return thread_id;
72 }
73
74 int
rte_thread_key_create(rte_thread_key * key,__rte_unused void (* destructor)(void *))75 rte_thread_key_create(rte_thread_key *key,
76 __rte_unused void (*destructor)(void *))
77 {
78 *key = malloc(sizeof(**key));
79 if ((*key) == NULL) {
80 RTE_LOG(DEBUG, EAL, "Cannot allocate TLS key.\n");
81 rte_errno = ENOMEM;
82 return -1;
83 }
84 (*key)->thread_index = TlsAlloc();
85 if ((*key)->thread_index == TLS_OUT_OF_INDEXES) {
86 RTE_LOG_WIN32_ERR("TlsAlloc()");
87 free(*key);
88 rte_errno = ENOEXEC;
89 return -1;
90 }
91 return 0;
92 }
93
94 int
rte_thread_key_delete(rte_thread_key key)95 rte_thread_key_delete(rte_thread_key key)
96 {
97 if (!key) {
98 RTE_LOG(DEBUG, EAL, "Invalid TLS key.\n");
99 rte_errno = EINVAL;
100 return -1;
101 }
102 if (!TlsFree(key->thread_index)) {
103 RTE_LOG_WIN32_ERR("TlsFree()");
104 free(key);
105 rte_errno = ENOEXEC;
106 return -1;
107 }
108 free(key);
109 return 0;
110 }
111
112 int
rte_thread_value_set(rte_thread_key key,const void * value)113 rte_thread_value_set(rte_thread_key key, const void *value)
114 {
115 char *p;
116
117 if (!key) {
118 RTE_LOG(DEBUG, EAL, "Invalid TLS key.\n");
119 rte_errno = EINVAL;
120 return -1;
121 }
122 /* discard const qualifier */
123 p = (char *) (uintptr_t) value;
124 if (!TlsSetValue(key->thread_index, p)) {
125 RTE_LOG_WIN32_ERR("TlsSetValue()");
126 rte_errno = ENOEXEC;
127 return -1;
128 }
129 return 0;
130 }
131
132 void *
rte_thread_value_get(rte_thread_key key)133 rte_thread_value_get(rte_thread_key key)
134 {
135 void *output;
136
137 if (!key) {
138 RTE_LOG(DEBUG, EAL, "Invalid TLS key.\n");
139 rte_errno = EINVAL;
140 return NULL;
141 }
142 output = TlsGetValue(key->thread_index);
143 if (GetLastError() != ERROR_SUCCESS) {
144 RTE_LOG_WIN32_ERR("TlsGetValue()");
145 rte_errno = ENOEXEC;
146 return NULL;
147 }
148 return output;
149 }
150
151 static int
convert_cpuset_to_affinity(const rte_cpuset_t * cpuset,PGROUP_AFFINITY affinity)152 convert_cpuset_to_affinity(const rte_cpuset_t *cpuset,
153 PGROUP_AFFINITY affinity)
154 {
155 int ret = 0;
156 PGROUP_AFFINITY cpu_affinity = NULL;
157 unsigned int cpu_idx;
158
159 memset(affinity, 0, sizeof(GROUP_AFFINITY));
160 affinity->Group = (USHORT)-1;
161
162 /* Check that all cpus of the set belong to the same processor group and
163 * accumulate thread affinity to be applied.
164 */
165 for (cpu_idx = 0; cpu_idx < CPU_SETSIZE; cpu_idx++) {
166 if (!CPU_ISSET(cpu_idx, cpuset))
167 continue;
168
169 cpu_affinity = eal_get_cpu_affinity(cpu_idx);
170
171 if (affinity->Group == (USHORT)-1) {
172 affinity->Group = cpu_affinity->Group;
173 } else if (affinity->Group != cpu_affinity->Group) {
174 RTE_LOG(DEBUG, EAL, "All processors must belong to the same processor group\n");
175 ret = ENOTSUP;
176 goto cleanup;
177 }
178
179 affinity->Mask |= cpu_affinity->Mask;
180 }
181
182 if (affinity->Mask == 0) {
183 ret = EINVAL;
184 goto cleanup;
185 }
186
187 cleanup:
188 return ret;
189 }
190
191 int
rte_thread_set_affinity_by_id(rte_thread_t thread_id,const rte_cpuset_t * cpuset)192 rte_thread_set_affinity_by_id(rte_thread_t thread_id,
193 const rte_cpuset_t *cpuset)
194 {
195 int ret = 0;
196 GROUP_AFFINITY thread_affinity;
197 HANDLE thread_handle = NULL;
198
199 if (cpuset == NULL) {
200 ret = EINVAL;
201 goto cleanup;
202 }
203
204 ret = convert_cpuset_to_affinity(cpuset, &thread_affinity);
205 if (ret != 0) {
206 RTE_LOG(DEBUG, EAL, "Unable to convert cpuset to thread affinity\n");
207 goto cleanup;
208 }
209
210 thread_handle = OpenThread(THREAD_ALL_ACCESS, FALSE,
211 thread_id.opaque_id);
212 if (thread_handle == NULL) {
213 ret = thread_log_last_error("OpenThread()");
214 goto cleanup;
215 }
216
217 if (!SetThreadGroupAffinity(thread_handle, &thread_affinity, NULL)) {
218 ret = thread_log_last_error("SetThreadGroupAffinity()");
219 goto cleanup;
220 }
221
222 cleanup:
223 if (thread_handle != NULL) {
224 CloseHandle(thread_handle);
225 thread_handle = NULL;
226 }
227
228 return ret;
229 }
230
231 int
rte_thread_get_affinity_by_id(rte_thread_t thread_id,rte_cpuset_t * cpuset)232 rte_thread_get_affinity_by_id(rte_thread_t thread_id,
233 rte_cpuset_t *cpuset)
234 {
235 HANDLE thread_handle = NULL;
236 PGROUP_AFFINITY cpu_affinity;
237 GROUP_AFFINITY thread_affinity;
238 unsigned int cpu_idx;
239 int ret = 0;
240
241 if (cpuset == NULL) {
242 ret = EINVAL;
243 goto cleanup;
244 }
245
246 thread_handle = OpenThread(THREAD_ALL_ACCESS, FALSE,
247 thread_id.opaque_id);
248 if (thread_handle == NULL) {
249 ret = thread_log_last_error("OpenThread()");
250 goto cleanup;
251 }
252
253 /* obtain previous thread affinity */
254 if (!GetThreadGroupAffinity(thread_handle, &thread_affinity)) {
255 ret = thread_log_last_error("GetThreadGroupAffinity()");
256 goto cleanup;
257 }
258
259 CPU_ZERO(cpuset);
260
261 /* Convert affinity to DPDK cpu set */
262 for (cpu_idx = 0; cpu_idx < CPU_SETSIZE; cpu_idx++) {
263
264 cpu_affinity = eal_get_cpu_affinity(cpu_idx);
265
266 if ((cpu_affinity->Group == thread_affinity.Group) &&
267 ((cpu_affinity->Mask & thread_affinity.Mask) != 0)) {
268 CPU_SET(cpu_idx, cpuset);
269 }
270 }
271
272 cleanup:
273 if (thread_handle != NULL) {
274 CloseHandle(thread_handle);
275 thread_handle = NULL;
276 }
277 return ret;
278 }
279