199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson * Copyright 2021 Mellanox Technologies, Ltd
3b70a9b78STyler Retzlaff * Copyright (C) 2022 Microsoft Corporation
499a2dd95SBruce Richardson */
599a2dd95SBruce Richardson
672b452c5SDmitry Kozlyuk #include <errno.h>
76d87be58STyler Retzlaff #include <wchar.h>
872b452c5SDmitry Kozlyuk
96d87be58STyler Retzlaff #include <rte_eal.h>
1099a2dd95SBruce Richardson #include <rte_common.h>
1199a2dd95SBruce Richardson #include <rte_errno.h>
122a7a42a5STyler Retzlaff #include <rte_stdatomic.h>
1399a2dd95SBruce Richardson #include <rte_thread.h>
14b70a9b78STyler Retzlaff
15*ae67895bSDavid Marchand #include "eal_private.h"
16b70a9b78STyler Retzlaff #include "eal_windows.h"
1799a2dd95SBruce Richardson
1899a2dd95SBruce Richardson struct eal_tls_key {
1999a2dd95SBruce Richardson DWORD thread_index;
2099a2dd95SBruce Richardson };
2199a2dd95SBruce Richardson
22ce6e911dSTyler Retzlaff struct thread_routine_ctx {
23ce6e911dSTyler Retzlaff rte_thread_func thread_func;
242a7a42a5STyler Retzlaff RTE_ATOMIC(bool) thread_init_failed;
25ce6e911dSTyler Retzlaff void *routine_args;
26ce6e911dSTyler Retzlaff };
27ce6e911dSTyler Retzlaff
28b70a9b78STyler Retzlaff /* Translates the most common error codes related to threads */
29b70a9b78STyler Retzlaff static int
thread_translate_win32_error(DWORD error)30b70a9b78STyler Retzlaff thread_translate_win32_error(DWORD error)
31b70a9b78STyler Retzlaff {
32b70a9b78STyler Retzlaff switch (error) {
33b70a9b78STyler Retzlaff case ERROR_SUCCESS:
34b70a9b78STyler Retzlaff return 0;
35b70a9b78STyler Retzlaff
36b70a9b78STyler Retzlaff case ERROR_INVALID_PARAMETER:
37b70a9b78STyler Retzlaff return EINVAL;
38b70a9b78STyler Retzlaff
39b70a9b78STyler Retzlaff case ERROR_INVALID_HANDLE:
40b70a9b78STyler Retzlaff return EFAULT;
41b70a9b78STyler Retzlaff
42b70a9b78STyler Retzlaff case ERROR_NOT_ENOUGH_MEMORY:
43b70a9b78STyler Retzlaff /* FALLTHROUGH */
44b70a9b78STyler Retzlaff case ERROR_NO_SYSTEM_RESOURCES:
45b70a9b78STyler Retzlaff return ENOMEM;
46b70a9b78STyler Retzlaff
47b70a9b78STyler Retzlaff case ERROR_PRIVILEGE_NOT_HELD:
48b70a9b78STyler Retzlaff /* FALLTHROUGH */
49b70a9b78STyler Retzlaff case ERROR_ACCESS_DENIED:
50b70a9b78STyler Retzlaff return EACCES;
51b70a9b78STyler Retzlaff
52b70a9b78STyler Retzlaff case ERROR_ALREADY_EXISTS:
53b70a9b78STyler Retzlaff return EEXIST;
54b70a9b78STyler Retzlaff
55b70a9b78STyler Retzlaff case ERROR_POSSIBLE_DEADLOCK:
56b70a9b78STyler Retzlaff return EDEADLK;
57b70a9b78STyler Retzlaff
58b70a9b78STyler Retzlaff case ERROR_INVALID_FUNCTION:
59b70a9b78STyler Retzlaff /* FALLTHROUGH */
60b70a9b78STyler Retzlaff case ERROR_CALL_NOT_IMPLEMENTED:
61b70a9b78STyler Retzlaff return ENOSYS;
62b70a9b78STyler Retzlaff }
63b70a9b78STyler Retzlaff
64b70a9b78STyler Retzlaff return EINVAL;
65b70a9b78STyler Retzlaff }
66b70a9b78STyler Retzlaff
67b70a9b78STyler Retzlaff static int
thread_log_last_error(const char * message)68b70a9b78STyler Retzlaff thread_log_last_error(const char *message)
69b70a9b78STyler Retzlaff {
70b70a9b78STyler Retzlaff DWORD error = GetLastError();
71*ae67895bSDavid Marchand EAL_LOG(DEBUG, "GetLastError()=%lu: %s", error, message);
72b70a9b78STyler Retzlaff
73b70a9b78STyler Retzlaff return thread_translate_win32_error(error);
74b70a9b78STyler Retzlaff }
75b70a9b78STyler Retzlaff
76ca04c78bSTyler Retzlaff static int
thread_map_priority_to_os_value(enum rte_thread_priority eal_pri,int * os_pri,DWORD * pri_class)77ca04c78bSTyler Retzlaff thread_map_priority_to_os_value(enum rte_thread_priority eal_pri, int *os_pri,
78ca04c78bSTyler Retzlaff DWORD *pri_class)
79ca04c78bSTyler Retzlaff {
80ca04c78bSTyler Retzlaff /* Clear the output parameters. */
81ca04c78bSTyler Retzlaff *os_pri = -1;
82ca04c78bSTyler Retzlaff *pri_class = -1;
83ca04c78bSTyler Retzlaff
84ca04c78bSTyler Retzlaff switch (eal_pri) {
85ca04c78bSTyler Retzlaff case RTE_THREAD_PRIORITY_NORMAL:
86ca04c78bSTyler Retzlaff *pri_class = NORMAL_PRIORITY_CLASS;
87ca04c78bSTyler Retzlaff *os_pri = THREAD_PRIORITY_NORMAL;
88ca04c78bSTyler Retzlaff break;
89ca04c78bSTyler Retzlaff case RTE_THREAD_PRIORITY_REALTIME_CRITICAL:
90ca04c78bSTyler Retzlaff *pri_class = REALTIME_PRIORITY_CLASS;
91ca04c78bSTyler Retzlaff *os_pri = THREAD_PRIORITY_TIME_CRITICAL;
92ca04c78bSTyler Retzlaff break;
93ca04c78bSTyler Retzlaff default:
94*ae67895bSDavid Marchand EAL_LOG(DEBUG, "The requested priority value is invalid.");
95ca04c78bSTyler Retzlaff return EINVAL;
96ca04c78bSTyler Retzlaff }
97ca04c78bSTyler Retzlaff
98ca04c78bSTyler Retzlaff return 0;
99ca04c78bSTyler Retzlaff }
100ca04c78bSTyler Retzlaff
101ca04c78bSTyler Retzlaff static int
thread_map_os_priority_to_eal_value(int os_pri,DWORD pri_class,enum rte_thread_priority * eal_pri)102ca04c78bSTyler Retzlaff thread_map_os_priority_to_eal_value(int os_pri, DWORD pri_class,
103ca04c78bSTyler Retzlaff enum rte_thread_priority *eal_pri)
104ca04c78bSTyler Retzlaff {
105ca04c78bSTyler Retzlaff switch (pri_class) {
106ca04c78bSTyler Retzlaff case NORMAL_PRIORITY_CLASS:
107ca04c78bSTyler Retzlaff if (os_pri == THREAD_PRIORITY_NORMAL) {
108ca04c78bSTyler Retzlaff *eal_pri = RTE_THREAD_PRIORITY_NORMAL;
109ca04c78bSTyler Retzlaff return 0;
110ca04c78bSTyler Retzlaff }
111ca04c78bSTyler Retzlaff break;
112ca04c78bSTyler Retzlaff case HIGH_PRIORITY_CLASS:
113*ae67895bSDavid Marchand EAL_LOG(WARNING, "The OS priority class is high not real-time.");
114ca04c78bSTyler Retzlaff /* FALLTHROUGH */
115ca04c78bSTyler Retzlaff case REALTIME_PRIORITY_CLASS:
116ca04c78bSTyler Retzlaff if (os_pri == THREAD_PRIORITY_TIME_CRITICAL) {
117ca04c78bSTyler Retzlaff *eal_pri = RTE_THREAD_PRIORITY_REALTIME_CRITICAL;
118ca04c78bSTyler Retzlaff return 0;
119ca04c78bSTyler Retzlaff }
120ca04c78bSTyler Retzlaff break;
121ca04c78bSTyler Retzlaff default:
122*ae67895bSDavid Marchand EAL_LOG(DEBUG, "The OS priority value does not map to an EAL-defined priority.");
123ca04c78bSTyler Retzlaff return EINVAL;
124ca04c78bSTyler Retzlaff }
125ca04c78bSTyler Retzlaff
126ca04c78bSTyler Retzlaff return 0;
127ca04c78bSTyler Retzlaff }
128ca04c78bSTyler Retzlaff
129ce6e911dSTyler Retzlaff static int
convert_cpuset_to_affinity(const rte_cpuset_t * cpuset,PGROUP_AFFINITY affinity)130ce6e911dSTyler Retzlaff convert_cpuset_to_affinity(const rte_cpuset_t *cpuset,
131ce6e911dSTyler Retzlaff PGROUP_AFFINITY affinity)
132ce6e911dSTyler Retzlaff {
133ce6e911dSTyler Retzlaff int ret = 0;
134ce6e911dSTyler Retzlaff PGROUP_AFFINITY cpu_affinity = NULL;
135ce6e911dSTyler Retzlaff unsigned int cpu_idx;
136ce6e911dSTyler Retzlaff
137ce6e911dSTyler Retzlaff memset(affinity, 0, sizeof(GROUP_AFFINITY));
138ce6e911dSTyler Retzlaff affinity->Group = (USHORT)-1;
139ce6e911dSTyler Retzlaff
140ce6e911dSTyler Retzlaff /* Check that all cpus of the set belong to the same processor group and
141ce6e911dSTyler Retzlaff * accumulate thread affinity to be applied.
142ce6e911dSTyler Retzlaff */
143ce6e911dSTyler Retzlaff for (cpu_idx = 0; cpu_idx < CPU_SETSIZE; cpu_idx++) {
144ce6e911dSTyler Retzlaff if (!CPU_ISSET(cpu_idx, cpuset))
145ce6e911dSTyler Retzlaff continue;
146ce6e911dSTyler Retzlaff
147ce6e911dSTyler Retzlaff cpu_affinity = eal_get_cpu_affinity(cpu_idx);
148ce6e911dSTyler Retzlaff
149ce6e911dSTyler Retzlaff if (affinity->Group == (USHORT)-1) {
150ce6e911dSTyler Retzlaff affinity->Group = cpu_affinity->Group;
151ce6e911dSTyler Retzlaff } else if (affinity->Group != cpu_affinity->Group) {
152*ae67895bSDavid Marchand EAL_LOG(DEBUG, "All processors must belong to the same processor group");
153ce6e911dSTyler Retzlaff ret = ENOTSUP;
154ce6e911dSTyler Retzlaff goto cleanup;
155ce6e911dSTyler Retzlaff }
156ce6e911dSTyler Retzlaff
157ce6e911dSTyler Retzlaff affinity->Mask |= cpu_affinity->Mask;
158ce6e911dSTyler Retzlaff }
159ce6e911dSTyler Retzlaff
160ce6e911dSTyler Retzlaff if (affinity->Mask == 0) {
161ce6e911dSTyler Retzlaff ret = EINVAL;
162ce6e911dSTyler Retzlaff goto cleanup;
163ce6e911dSTyler Retzlaff }
164ce6e911dSTyler Retzlaff
165ce6e911dSTyler Retzlaff cleanup:
166ce6e911dSTyler Retzlaff return ret;
167ce6e911dSTyler Retzlaff }
168ce6e911dSTyler Retzlaff
169ce6e911dSTyler Retzlaff static DWORD
thread_func_wrapper(void * arg)170ce6e911dSTyler Retzlaff thread_func_wrapper(void *arg)
171ce6e911dSTyler Retzlaff {
172ce6e911dSTyler Retzlaff struct thread_routine_ctx ctx = *(struct thread_routine_ctx *)arg;
1732a7a42a5STyler Retzlaff const bool thread_exit = rte_atomic_load_explicit(
1742a7a42a5STyler Retzlaff &ctx.thread_init_failed, rte_memory_order_acquire);
175ce6e911dSTyler Retzlaff
176ce6e911dSTyler Retzlaff free(arg);
177ce6e911dSTyler Retzlaff
1784ca43a88STyler Retzlaff if (thread_exit)
1794ca43a88STyler Retzlaff return 0;
1804ca43a88STyler Retzlaff
181ce6e911dSTyler Retzlaff return (DWORD)ctx.thread_func(ctx.routine_args);
182ce6e911dSTyler Retzlaff }
183ce6e911dSTyler Retzlaff
184ce6e911dSTyler Retzlaff int
rte_thread_create(rte_thread_t * thread_id,const rte_thread_attr_t * thread_attr,rte_thread_func thread_func,void * args)185ce6e911dSTyler Retzlaff rte_thread_create(rte_thread_t *thread_id,
186ce6e911dSTyler Retzlaff const rte_thread_attr_t *thread_attr,
187ce6e911dSTyler Retzlaff rte_thread_func thread_func, void *args)
188ce6e911dSTyler Retzlaff {
189ce6e911dSTyler Retzlaff int ret = 0;
190ce6e911dSTyler Retzlaff DWORD tid;
191ce6e911dSTyler Retzlaff HANDLE thread_handle = NULL;
192ce6e911dSTyler Retzlaff GROUP_AFFINITY thread_affinity;
193ce6e911dSTyler Retzlaff struct thread_routine_ctx *ctx;
1944ca43a88STyler Retzlaff bool thread_exit = false;
195ce6e911dSTyler Retzlaff
196ce6e911dSTyler Retzlaff ctx = calloc(1, sizeof(*ctx));
197ce6e911dSTyler Retzlaff if (ctx == NULL) {
198*ae67895bSDavid Marchand EAL_LOG(DEBUG, "Insufficient memory for thread context allocations");
199ce6e911dSTyler Retzlaff ret = ENOMEM;
200ce6e911dSTyler Retzlaff goto cleanup;
201ce6e911dSTyler Retzlaff }
202ce6e911dSTyler Retzlaff ctx->routine_args = args;
203ce6e911dSTyler Retzlaff ctx->thread_func = thread_func;
2044ca43a88STyler Retzlaff ctx->thread_init_failed = false;
205ce6e911dSTyler Retzlaff
206ce6e911dSTyler Retzlaff thread_handle = CreateThread(NULL, 0, thread_func_wrapper, ctx,
207ce6e911dSTyler Retzlaff CREATE_SUSPENDED, &tid);
208ce6e911dSTyler Retzlaff if (thread_handle == NULL) {
209ce6e911dSTyler Retzlaff ret = thread_log_last_error("CreateThread()");
210ce6e911dSTyler Retzlaff goto cleanup;
211ce6e911dSTyler Retzlaff }
212ce6e911dSTyler Retzlaff thread_id->opaque_id = tid;
213ce6e911dSTyler Retzlaff
214ce6e911dSTyler Retzlaff if (thread_attr != NULL) {
215ce6e911dSTyler Retzlaff if (CPU_COUNT(&thread_attr->cpuset) > 0) {
216ce6e911dSTyler Retzlaff ret = convert_cpuset_to_affinity(
217ce6e911dSTyler Retzlaff &thread_attr->cpuset,
218ce6e911dSTyler Retzlaff &thread_affinity
219ce6e911dSTyler Retzlaff );
220ce6e911dSTyler Retzlaff if (ret != 0) {
221*ae67895bSDavid Marchand EAL_LOG(DEBUG, "Unable to convert cpuset to thread affinity");
2224ca43a88STyler Retzlaff thread_exit = true;
2234ca43a88STyler Retzlaff goto resume_thread;
224ce6e911dSTyler Retzlaff }
225ce6e911dSTyler Retzlaff
226ce6e911dSTyler Retzlaff if (!SetThreadGroupAffinity(thread_handle,
227ce6e911dSTyler Retzlaff &thread_affinity, NULL)) {
228ce6e911dSTyler Retzlaff ret = thread_log_last_error("SetThreadGroupAffinity()");
2294ca43a88STyler Retzlaff thread_exit = true;
2304ca43a88STyler Retzlaff goto resume_thread;
231ce6e911dSTyler Retzlaff }
232ce6e911dSTyler Retzlaff }
233ce6e911dSTyler Retzlaff ret = rte_thread_set_priority(*thread_id,
234ce6e911dSTyler Retzlaff thread_attr->priority);
235ce6e911dSTyler Retzlaff if (ret != 0) {
236*ae67895bSDavid Marchand EAL_LOG(DEBUG, "Unable to set thread priority");
2374ca43a88STyler Retzlaff thread_exit = true;
2384ca43a88STyler Retzlaff goto resume_thread;
239ce6e911dSTyler Retzlaff }
240ce6e911dSTyler Retzlaff }
241ce6e911dSTyler Retzlaff
2424ca43a88STyler Retzlaff resume_thread:
2432a7a42a5STyler Retzlaff rte_atomic_store_explicit(&ctx->thread_init_failed, thread_exit, rte_memory_order_release);
2444ca43a88STyler Retzlaff
245ce6e911dSTyler Retzlaff if (ResumeThread(thread_handle) == (DWORD)-1) {
246ce6e911dSTyler Retzlaff ret = thread_log_last_error("ResumeThread()");
247ce6e911dSTyler Retzlaff goto cleanup;
248ce6e911dSTyler Retzlaff }
249ce6e911dSTyler Retzlaff
250ce6e911dSTyler Retzlaff ctx = NULL;
251ce6e911dSTyler Retzlaff cleanup:
252ce6e911dSTyler Retzlaff free(ctx);
253ce6e911dSTyler Retzlaff if (thread_handle != NULL) {
254ce6e911dSTyler Retzlaff CloseHandle(thread_handle);
255ce6e911dSTyler Retzlaff thread_handle = NULL;
256ce6e911dSTyler Retzlaff }
257ce6e911dSTyler Retzlaff
258ce6e911dSTyler Retzlaff return ret;
259ce6e911dSTyler Retzlaff }
260ce6e911dSTyler Retzlaff
261ce6e911dSTyler Retzlaff int
rte_thread_join(rte_thread_t thread_id,uint32_t * value_ptr)262ce6e911dSTyler Retzlaff rte_thread_join(rte_thread_t thread_id, uint32_t *value_ptr)
263ce6e911dSTyler Retzlaff {
264ce6e911dSTyler Retzlaff HANDLE thread_handle;
265ce6e911dSTyler Retzlaff DWORD result;
266ce6e911dSTyler Retzlaff DWORD exit_code = 0;
267ce6e911dSTyler Retzlaff BOOL err;
268ce6e911dSTyler Retzlaff int ret = 0;
269ce6e911dSTyler Retzlaff
270ce6e911dSTyler Retzlaff thread_handle = OpenThread(SYNCHRONIZE | THREAD_QUERY_INFORMATION,
271ce6e911dSTyler Retzlaff FALSE, thread_id.opaque_id);
272ce6e911dSTyler Retzlaff if (thread_handle == NULL) {
273ce6e911dSTyler Retzlaff ret = thread_log_last_error("OpenThread()");
274ce6e911dSTyler Retzlaff goto cleanup;
275ce6e911dSTyler Retzlaff }
276ce6e911dSTyler Retzlaff
277ce6e911dSTyler Retzlaff result = WaitForSingleObject(thread_handle, INFINITE);
278ce6e911dSTyler Retzlaff if (result != WAIT_OBJECT_0) {
279ce6e911dSTyler Retzlaff ret = thread_log_last_error("WaitForSingleObject()");
280ce6e911dSTyler Retzlaff goto cleanup;
281ce6e911dSTyler Retzlaff }
282ce6e911dSTyler Retzlaff
283ce6e911dSTyler Retzlaff if (value_ptr != NULL) {
284ce6e911dSTyler Retzlaff err = GetExitCodeThread(thread_handle, &exit_code);
285ce6e911dSTyler Retzlaff if (err == 0) {
286ce6e911dSTyler Retzlaff ret = thread_log_last_error("GetExitCodeThread()");
287ce6e911dSTyler Retzlaff goto cleanup;
288ce6e911dSTyler Retzlaff }
289ce6e911dSTyler Retzlaff *value_ptr = exit_code;
290ce6e911dSTyler Retzlaff }
291ce6e911dSTyler Retzlaff
292ce6e911dSTyler Retzlaff cleanup:
293ce6e911dSTyler Retzlaff if (thread_handle != NULL) {
294ce6e911dSTyler Retzlaff CloseHandle(thread_handle);
295ce6e911dSTyler Retzlaff thread_handle = NULL;
296ce6e911dSTyler Retzlaff }
297ce6e911dSTyler Retzlaff
298ce6e911dSTyler Retzlaff return ret;
299ce6e911dSTyler Retzlaff }
300ce6e911dSTyler Retzlaff
301ce6e911dSTyler Retzlaff int
rte_thread_detach(rte_thread_t thread_id)302ce6e911dSTyler Retzlaff rte_thread_detach(rte_thread_t thread_id)
303ce6e911dSTyler Retzlaff {
304ce6e911dSTyler Retzlaff /* No resources that need to be released. */
305ce6e911dSTyler Retzlaff RTE_SET_USED(thread_id);
306ce6e911dSTyler Retzlaff
307ce6e911dSTyler Retzlaff return 0;
308ce6e911dSTyler Retzlaff }
309ce6e911dSTyler Retzlaff
310a2e94ca8STyler Retzlaff int
rte_thread_equal(rte_thread_t t1,rte_thread_t t2)311a2e94ca8STyler Retzlaff rte_thread_equal(rte_thread_t t1, rte_thread_t t2)
312a2e94ca8STyler Retzlaff {
313a2e94ca8STyler Retzlaff return t1.opaque_id == t2.opaque_id;
314a2e94ca8STyler Retzlaff }
315a2e94ca8STyler Retzlaff
31656539289STyler Retzlaff rte_thread_t
rte_thread_self(void)31756539289STyler Retzlaff rte_thread_self(void)
31856539289STyler Retzlaff {
31956539289STyler Retzlaff rte_thread_t thread_id;
32056539289STyler Retzlaff
32156539289STyler Retzlaff thread_id.opaque_id = GetCurrentThreadId();
32256539289STyler Retzlaff
32356539289STyler Retzlaff return thread_id;
32456539289STyler Retzlaff }
32556539289STyler Retzlaff
3266d87be58STyler Retzlaff void
rte_thread_set_name(rte_thread_t thread_id,const char * thread_name)3276d87be58STyler Retzlaff rte_thread_set_name(rte_thread_t thread_id, const char *thread_name)
3286d87be58STyler Retzlaff {
3296d87be58STyler Retzlaff int ret = 0;
33093d8a7edSThomas Monjalon wchar_t wname[RTE_THREAD_NAME_SIZE];
3316d87be58STyler Retzlaff mbstate_t state = {0};
3326d87be58STyler Retzlaff size_t rv;
3336d87be58STyler Retzlaff HANDLE thread_handle;
3346d87be58STyler Retzlaff
3356d87be58STyler Retzlaff thread_handle = OpenThread(THREAD_ALL_ACCESS, FALSE,
3366d87be58STyler Retzlaff thread_id.opaque_id);
3376d87be58STyler Retzlaff if (thread_handle == NULL) {
3386d87be58STyler Retzlaff ret = thread_log_last_error("OpenThread()");
3396d87be58STyler Retzlaff goto cleanup;
3406d87be58STyler Retzlaff }
3416d87be58STyler Retzlaff
3426d87be58STyler Retzlaff memset(wname, 0, sizeof(wname));
3436d87be58STyler Retzlaff rv = mbsrtowcs(wname, &thread_name, RTE_DIM(wname) - 1, &state);
3446d87be58STyler Retzlaff if (rv == (size_t)-1) {
3456d87be58STyler Retzlaff ret = EILSEQ;
3466d87be58STyler Retzlaff goto cleanup;
3476d87be58STyler Retzlaff }
3486d87be58STyler Retzlaff
3496d87be58STyler Retzlaff #ifndef RTE_TOOLCHAIN_GCC
3506d87be58STyler Retzlaff if (FAILED(SetThreadDescription(thread_handle, wname))) {
3516d87be58STyler Retzlaff ret = EINVAL;
3526d87be58STyler Retzlaff goto cleanup;
3536d87be58STyler Retzlaff }
3546d87be58STyler Retzlaff #else
3556d87be58STyler Retzlaff ret = ENOTSUP;
3566d87be58STyler Retzlaff goto cleanup;
3576d87be58STyler Retzlaff #endif
3586d87be58STyler Retzlaff
3596d87be58STyler Retzlaff cleanup:
3606d87be58STyler Retzlaff if (thread_handle != NULL)
3616d87be58STyler Retzlaff CloseHandle(thread_handle);
3626d87be58STyler Retzlaff
3636d87be58STyler Retzlaff if (ret != 0)
364*ae67895bSDavid Marchand EAL_LOG(DEBUG, "Failed to set thread name");
3656d87be58STyler Retzlaff }
3666d87be58STyler Retzlaff
36799a2dd95SBruce Richardson int
rte_thread_get_priority(rte_thread_t thread_id,enum rte_thread_priority * priority)368ca04c78bSTyler Retzlaff rte_thread_get_priority(rte_thread_t thread_id,
369ca04c78bSTyler Retzlaff enum rte_thread_priority *priority)
370ca04c78bSTyler Retzlaff {
371ca04c78bSTyler Retzlaff HANDLE thread_handle = NULL;
372ca04c78bSTyler Retzlaff DWORD pri_class;
373ca04c78bSTyler Retzlaff int os_pri;
374ca04c78bSTyler Retzlaff int ret;
375ca04c78bSTyler Retzlaff
376ca04c78bSTyler Retzlaff pri_class = GetPriorityClass(GetCurrentProcess());
377ca04c78bSTyler Retzlaff if (pri_class == 0) {
378ca04c78bSTyler Retzlaff ret = thread_log_last_error("GetPriorityClass()");
379ca04c78bSTyler Retzlaff goto cleanup;
380ca04c78bSTyler Retzlaff }
381ca04c78bSTyler Retzlaff
382ca04c78bSTyler Retzlaff thread_handle = OpenThread(THREAD_SET_INFORMATION |
383ca04c78bSTyler Retzlaff THREAD_QUERY_INFORMATION, FALSE, thread_id.opaque_id);
384ca04c78bSTyler Retzlaff if (thread_handle == NULL) {
385ca04c78bSTyler Retzlaff ret = thread_log_last_error("OpenThread()");
386ca04c78bSTyler Retzlaff goto cleanup;
387ca04c78bSTyler Retzlaff }
388ca04c78bSTyler Retzlaff
389ca04c78bSTyler Retzlaff os_pri = GetThreadPriority(thread_handle);
390ca04c78bSTyler Retzlaff if (os_pri == THREAD_PRIORITY_ERROR_RETURN) {
391ca04c78bSTyler Retzlaff ret = thread_log_last_error("GetThreadPriority()");
392ca04c78bSTyler Retzlaff goto cleanup;
393ca04c78bSTyler Retzlaff }
394ca04c78bSTyler Retzlaff
395ca04c78bSTyler Retzlaff ret = thread_map_os_priority_to_eal_value(os_pri, pri_class, priority);
396ca04c78bSTyler Retzlaff if (ret != 0)
397ca04c78bSTyler Retzlaff goto cleanup;
398ca04c78bSTyler Retzlaff
399ca04c78bSTyler Retzlaff cleanup:
400ca04c78bSTyler Retzlaff if (thread_handle != NULL)
401ca04c78bSTyler Retzlaff CloseHandle(thread_handle);
402ca04c78bSTyler Retzlaff
403ca04c78bSTyler Retzlaff return ret;
404ca04c78bSTyler Retzlaff }
405ca04c78bSTyler Retzlaff
406ca04c78bSTyler Retzlaff int
rte_thread_set_priority(rte_thread_t thread_id,enum rte_thread_priority priority)407ca04c78bSTyler Retzlaff rte_thread_set_priority(rte_thread_t thread_id,
408ca04c78bSTyler Retzlaff enum rte_thread_priority priority)
409ca04c78bSTyler Retzlaff {
410ca04c78bSTyler Retzlaff HANDLE thread_handle;
411ca04c78bSTyler Retzlaff DWORD priority_class;
412ca04c78bSTyler Retzlaff int os_priority;
413ca04c78bSTyler Retzlaff int ret = 0;
414ca04c78bSTyler Retzlaff
415ca04c78bSTyler Retzlaff thread_handle = OpenThread(THREAD_SET_INFORMATION |
416ca04c78bSTyler Retzlaff THREAD_QUERY_INFORMATION, FALSE, thread_id.opaque_id);
417ca04c78bSTyler Retzlaff if (thread_handle == NULL) {
418ca04c78bSTyler Retzlaff ret = thread_log_last_error("OpenThread()");
419ca04c78bSTyler Retzlaff goto cleanup;
420ca04c78bSTyler Retzlaff }
421ca04c78bSTyler Retzlaff
422ca04c78bSTyler Retzlaff ret = thread_map_priority_to_os_value(priority, &os_priority,
423ca04c78bSTyler Retzlaff &priority_class);
424ca04c78bSTyler Retzlaff if (ret != 0)
425ca04c78bSTyler Retzlaff goto cleanup;
426ca04c78bSTyler Retzlaff
427ca04c78bSTyler Retzlaff if (!SetPriorityClass(GetCurrentProcess(), priority_class)) {
428ca04c78bSTyler Retzlaff ret = thread_log_last_error("SetPriorityClass()");
429ca04c78bSTyler Retzlaff goto cleanup;
430ca04c78bSTyler Retzlaff }
431ca04c78bSTyler Retzlaff
432ca04c78bSTyler Retzlaff if (!SetThreadPriority(thread_handle, os_priority)) {
433ca04c78bSTyler Retzlaff ret = thread_log_last_error("SetThreadPriority()");
434ca04c78bSTyler Retzlaff goto cleanup;
435ca04c78bSTyler Retzlaff }
436ca04c78bSTyler Retzlaff
437ca04c78bSTyler Retzlaff cleanup:
438ca04c78bSTyler Retzlaff if (thread_handle != NULL)
439ca04c78bSTyler Retzlaff CloseHandle(thread_handle);
440ca04c78bSTyler Retzlaff
441ca04c78bSTyler Retzlaff return ret;
442ca04c78bSTyler Retzlaff }
443ca04c78bSTyler Retzlaff
444ca04c78bSTyler Retzlaff int
rte_thread_key_create(rte_thread_key * key,__rte_unused void (* destructor)(void *))44599a2dd95SBruce Richardson rte_thread_key_create(rte_thread_key *key,
44699a2dd95SBruce Richardson __rte_unused void (*destructor)(void *))
44799a2dd95SBruce Richardson {
44899a2dd95SBruce Richardson *key = malloc(sizeof(**key));
44999a2dd95SBruce Richardson if ((*key) == NULL) {
450*ae67895bSDavid Marchand EAL_LOG(DEBUG, "Cannot allocate TLS key.");
45199a2dd95SBruce Richardson rte_errno = ENOMEM;
45299a2dd95SBruce Richardson return -1;
45399a2dd95SBruce Richardson }
45499a2dd95SBruce Richardson (*key)->thread_index = TlsAlloc();
45599a2dd95SBruce Richardson if ((*key)->thread_index == TLS_OUT_OF_INDEXES) {
45699a2dd95SBruce Richardson RTE_LOG_WIN32_ERR("TlsAlloc()");
45799a2dd95SBruce Richardson free(*key);
45899a2dd95SBruce Richardson rte_errno = ENOEXEC;
45999a2dd95SBruce Richardson return -1;
46099a2dd95SBruce Richardson }
46199a2dd95SBruce Richardson return 0;
46299a2dd95SBruce Richardson }
46399a2dd95SBruce Richardson
46499a2dd95SBruce Richardson int
rte_thread_key_delete(rte_thread_key key)46599a2dd95SBruce Richardson rte_thread_key_delete(rte_thread_key key)
46699a2dd95SBruce Richardson {
46799a2dd95SBruce Richardson if (!key) {
468*ae67895bSDavid Marchand EAL_LOG(DEBUG, "Invalid TLS key.");
46999a2dd95SBruce Richardson rte_errno = EINVAL;
47099a2dd95SBruce Richardson return -1;
47199a2dd95SBruce Richardson }
47299a2dd95SBruce Richardson if (!TlsFree(key->thread_index)) {
47399a2dd95SBruce Richardson RTE_LOG_WIN32_ERR("TlsFree()");
47499a2dd95SBruce Richardson free(key);
47599a2dd95SBruce Richardson rte_errno = ENOEXEC;
47699a2dd95SBruce Richardson return -1;
47799a2dd95SBruce Richardson }
47899a2dd95SBruce Richardson free(key);
47999a2dd95SBruce Richardson return 0;
48099a2dd95SBruce Richardson }
48199a2dd95SBruce Richardson
48299a2dd95SBruce Richardson int
rte_thread_value_set(rte_thread_key key,const void * value)48399a2dd95SBruce Richardson rte_thread_value_set(rte_thread_key key, const void *value)
48499a2dd95SBruce Richardson {
48599a2dd95SBruce Richardson char *p;
48699a2dd95SBruce Richardson
48799a2dd95SBruce Richardson if (!key) {
488*ae67895bSDavid Marchand EAL_LOG(DEBUG, "Invalid TLS key.");
48999a2dd95SBruce Richardson rte_errno = EINVAL;
49099a2dd95SBruce Richardson return -1;
49199a2dd95SBruce Richardson }
49299a2dd95SBruce Richardson /* discard const qualifier */
49399a2dd95SBruce Richardson p = (char *) (uintptr_t) value;
49499a2dd95SBruce Richardson if (!TlsSetValue(key->thread_index, p)) {
49599a2dd95SBruce Richardson RTE_LOG_WIN32_ERR("TlsSetValue()");
49699a2dd95SBruce Richardson rte_errno = ENOEXEC;
49799a2dd95SBruce Richardson return -1;
49899a2dd95SBruce Richardson }
49999a2dd95SBruce Richardson return 0;
50099a2dd95SBruce Richardson }
50199a2dd95SBruce Richardson
50299a2dd95SBruce Richardson void *
rte_thread_value_get(rte_thread_key key)50399a2dd95SBruce Richardson rte_thread_value_get(rte_thread_key key)
50499a2dd95SBruce Richardson {
50599a2dd95SBruce Richardson void *output;
50699a2dd95SBruce Richardson
50799a2dd95SBruce Richardson if (!key) {
508*ae67895bSDavid Marchand EAL_LOG(DEBUG, "Invalid TLS key.");
50999a2dd95SBruce Richardson rte_errno = EINVAL;
51099a2dd95SBruce Richardson return NULL;
51199a2dd95SBruce Richardson }
51299a2dd95SBruce Richardson output = TlsGetValue(key->thread_index);
51399a2dd95SBruce Richardson if (GetLastError() != ERROR_SUCCESS) {
51499a2dd95SBruce Richardson RTE_LOG_WIN32_ERR("TlsGetValue()");
51599a2dd95SBruce Richardson rte_errno = ENOEXEC;
51699a2dd95SBruce Richardson return NULL;
51799a2dd95SBruce Richardson }
51899a2dd95SBruce Richardson return output;
51999a2dd95SBruce Richardson }
520b70a9b78STyler Retzlaff
521b70a9b78STyler Retzlaff int
rte_thread_set_affinity_by_id(rte_thread_t thread_id,const rte_cpuset_t * cpuset)522b70a9b78STyler Retzlaff rte_thread_set_affinity_by_id(rte_thread_t thread_id,
523b70a9b78STyler Retzlaff const rte_cpuset_t *cpuset)
524b70a9b78STyler Retzlaff {
525b70a9b78STyler Retzlaff int ret = 0;
526b70a9b78STyler Retzlaff GROUP_AFFINITY thread_affinity;
527b70a9b78STyler Retzlaff HANDLE thread_handle = NULL;
528b70a9b78STyler Retzlaff
529b70a9b78STyler Retzlaff if (cpuset == NULL) {
530b70a9b78STyler Retzlaff ret = EINVAL;
531b70a9b78STyler Retzlaff goto cleanup;
532b70a9b78STyler Retzlaff }
533b70a9b78STyler Retzlaff
534b70a9b78STyler Retzlaff ret = convert_cpuset_to_affinity(cpuset, &thread_affinity);
535b70a9b78STyler Retzlaff if (ret != 0) {
536*ae67895bSDavid Marchand EAL_LOG(DEBUG, "Unable to convert cpuset to thread affinity");
537b70a9b78STyler Retzlaff goto cleanup;
538b70a9b78STyler Retzlaff }
539b70a9b78STyler Retzlaff
540b70a9b78STyler Retzlaff thread_handle = OpenThread(THREAD_ALL_ACCESS, FALSE,
541b70a9b78STyler Retzlaff thread_id.opaque_id);
542b70a9b78STyler Retzlaff if (thread_handle == NULL) {
543b70a9b78STyler Retzlaff ret = thread_log_last_error("OpenThread()");
544b70a9b78STyler Retzlaff goto cleanup;
545b70a9b78STyler Retzlaff }
546b70a9b78STyler Retzlaff
547b70a9b78STyler Retzlaff if (!SetThreadGroupAffinity(thread_handle, &thread_affinity, NULL)) {
548b70a9b78STyler Retzlaff ret = thread_log_last_error("SetThreadGroupAffinity()");
549b70a9b78STyler Retzlaff goto cleanup;
550b70a9b78STyler Retzlaff }
551b70a9b78STyler Retzlaff
552b70a9b78STyler Retzlaff cleanup:
553b70a9b78STyler Retzlaff if (thread_handle != NULL) {
554b70a9b78STyler Retzlaff CloseHandle(thread_handle);
555b70a9b78STyler Retzlaff thread_handle = NULL;
556b70a9b78STyler Retzlaff }
557b70a9b78STyler Retzlaff
558b70a9b78STyler Retzlaff return ret;
559b70a9b78STyler Retzlaff }
560b70a9b78STyler Retzlaff
561b70a9b78STyler Retzlaff int
rte_thread_get_affinity_by_id(rte_thread_t thread_id,rte_cpuset_t * cpuset)562b70a9b78STyler Retzlaff rte_thread_get_affinity_by_id(rte_thread_t thread_id,
563b70a9b78STyler Retzlaff rte_cpuset_t *cpuset)
564b70a9b78STyler Retzlaff {
565b70a9b78STyler Retzlaff HANDLE thread_handle = NULL;
566b70a9b78STyler Retzlaff PGROUP_AFFINITY cpu_affinity;
567b70a9b78STyler Retzlaff GROUP_AFFINITY thread_affinity;
568b70a9b78STyler Retzlaff unsigned int cpu_idx;
569b70a9b78STyler Retzlaff int ret = 0;
570b70a9b78STyler Retzlaff
571b70a9b78STyler Retzlaff if (cpuset == NULL) {
572b70a9b78STyler Retzlaff ret = EINVAL;
573b70a9b78STyler Retzlaff goto cleanup;
574b70a9b78STyler Retzlaff }
575b70a9b78STyler Retzlaff
576b70a9b78STyler Retzlaff thread_handle = OpenThread(THREAD_ALL_ACCESS, FALSE,
577b70a9b78STyler Retzlaff thread_id.opaque_id);
578b70a9b78STyler Retzlaff if (thread_handle == NULL) {
579b70a9b78STyler Retzlaff ret = thread_log_last_error("OpenThread()");
580b70a9b78STyler Retzlaff goto cleanup;
581b70a9b78STyler Retzlaff }
582b70a9b78STyler Retzlaff
583b70a9b78STyler Retzlaff /* obtain previous thread affinity */
584b70a9b78STyler Retzlaff if (!GetThreadGroupAffinity(thread_handle, &thread_affinity)) {
585b70a9b78STyler Retzlaff ret = thread_log_last_error("GetThreadGroupAffinity()");
586b70a9b78STyler Retzlaff goto cleanup;
587b70a9b78STyler Retzlaff }
588b70a9b78STyler Retzlaff
589b70a9b78STyler Retzlaff CPU_ZERO(cpuset);
590b70a9b78STyler Retzlaff
591b70a9b78STyler Retzlaff /* Convert affinity to DPDK cpu set */
592b70a9b78STyler Retzlaff for (cpu_idx = 0; cpu_idx < CPU_SETSIZE; cpu_idx++) {
593b70a9b78STyler Retzlaff
594b70a9b78STyler Retzlaff cpu_affinity = eal_get_cpu_affinity(cpu_idx);
595b70a9b78STyler Retzlaff
596b70a9b78STyler Retzlaff if ((cpu_affinity->Group == thread_affinity.Group) &&
597b70a9b78STyler Retzlaff ((cpu_affinity->Mask & thread_affinity.Mask) != 0)) {
598b70a9b78STyler Retzlaff CPU_SET(cpu_idx, cpuset);
599b70a9b78STyler Retzlaff }
600b70a9b78STyler Retzlaff }
601b70a9b78STyler Retzlaff
602b70a9b78STyler Retzlaff cleanup:
603b70a9b78STyler Retzlaff if (thread_handle != NULL) {
604b70a9b78STyler Retzlaff CloseHandle(thread_handle);
605b70a9b78STyler Retzlaff thread_handle = NULL;
606b70a9b78STyler Retzlaff }
607b70a9b78STyler Retzlaff return ret;
608b70a9b78STyler Retzlaff }
609