xref: /dpdk/lib/eal/windows/rte_thread.c (revision ae67895b507bb6af22263c79ba0d5c374b396485)
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