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