doc: remove reference to pcapng init function
[dpdk.git] / lib / eal / windows / rte_thread.c
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
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
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
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
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
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
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 *
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
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
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
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 }