xref: /dpdk/lib/eal/windows/rte_thread.c (revision a2e94ca89f8f37c0d3f368a97cad3da07e78c979)
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>
772b452c5SDmitry Kozlyuk 
899a2dd95SBruce Richardson #include <rte_common.h>
999a2dd95SBruce Richardson #include <rte_errno.h>
1099a2dd95SBruce Richardson #include <rte_thread.h>
11b70a9b78STyler Retzlaff 
12b70a9b78STyler Retzlaff #include "eal_windows.h"
1399a2dd95SBruce Richardson 
1499a2dd95SBruce Richardson struct eal_tls_key {
1599a2dd95SBruce Richardson 	DWORD thread_index;
1699a2dd95SBruce Richardson };
1799a2dd95SBruce Richardson 
18ce6e911dSTyler Retzlaff struct thread_routine_ctx {
19ce6e911dSTyler Retzlaff 	rte_thread_func thread_func;
20ce6e911dSTyler Retzlaff 	void *routine_args;
21ce6e911dSTyler Retzlaff };
22ce6e911dSTyler Retzlaff 
23b70a9b78STyler Retzlaff /* Translates the most common error codes related to threads */
24b70a9b78STyler Retzlaff static int
25b70a9b78STyler Retzlaff thread_translate_win32_error(DWORD error)
26b70a9b78STyler Retzlaff {
27b70a9b78STyler Retzlaff 	switch (error) {
28b70a9b78STyler Retzlaff 	case ERROR_SUCCESS:
29b70a9b78STyler Retzlaff 		return 0;
30b70a9b78STyler Retzlaff 
31b70a9b78STyler Retzlaff 	case ERROR_INVALID_PARAMETER:
32b70a9b78STyler Retzlaff 		return EINVAL;
33b70a9b78STyler Retzlaff 
34b70a9b78STyler Retzlaff 	case ERROR_INVALID_HANDLE:
35b70a9b78STyler Retzlaff 		return EFAULT;
36b70a9b78STyler Retzlaff 
37b70a9b78STyler Retzlaff 	case ERROR_NOT_ENOUGH_MEMORY:
38b70a9b78STyler Retzlaff 		/* FALLTHROUGH */
39b70a9b78STyler Retzlaff 	case ERROR_NO_SYSTEM_RESOURCES:
40b70a9b78STyler Retzlaff 		return ENOMEM;
41b70a9b78STyler Retzlaff 
42b70a9b78STyler Retzlaff 	case ERROR_PRIVILEGE_NOT_HELD:
43b70a9b78STyler Retzlaff 		/* FALLTHROUGH */
44b70a9b78STyler Retzlaff 	case ERROR_ACCESS_DENIED:
45b70a9b78STyler Retzlaff 		return EACCES;
46b70a9b78STyler Retzlaff 
47b70a9b78STyler Retzlaff 	case ERROR_ALREADY_EXISTS:
48b70a9b78STyler Retzlaff 		return EEXIST;
49b70a9b78STyler Retzlaff 
50b70a9b78STyler Retzlaff 	case ERROR_POSSIBLE_DEADLOCK:
51b70a9b78STyler Retzlaff 		return EDEADLK;
52b70a9b78STyler Retzlaff 
53b70a9b78STyler Retzlaff 	case ERROR_INVALID_FUNCTION:
54b70a9b78STyler Retzlaff 		/* FALLTHROUGH */
55b70a9b78STyler Retzlaff 	case ERROR_CALL_NOT_IMPLEMENTED:
56b70a9b78STyler Retzlaff 		return ENOSYS;
57b70a9b78STyler Retzlaff 	}
58b70a9b78STyler Retzlaff 
59b70a9b78STyler Retzlaff 	return EINVAL;
60b70a9b78STyler Retzlaff }
61b70a9b78STyler Retzlaff 
62b70a9b78STyler Retzlaff static int
63b70a9b78STyler Retzlaff thread_log_last_error(const char *message)
64b70a9b78STyler Retzlaff {
65b70a9b78STyler Retzlaff 	DWORD error = GetLastError();
66b70a9b78STyler Retzlaff 	RTE_LOG(DEBUG, EAL, "GetLastError()=%lu: %s\n", error, message);
67b70a9b78STyler Retzlaff 
68b70a9b78STyler Retzlaff 	return thread_translate_win32_error(error);
69b70a9b78STyler Retzlaff }
70b70a9b78STyler Retzlaff 
71ca04c78bSTyler Retzlaff static int
72ca04c78bSTyler Retzlaff thread_map_priority_to_os_value(enum rte_thread_priority eal_pri, int *os_pri,
73ca04c78bSTyler Retzlaff 	DWORD *pri_class)
74ca04c78bSTyler Retzlaff {
75ca04c78bSTyler Retzlaff 	/* Clear the output parameters. */
76ca04c78bSTyler Retzlaff 	*os_pri = -1;
77ca04c78bSTyler Retzlaff 	*pri_class = -1;
78ca04c78bSTyler Retzlaff 
79ca04c78bSTyler Retzlaff 	switch (eal_pri) {
80ca04c78bSTyler Retzlaff 	case RTE_THREAD_PRIORITY_NORMAL:
81ca04c78bSTyler Retzlaff 		*pri_class = NORMAL_PRIORITY_CLASS;
82ca04c78bSTyler Retzlaff 		*os_pri = THREAD_PRIORITY_NORMAL;
83ca04c78bSTyler Retzlaff 		break;
84ca04c78bSTyler Retzlaff 	case RTE_THREAD_PRIORITY_REALTIME_CRITICAL:
85ca04c78bSTyler Retzlaff 		*pri_class = REALTIME_PRIORITY_CLASS;
86ca04c78bSTyler Retzlaff 		*os_pri = THREAD_PRIORITY_TIME_CRITICAL;
87ca04c78bSTyler Retzlaff 		break;
88ca04c78bSTyler Retzlaff 	default:
89ca04c78bSTyler Retzlaff 		RTE_LOG(DEBUG, EAL, "The requested priority value is invalid.\n");
90ca04c78bSTyler Retzlaff 		return EINVAL;
91ca04c78bSTyler Retzlaff 	}
92ca04c78bSTyler Retzlaff 
93ca04c78bSTyler Retzlaff 	return 0;
94ca04c78bSTyler Retzlaff }
95ca04c78bSTyler Retzlaff 
96ca04c78bSTyler Retzlaff static int
97ca04c78bSTyler Retzlaff thread_map_os_priority_to_eal_value(int os_pri, DWORD pri_class,
98ca04c78bSTyler Retzlaff 	enum rte_thread_priority *eal_pri)
99ca04c78bSTyler Retzlaff {
100ca04c78bSTyler Retzlaff 	switch (pri_class) {
101ca04c78bSTyler Retzlaff 	case NORMAL_PRIORITY_CLASS:
102ca04c78bSTyler Retzlaff 		if (os_pri == THREAD_PRIORITY_NORMAL) {
103ca04c78bSTyler Retzlaff 			*eal_pri = RTE_THREAD_PRIORITY_NORMAL;
104ca04c78bSTyler Retzlaff 			return 0;
105ca04c78bSTyler Retzlaff 		}
106ca04c78bSTyler Retzlaff 		break;
107ca04c78bSTyler Retzlaff 	case HIGH_PRIORITY_CLASS:
108ca04c78bSTyler Retzlaff 		RTE_LOG(WARNING, EAL, "The OS priority class is high not real-time.\n");
109ca04c78bSTyler Retzlaff 		/* FALLTHROUGH */
110ca04c78bSTyler Retzlaff 	case REALTIME_PRIORITY_CLASS:
111ca04c78bSTyler Retzlaff 		if (os_pri == THREAD_PRIORITY_TIME_CRITICAL) {
112ca04c78bSTyler Retzlaff 			*eal_pri = RTE_THREAD_PRIORITY_REALTIME_CRITICAL;
113ca04c78bSTyler Retzlaff 			return 0;
114ca04c78bSTyler Retzlaff 		}
115ca04c78bSTyler Retzlaff 		break;
116ca04c78bSTyler Retzlaff 	default:
117ca04c78bSTyler Retzlaff 		RTE_LOG(DEBUG, EAL, "The OS priority value does not map to an EAL-defined priority.\n");
118ca04c78bSTyler Retzlaff 		return EINVAL;
119ca04c78bSTyler Retzlaff 	}
120ca04c78bSTyler Retzlaff 
121ca04c78bSTyler Retzlaff 	return 0;
122ca04c78bSTyler Retzlaff }
123ca04c78bSTyler Retzlaff 
124ce6e911dSTyler Retzlaff static int
125ce6e911dSTyler Retzlaff convert_cpuset_to_affinity(const rte_cpuset_t *cpuset,
126ce6e911dSTyler Retzlaff 		PGROUP_AFFINITY affinity)
127ce6e911dSTyler Retzlaff {
128ce6e911dSTyler Retzlaff 	int ret = 0;
129ce6e911dSTyler Retzlaff 	PGROUP_AFFINITY cpu_affinity = NULL;
130ce6e911dSTyler Retzlaff 	unsigned int cpu_idx;
131ce6e911dSTyler Retzlaff 
132ce6e911dSTyler Retzlaff 	memset(affinity, 0, sizeof(GROUP_AFFINITY));
133ce6e911dSTyler Retzlaff 	affinity->Group = (USHORT)-1;
134ce6e911dSTyler Retzlaff 
135ce6e911dSTyler Retzlaff 	/* Check that all cpus of the set belong to the same processor group and
136ce6e911dSTyler Retzlaff 	 * accumulate thread affinity to be applied.
137ce6e911dSTyler Retzlaff 	 */
138ce6e911dSTyler Retzlaff 	for (cpu_idx = 0; cpu_idx < CPU_SETSIZE; cpu_idx++) {
139ce6e911dSTyler Retzlaff 		if (!CPU_ISSET(cpu_idx, cpuset))
140ce6e911dSTyler Retzlaff 			continue;
141ce6e911dSTyler Retzlaff 
142ce6e911dSTyler Retzlaff 		cpu_affinity = eal_get_cpu_affinity(cpu_idx);
143ce6e911dSTyler Retzlaff 
144ce6e911dSTyler Retzlaff 		if (affinity->Group == (USHORT)-1) {
145ce6e911dSTyler Retzlaff 			affinity->Group = cpu_affinity->Group;
146ce6e911dSTyler Retzlaff 		} else if (affinity->Group != cpu_affinity->Group) {
147ce6e911dSTyler Retzlaff 			RTE_LOG(DEBUG, EAL, "All processors must belong to the same processor group\n");
148ce6e911dSTyler Retzlaff 			ret = ENOTSUP;
149ce6e911dSTyler Retzlaff 			goto cleanup;
150ce6e911dSTyler Retzlaff 		}
151ce6e911dSTyler Retzlaff 
152ce6e911dSTyler Retzlaff 		affinity->Mask |= cpu_affinity->Mask;
153ce6e911dSTyler Retzlaff 	}
154ce6e911dSTyler Retzlaff 
155ce6e911dSTyler Retzlaff 	if (affinity->Mask == 0) {
156ce6e911dSTyler Retzlaff 		ret = EINVAL;
157ce6e911dSTyler Retzlaff 		goto cleanup;
158ce6e911dSTyler Retzlaff 	}
159ce6e911dSTyler Retzlaff 
160ce6e911dSTyler Retzlaff cleanup:
161ce6e911dSTyler Retzlaff 	return ret;
162ce6e911dSTyler Retzlaff }
163ce6e911dSTyler Retzlaff 
164ce6e911dSTyler Retzlaff static DWORD
165ce6e911dSTyler Retzlaff thread_func_wrapper(void *arg)
166ce6e911dSTyler Retzlaff {
167ce6e911dSTyler Retzlaff 	struct thread_routine_ctx ctx = *(struct thread_routine_ctx *)arg;
168ce6e911dSTyler Retzlaff 
169ce6e911dSTyler Retzlaff 	free(arg);
170ce6e911dSTyler Retzlaff 
171ce6e911dSTyler Retzlaff 	return (DWORD)ctx.thread_func(ctx.routine_args);
172ce6e911dSTyler Retzlaff }
173ce6e911dSTyler Retzlaff 
174ce6e911dSTyler Retzlaff int
175ce6e911dSTyler Retzlaff rte_thread_create(rte_thread_t *thread_id,
176ce6e911dSTyler Retzlaff 		  const rte_thread_attr_t *thread_attr,
177ce6e911dSTyler Retzlaff 		  rte_thread_func thread_func, void *args)
178ce6e911dSTyler Retzlaff {
179ce6e911dSTyler Retzlaff 	int ret = 0;
180ce6e911dSTyler Retzlaff 	DWORD tid;
181ce6e911dSTyler Retzlaff 	HANDLE thread_handle = NULL;
182ce6e911dSTyler Retzlaff 	GROUP_AFFINITY thread_affinity;
183ce6e911dSTyler Retzlaff 	struct thread_routine_ctx *ctx;
184ce6e911dSTyler Retzlaff 
185ce6e911dSTyler Retzlaff 	ctx = calloc(1, sizeof(*ctx));
186ce6e911dSTyler Retzlaff 	if (ctx == NULL) {
187ce6e911dSTyler Retzlaff 		RTE_LOG(DEBUG, EAL, "Insufficient memory for thread context allocations\n");
188ce6e911dSTyler Retzlaff 		ret = ENOMEM;
189ce6e911dSTyler Retzlaff 		goto cleanup;
190ce6e911dSTyler Retzlaff 	}
191ce6e911dSTyler Retzlaff 	ctx->routine_args = args;
192ce6e911dSTyler Retzlaff 	ctx->thread_func = thread_func;
193ce6e911dSTyler Retzlaff 
194ce6e911dSTyler Retzlaff 	thread_handle = CreateThread(NULL, 0, thread_func_wrapper, ctx,
195ce6e911dSTyler Retzlaff 		CREATE_SUSPENDED, &tid);
196ce6e911dSTyler Retzlaff 	if (thread_handle == NULL) {
197ce6e911dSTyler Retzlaff 		ret = thread_log_last_error("CreateThread()");
198ce6e911dSTyler Retzlaff 		goto cleanup;
199ce6e911dSTyler Retzlaff 	}
200ce6e911dSTyler Retzlaff 	thread_id->opaque_id = tid;
201ce6e911dSTyler Retzlaff 
202ce6e911dSTyler Retzlaff 	if (thread_attr != NULL) {
203ce6e911dSTyler Retzlaff 		if (CPU_COUNT(&thread_attr->cpuset) > 0) {
204ce6e911dSTyler Retzlaff 			ret = convert_cpuset_to_affinity(
205ce6e911dSTyler Retzlaff 							&thread_attr->cpuset,
206ce6e911dSTyler Retzlaff 							&thread_affinity
207ce6e911dSTyler Retzlaff 							);
208ce6e911dSTyler Retzlaff 			if (ret != 0) {
209ce6e911dSTyler Retzlaff 				RTE_LOG(DEBUG, EAL, "Unable to convert cpuset to thread affinity\n");
210ce6e911dSTyler Retzlaff 				goto cleanup;
211ce6e911dSTyler Retzlaff 			}
212ce6e911dSTyler Retzlaff 
213ce6e911dSTyler Retzlaff 			if (!SetThreadGroupAffinity(thread_handle,
214ce6e911dSTyler Retzlaff 						    &thread_affinity, NULL)) {
215ce6e911dSTyler Retzlaff 				ret = thread_log_last_error("SetThreadGroupAffinity()");
216ce6e911dSTyler Retzlaff 				goto cleanup;
217ce6e911dSTyler Retzlaff 			}
218ce6e911dSTyler Retzlaff 		}
219ce6e911dSTyler Retzlaff 		ret = rte_thread_set_priority(*thread_id,
220ce6e911dSTyler Retzlaff 				thread_attr->priority);
221ce6e911dSTyler Retzlaff 		if (ret != 0) {
222ce6e911dSTyler Retzlaff 			RTE_LOG(DEBUG, EAL, "Unable to set thread priority\n");
223ce6e911dSTyler Retzlaff 			goto cleanup;
224ce6e911dSTyler Retzlaff 		}
225ce6e911dSTyler Retzlaff 	}
226ce6e911dSTyler Retzlaff 
227ce6e911dSTyler Retzlaff 	if (ResumeThread(thread_handle) == (DWORD)-1) {
228ce6e911dSTyler Retzlaff 		ret = thread_log_last_error("ResumeThread()");
229ce6e911dSTyler Retzlaff 		goto cleanup;
230ce6e911dSTyler Retzlaff 	}
231ce6e911dSTyler Retzlaff 
232ce6e911dSTyler Retzlaff 	ctx = NULL;
233ce6e911dSTyler Retzlaff cleanup:
234ce6e911dSTyler Retzlaff 	free(ctx);
235ce6e911dSTyler Retzlaff 	if (thread_handle != NULL) {
236ce6e911dSTyler Retzlaff 		CloseHandle(thread_handle);
237ce6e911dSTyler Retzlaff 		thread_handle = NULL;
238ce6e911dSTyler Retzlaff 	}
239ce6e911dSTyler Retzlaff 
240ce6e911dSTyler Retzlaff 	return ret;
241ce6e911dSTyler Retzlaff }
242ce6e911dSTyler Retzlaff 
243ce6e911dSTyler Retzlaff int
244ce6e911dSTyler Retzlaff rte_thread_join(rte_thread_t thread_id, uint32_t *value_ptr)
245ce6e911dSTyler Retzlaff {
246ce6e911dSTyler Retzlaff 	HANDLE thread_handle;
247ce6e911dSTyler Retzlaff 	DWORD result;
248ce6e911dSTyler Retzlaff 	DWORD exit_code = 0;
249ce6e911dSTyler Retzlaff 	BOOL err;
250ce6e911dSTyler Retzlaff 	int ret = 0;
251ce6e911dSTyler Retzlaff 
252ce6e911dSTyler Retzlaff 	thread_handle = OpenThread(SYNCHRONIZE | THREAD_QUERY_INFORMATION,
253ce6e911dSTyler Retzlaff 				   FALSE, thread_id.opaque_id);
254ce6e911dSTyler Retzlaff 	if (thread_handle == NULL) {
255ce6e911dSTyler Retzlaff 		ret = thread_log_last_error("OpenThread()");
256ce6e911dSTyler Retzlaff 		goto cleanup;
257ce6e911dSTyler Retzlaff 	}
258ce6e911dSTyler Retzlaff 
259ce6e911dSTyler Retzlaff 	result = WaitForSingleObject(thread_handle, INFINITE);
260ce6e911dSTyler Retzlaff 	if (result != WAIT_OBJECT_0) {
261ce6e911dSTyler Retzlaff 		ret = thread_log_last_error("WaitForSingleObject()");
262ce6e911dSTyler Retzlaff 		goto cleanup;
263ce6e911dSTyler Retzlaff 	}
264ce6e911dSTyler Retzlaff 
265ce6e911dSTyler Retzlaff 	if (value_ptr != NULL) {
266ce6e911dSTyler Retzlaff 		err = GetExitCodeThread(thread_handle, &exit_code);
267ce6e911dSTyler Retzlaff 		if (err == 0) {
268ce6e911dSTyler Retzlaff 			ret = thread_log_last_error("GetExitCodeThread()");
269ce6e911dSTyler Retzlaff 			goto cleanup;
270ce6e911dSTyler Retzlaff 		}
271ce6e911dSTyler Retzlaff 		*value_ptr = exit_code;
272ce6e911dSTyler Retzlaff 	}
273ce6e911dSTyler Retzlaff 
274ce6e911dSTyler Retzlaff cleanup:
275ce6e911dSTyler Retzlaff 	if (thread_handle != NULL) {
276ce6e911dSTyler Retzlaff 		CloseHandle(thread_handle);
277ce6e911dSTyler Retzlaff 		thread_handle = NULL;
278ce6e911dSTyler Retzlaff 	}
279ce6e911dSTyler Retzlaff 
280ce6e911dSTyler Retzlaff 	return ret;
281ce6e911dSTyler Retzlaff }
282ce6e911dSTyler Retzlaff 
283ce6e911dSTyler Retzlaff int
284ce6e911dSTyler Retzlaff rte_thread_detach(rte_thread_t thread_id)
285ce6e911dSTyler Retzlaff {
286ce6e911dSTyler Retzlaff 	/* No resources that need to be released. */
287ce6e911dSTyler Retzlaff 	RTE_SET_USED(thread_id);
288ce6e911dSTyler Retzlaff 
289ce6e911dSTyler Retzlaff 	return 0;
290ce6e911dSTyler Retzlaff }
291ce6e911dSTyler Retzlaff 
292*a2e94ca8STyler Retzlaff int
293*a2e94ca8STyler Retzlaff rte_thread_equal(rte_thread_t t1, rte_thread_t t2)
294*a2e94ca8STyler Retzlaff {
295*a2e94ca8STyler Retzlaff 	return t1.opaque_id == t2.opaque_id;
296*a2e94ca8STyler Retzlaff }
297*a2e94ca8STyler Retzlaff 
29856539289STyler Retzlaff rte_thread_t
29956539289STyler Retzlaff rte_thread_self(void)
30056539289STyler Retzlaff {
30156539289STyler Retzlaff 	rte_thread_t thread_id;
30256539289STyler Retzlaff 
30356539289STyler Retzlaff 	thread_id.opaque_id = GetCurrentThreadId();
30456539289STyler Retzlaff 
30556539289STyler Retzlaff 	return thread_id;
30656539289STyler Retzlaff }
30756539289STyler Retzlaff 
30899a2dd95SBruce Richardson int
309ca04c78bSTyler Retzlaff rte_thread_get_priority(rte_thread_t thread_id,
310ca04c78bSTyler Retzlaff 	enum rte_thread_priority *priority)
311ca04c78bSTyler Retzlaff {
312ca04c78bSTyler Retzlaff 	HANDLE thread_handle = NULL;
313ca04c78bSTyler Retzlaff 	DWORD pri_class;
314ca04c78bSTyler Retzlaff 	int os_pri;
315ca04c78bSTyler Retzlaff 	int ret;
316ca04c78bSTyler Retzlaff 
317ca04c78bSTyler Retzlaff 	pri_class = GetPriorityClass(GetCurrentProcess());
318ca04c78bSTyler Retzlaff 	if (pri_class == 0) {
319ca04c78bSTyler Retzlaff 		ret = thread_log_last_error("GetPriorityClass()");
320ca04c78bSTyler Retzlaff 		goto cleanup;
321ca04c78bSTyler Retzlaff 	}
322ca04c78bSTyler Retzlaff 
323ca04c78bSTyler Retzlaff 	thread_handle = OpenThread(THREAD_SET_INFORMATION |
324ca04c78bSTyler Retzlaff 		THREAD_QUERY_INFORMATION, FALSE, thread_id.opaque_id);
325ca04c78bSTyler Retzlaff 	if (thread_handle == NULL) {
326ca04c78bSTyler Retzlaff 		ret = thread_log_last_error("OpenThread()");
327ca04c78bSTyler Retzlaff 		goto cleanup;
328ca04c78bSTyler Retzlaff 	}
329ca04c78bSTyler Retzlaff 
330ca04c78bSTyler Retzlaff 	os_pri = GetThreadPriority(thread_handle);
331ca04c78bSTyler Retzlaff 	if (os_pri == THREAD_PRIORITY_ERROR_RETURN) {
332ca04c78bSTyler Retzlaff 		ret = thread_log_last_error("GetThreadPriority()");
333ca04c78bSTyler Retzlaff 		goto cleanup;
334ca04c78bSTyler Retzlaff 	}
335ca04c78bSTyler Retzlaff 
336ca04c78bSTyler Retzlaff 	ret = thread_map_os_priority_to_eal_value(os_pri, pri_class, priority);
337ca04c78bSTyler Retzlaff 	if (ret != 0)
338ca04c78bSTyler Retzlaff 		goto cleanup;
339ca04c78bSTyler Retzlaff 
340ca04c78bSTyler Retzlaff cleanup:
341ca04c78bSTyler Retzlaff 	if (thread_handle != NULL)
342ca04c78bSTyler Retzlaff 		CloseHandle(thread_handle);
343ca04c78bSTyler Retzlaff 
344ca04c78bSTyler Retzlaff 	return ret;
345ca04c78bSTyler Retzlaff }
346ca04c78bSTyler Retzlaff 
347ca04c78bSTyler Retzlaff int
348ca04c78bSTyler Retzlaff rte_thread_set_priority(rte_thread_t thread_id,
349ca04c78bSTyler Retzlaff 			enum rte_thread_priority priority)
350ca04c78bSTyler Retzlaff {
351ca04c78bSTyler Retzlaff 	HANDLE thread_handle;
352ca04c78bSTyler Retzlaff 	DWORD priority_class;
353ca04c78bSTyler Retzlaff 	int os_priority;
354ca04c78bSTyler Retzlaff 	int ret = 0;
355ca04c78bSTyler Retzlaff 
356ca04c78bSTyler Retzlaff 	thread_handle = OpenThread(THREAD_SET_INFORMATION |
357ca04c78bSTyler Retzlaff 		THREAD_QUERY_INFORMATION, FALSE, thread_id.opaque_id);
358ca04c78bSTyler Retzlaff 	if (thread_handle == NULL) {
359ca04c78bSTyler Retzlaff 		ret = thread_log_last_error("OpenThread()");
360ca04c78bSTyler Retzlaff 		goto cleanup;
361ca04c78bSTyler Retzlaff 	}
362ca04c78bSTyler Retzlaff 
363ca04c78bSTyler Retzlaff 	ret = thread_map_priority_to_os_value(priority, &os_priority,
364ca04c78bSTyler Retzlaff 		&priority_class);
365ca04c78bSTyler Retzlaff 	if (ret != 0)
366ca04c78bSTyler Retzlaff 		goto cleanup;
367ca04c78bSTyler Retzlaff 
368ca04c78bSTyler Retzlaff 	if (!SetPriorityClass(GetCurrentProcess(), priority_class)) {
369ca04c78bSTyler Retzlaff 		ret = thread_log_last_error("SetPriorityClass()");
370ca04c78bSTyler Retzlaff 		goto cleanup;
371ca04c78bSTyler Retzlaff 	}
372ca04c78bSTyler Retzlaff 
373ca04c78bSTyler Retzlaff 	if (!SetThreadPriority(thread_handle, os_priority)) {
374ca04c78bSTyler Retzlaff 		ret = thread_log_last_error("SetThreadPriority()");
375ca04c78bSTyler Retzlaff 		goto cleanup;
376ca04c78bSTyler Retzlaff 	}
377ca04c78bSTyler Retzlaff 
378ca04c78bSTyler Retzlaff cleanup:
379ca04c78bSTyler Retzlaff 	if (thread_handle != NULL)
380ca04c78bSTyler Retzlaff 		CloseHandle(thread_handle);
381ca04c78bSTyler Retzlaff 
382ca04c78bSTyler Retzlaff 	return ret;
383ca04c78bSTyler Retzlaff }
384ca04c78bSTyler Retzlaff 
385ca04c78bSTyler Retzlaff int
38699a2dd95SBruce Richardson rte_thread_key_create(rte_thread_key *key,
38799a2dd95SBruce Richardson 		__rte_unused void (*destructor)(void *))
38899a2dd95SBruce Richardson {
38999a2dd95SBruce Richardson 	*key = malloc(sizeof(**key));
39099a2dd95SBruce Richardson 	if ((*key) == NULL) {
39199a2dd95SBruce Richardson 		RTE_LOG(DEBUG, EAL, "Cannot allocate TLS key.\n");
39299a2dd95SBruce Richardson 		rte_errno = ENOMEM;
39399a2dd95SBruce Richardson 		return -1;
39499a2dd95SBruce Richardson 	}
39599a2dd95SBruce Richardson 	(*key)->thread_index = TlsAlloc();
39699a2dd95SBruce Richardson 	if ((*key)->thread_index == TLS_OUT_OF_INDEXES) {
39799a2dd95SBruce Richardson 		RTE_LOG_WIN32_ERR("TlsAlloc()");
39899a2dd95SBruce Richardson 		free(*key);
39999a2dd95SBruce Richardson 		rte_errno = ENOEXEC;
40099a2dd95SBruce Richardson 		return -1;
40199a2dd95SBruce Richardson 	}
40299a2dd95SBruce Richardson 	return 0;
40399a2dd95SBruce Richardson }
40499a2dd95SBruce Richardson 
40599a2dd95SBruce Richardson int
40699a2dd95SBruce Richardson rte_thread_key_delete(rte_thread_key key)
40799a2dd95SBruce Richardson {
40899a2dd95SBruce Richardson 	if (!key) {
40999a2dd95SBruce Richardson 		RTE_LOG(DEBUG, EAL, "Invalid TLS key.\n");
41099a2dd95SBruce Richardson 		rte_errno = EINVAL;
41199a2dd95SBruce Richardson 		return -1;
41299a2dd95SBruce Richardson 	}
41399a2dd95SBruce Richardson 	if (!TlsFree(key->thread_index)) {
41499a2dd95SBruce Richardson 		RTE_LOG_WIN32_ERR("TlsFree()");
41599a2dd95SBruce Richardson 		free(key);
41699a2dd95SBruce Richardson 		rte_errno = ENOEXEC;
41799a2dd95SBruce Richardson 		return -1;
41899a2dd95SBruce Richardson 	}
41999a2dd95SBruce Richardson 	free(key);
42099a2dd95SBruce Richardson 	return 0;
42199a2dd95SBruce Richardson }
42299a2dd95SBruce Richardson 
42399a2dd95SBruce Richardson int
42499a2dd95SBruce Richardson rte_thread_value_set(rte_thread_key key, const void *value)
42599a2dd95SBruce Richardson {
42699a2dd95SBruce Richardson 	char *p;
42799a2dd95SBruce Richardson 
42899a2dd95SBruce Richardson 	if (!key) {
42999a2dd95SBruce Richardson 		RTE_LOG(DEBUG, EAL, "Invalid TLS key.\n");
43099a2dd95SBruce Richardson 		rte_errno = EINVAL;
43199a2dd95SBruce Richardson 		return -1;
43299a2dd95SBruce Richardson 	}
43399a2dd95SBruce Richardson 	/* discard const qualifier */
43499a2dd95SBruce Richardson 	p = (char *) (uintptr_t) value;
43599a2dd95SBruce Richardson 	if (!TlsSetValue(key->thread_index, p)) {
43699a2dd95SBruce Richardson 		RTE_LOG_WIN32_ERR("TlsSetValue()");
43799a2dd95SBruce Richardson 		rte_errno = ENOEXEC;
43899a2dd95SBruce Richardson 		return -1;
43999a2dd95SBruce Richardson 	}
44099a2dd95SBruce Richardson 	return 0;
44199a2dd95SBruce Richardson }
44299a2dd95SBruce Richardson 
44399a2dd95SBruce Richardson void *
44499a2dd95SBruce Richardson rte_thread_value_get(rte_thread_key key)
44599a2dd95SBruce Richardson {
44699a2dd95SBruce Richardson 	void *output;
44799a2dd95SBruce Richardson 
44899a2dd95SBruce Richardson 	if (!key) {
44999a2dd95SBruce Richardson 		RTE_LOG(DEBUG, EAL, "Invalid TLS key.\n");
45099a2dd95SBruce Richardson 		rte_errno = EINVAL;
45199a2dd95SBruce Richardson 		return NULL;
45299a2dd95SBruce Richardson 	}
45399a2dd95SBruce Richardson 	output = TlsGetValue(key->thread_index);
45499a2dd95SBruce Richardson 	if (GetLastError() != ERROR_SUCCESS) {
45599a2dd95SBruce Richardson 		RTE_LOG_WIN32_ERR("TlsGetValue()");
45699a2dd95SBruce Richardson 		rte_errno = ENOEXEC;
45799a2dd95SBruce Richardson 		return NULL;
45899a2dd95SBruce Richardson 	}
45999a2dd95SBruce Richardson 	return output;
46099a2dd95SBruce Richardson }
461b70a9b78STyler Retzlaff 
462b70a9b78STyler Retzlaff int
463b70a9b78STyler Retzlaff rte_thread_set_affinity_by_id(rte_thread_t thread_id,
464b70a9b78STyler Retzlaff 		const rte_cpuset_t *cpuset)
465b70a9b78STyler Retzlaff {
466b70a9b78STyler Retzlaff 	int ret = 0;
467b70a9b78STyler Retzlaff 	GROUP_AFFINITY thread_affinity;
468b70a9b78STyler Retzlaff 	HANDLE thread_handle = NULL;
469b70a9b78STyler Retzlaff 
470b70a9b78STyler Retzlaff 	if (cpuset == NULL) {
471b70a9b78STyler Retzlaff 		ret = EINVAL;
472b70a9b78STyler Retzlaff 		goto cleanup;
473b70a9b78STyler Retzlaff 	}
474b70a9b78STyler Retzlaff 
475b70a9b78STyler Retzlaff 	ret = convert_cpuset_to_affinity(cpuset, &thread_affinity);
476b70a9b78STyler Retzlaff 	if (ret != 0) {
477b70a9b78STyler Retzlaff 		RTE_LOG(DEBUG, EAL, "Unable to convert cpuset to thread affinity\n");
478b70a9b78STyler Retzlaff 		goto cleanup;
479b70a9b78STyler Retzlaff 	}
480b70a9b78STyler Retzlaff 
481b70a9b78STyler Retzlaff 	thread_handle = OpenThread(THREAD_ALL_ACCESS, FALSE,
482b70a9b78STyler Retzlaff 		thread_id.opaque_id);
483b70a9b78STyler Retzlaff 	if (thread_handle == NULL) {
484b70a9b78STyler Retzlaff 		ret = thread_log_last_error("OpenThread()");
485b70a9b78STyler Retzlaff 		goto cleanup;
486b70a9b78STyler Retzlaff 	}
487b70a9b78STyler Retzlaff 
488b70a9b78STyler Retzlaff 	if (!SetThreadGroupAffinity(thread_handle, &thread_affinity, NULL)) {
489b70a9b78STyler Retzlaff 		ret = thread_log_last_error("SetThreadGroupAffinity()");
490b70a9b78STyler Retzlaff 		goto cleanup;
491b70a9b78STyler Retzlaff 	}
492b70a9b78STyler Retzlaff 
493b70a9b78STyler Retzlaff cleanup:
494b70a9b78STyler Retzlaff 	if (thread_handle != NULL) {
495b70a9b78STyler Retzlaff 		CloseHandle(thread_handle);
496b70a9b78STyler Retzlaff 		thread_handle = NULL;
497b70a9b78STyler Retzlaff 	}
498b70a9b78STyler Retzlaff 
499b70a9b78STyler Retzlaff 	return ret;
500b70a9b78STyler Retzlaff }
501b70a9b78STyler Retzlaff 
502b70a9b78STyler Retzlaff int
503b70a9b78STyler Retzlaff rte_thread_get_affinity_by_id(rte_thread_t thread_id,
504b70a9b78STyler Retzlaff 		rte_cpuset_t *cpuset)
505b70a9b78STyler Retzlaff {
506b70a9b78STyler Retzlaff 	HANDLE thread_handle = NULL;
507b70a9b78STyler Retzlaff 	PGROUP_AFFINITY cpu_affinity;
508b70a9b78STyler Retzlaff 	GROUP_AFFINITY thread_affinity;
509b70a9b78STyler Retzlaff 	unsigned int cpu_idx;
510b70a9b78STyler Retzlaff 	int ret = 0;
511b70a9b78STyler Retzlaff 
512b70a9b78STyler Retzlaff 	if (cpuset == NULL) {
513b70a9b78STyler Retzlaff 		ret = EINVAL;
514b70a9b78STyler Retzlaff 		goto cleanup;
515b70a9b78STyler Retzlaff 	}
516b70a9b78STyler Retzlaff 
517b70a9b78STyler Retzlaff 	thread_handle = OpenThread(THREAD_ALL_ACCESS, FALSE,
518b70a9b78STyler Retzlaff 		thread_id.opaque_id);
519b70a9b78STyler Retzlaff 	if (thread_handle == NULL) {
520b70a9b78STyler Retzlaff 		ret = thread_log_last_error("OpenThread()");
521b70a9b78STyler Retzlaff 		goto cleanup;
522b70a9b78STyler Retzlaff 	}
523b70a9b78STyler Retzlaff 
524b70a9b78STyler Retzlaff 	/* obtain previous thread affinity */
525b70a9b78STyler Retzlaff 	if (!GetThreadGroupAffinity(thread_handle, &thread_affinity)) {
526b70a9b78STyler Retzlaff 		ret = thread_log_last_error("GetThreadGroupAffinity()");
527b70a9b78STyler Retzlaff 		goto cleanup;
528b70a9b78STyler Retzlaff 	}
529b70a9b78STyler Retzlaff 
530b70a9b78STyler Retzlaff 	CPU_ZERO(cpuset);
531b70a9b78STyler Retzlaff 
532b70a9b78STyler Retzlaff 	/* Convert affinity to DPDK cpu set */
533b70a9b78STyler Retzlaff 	for (cpu_idx = 0; cpu_idx < CPU_SETSIZE; cpu_idx++) {
534b70a9b78STyler Retzlaff 
535b70a9b78STyler Retzlaff 		cpu_affinity = eal_get_cpu_affinity(cpu_idx);
536b70a9b78STyler Retzlaff 
537b70a9b78STyler Retzlaff 		if ((cpu_affinity->Group == thread_affinity.Group) &&
538b70a9b78STyler Retzlaff 		   ((cpu_affinity->Mask & thread_affinity.Mask) != 0)) {
539b70a9b78STyler Retzlaff 			CPU_SET(cpu_idx, cpuset);
540b70a9b78STyler Retzlaff 		}
541b70a9b78STyler Retzlaff 	}
542b70a9b78STyler Retzlaff 
543b70a9b78STyler Retzlaff cleanup:
544b70a9b78STyler Retzlaff 	if (thread_handle != NULL) {
545b70a9b78STyler Retzlaff 		CloseHandle(thread_handle);
546b70a9b78STyler Retzlaff 		thread_handle = NULL;
547b70a9b78STyler Retzlaff 	}
548b70a9b78STyler Retzlaff 	return ret;
549b70a9b78STyler Retzlaff }
550