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