1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright 2021 Mellanox Technologies, Ltd 3 * Copyright (C) 2022 Microsoft Corporation 4 */ 5 6 #include <rte_common.h> 7 #include <rte_errno.h> 8 #include <rte_thread.h> 9 10 #include "eal_windows.h" 11 12 struct eal_tls_key { 13 DWORD thread_index; 14 }; 15 16 /* Translates the most common error codes related to threads */ 17 static int 18 thread_translate_win32_error(DWORD error) 19 { 20 switch (error) { 21 case ERROR_SUCCESS: 22 return 0; 23 24 case ERROR_INVALID_PARAMETER: 25 return EINVAL; 26 27 case ERROR_INVALID_HANDLE: 28 return EFAULT; 29 30 case ERROR_NOT_ENOUGH_MEMORY: 31 /* FALLTHROUGH */ 32 case ERROR_NO_SYSTEM_RESOURCES: 33 return ENOMEM; 34 35 case ERROR_PRIVILEGE_NOT_HELD: 36 /* FALLTHROUGH */ 37 case ERROR_ACCESS_DENIED: 38 return EACCES; 39 40 case ERROR_ALREADY_EXISTS: 41 return EEXIST; 42 43 case ERROR_POSSIBLE_DEADLOCK: 44 return EDEADLK; 45 46 case ERROR_INVALID_FUNCTION: 47 /* FALLTHROUGH */ 48 case ERROR_CALL_NOT_IMPLEMENTED: 49 return ENOSYS; 50 } 51 52 return EINVAL; 53 } 54 55 static int 56 thread_log_last_error(const char *message) 57 { 58 DWORD error = GetLastError(); 59 RTE_LOG(DEBUG, EAL, "GetLastError()=%lu: %s\n", error, message); 60 61 return thread_translate_win32_error(error); 62 } 63 64 rte_thread_t 65 rte_thread_self(void) 66 { 67 rte_thread_t thread_id; 68 69 thread_id.opaque_id = GetCurrentThreadId(); 70 71 return thread_id; 72 } 73 74 int 75 rte_thread_key_create(rte_thread_key *key, 76 __rte_unused void (*destructor)(void *)) 77 { 78 *key = malloc(sizeof(**key)); 79 if ((*key) == NULL) { 80 RTE_LOG(DEBUG, EAL, "Cannot allocate TLS key.\n"); 81 rte_errno = ENOMEM; 82 return -1; 83 } 84 (*key)->thread_index = TlsAlloc(); 85 if ((*key)->thread_index == TLS_OUT_OF_INDEXES) { 86 RTE_LOG_WIN32_ERR("TlsAlloc()"); 87 free(*key); 88 rte_errno = ENOEXEC; 89 return -1; 90 } 91 return 0; 92 } 93 94 int 95 rte_thread_key_delete(rte_thread_key key) 96 { 97 if (!key) { 98 RTE_LOG(DEBUG, EAL, "Invalid TLS key.\n"); 99 rte_errno = EINVAL; 100 return -1; 101 } 102 if (!TlsFree(key->thread_index)) { 103 RTE_LOG_WIN32_ERR("TlsFree()"); 104 free(key); 105 rte_errno = ENOEXEC; 106 return -1; 107 } 108 free(key); 109 return 0; 110 } 111 112 int 113 rte_thread_value_set(rte_thread_key key, const void *value) 114 { 115 char *p; 116 117 if (!key) { 118 RTE_LOG(DEBUG, EAL, "Invalid TLS key.\n"); 119 rte_errno = EINVAL; 120 return -1; 121 } 122 /* discard const qualifier */ 123 p = (char *) (uintptr_t) value; 124 if (!TlsSetValue(key->thread_index, p)) { 125 RTE_LOG_WIN32_ERR("TlsSetValue()"); 126 rte_errno = ENOEXEC; 127 return -1; 128 } 129 return 0; 130 } 131 132 void * 133 rte_thread_value_get(rte_thread_key key) 134 { 135 void *output; 136 137 if (!key) { 138 RTE_LOG(DEBUG, EAL, "Invalid TLS key.\n"); 139 rte_errno = EINVAL; 140 return NULL; 141 } 142 output = TlsGetValue(key->thread_index); 143 if (GetLastError() != ERROR_SUCCESS) { 144 RTE_LOG_WIN32_ERR("TlsGetValue()"); 145 rte_errno = ENOEXEC; 146 return NULL; 147 } 148 return output; 149 } 150 151 static int 152 convert_cpuset_to_affinity(const rte_cpuset_t *cpuset, 153 PGROUP_AFFINITY affinity) 154 { 155 int ret = 0; 156 PGROUP_AFFINITY cpu_affinity = NULL; 157 unsigned int cpu_idx; 158 159 memset(affinity, 0, sizeof(GROUP_AFFINITY)); 160 affinity->Group = (USHORT)-1; 161 162 /* Check that all cpus of the set belong to the same processor group and 163 * accumulate thread affinity to be applied. 164 */ 165 for (cpu_idx = 0; cpu_idx < CPU_SETSIZE; cpu_idx++) { 166 if (!CPU_ISSET(cpu_idx, cpuset)) 167 continue; 168 169 cpu_affinity = eal_get_cpu_affinity(cpu_idx); 170 171 if (affinity->Group == (USHORT)-1) { 172 affinity->Group = cpu_affinity->Group; 173 } else if (affinity->Group != cpu_affinity->Group) { 174 RTE_LOG(DEBUG, EAL, "All processors must belong to the same processor group\n"); 175 ret = ENOTSUP; 176 goto cleanup; 177 } 178 179 affinity->Mask |= cpu_affinity->Mask; 180 } 181 182 if (affinity->Mask == 0) { 183 ret = EINVAL; 184 goto cleanup; 185 } 186 187 cleanup: 188 return ret; 189 } 190 191 int 192 rte_thread_set_affinity_by_id(rte_thread_t thread_id, 193 const rte_cpuset_t *cpuset) 194 { 195 int ret = 0; 196 GROUP_AFFINITY thread_affinity; 197 HANDLE thread_handle = NULL; 198 199 if (cpuset == NULL) { 200 ret = EINVAL; 201 goto cleanup; 202 } 203 204 ret = convert_cpuset_to_affinity(cpuset, &thread_affinity); 205 if (ret != 0) { 206 RTE_LOG(DEBUG, EAL, "Unable to convert cpuset to thread affinity\n"); 207 goto cleanup; 208 } 209 210 thread_handle = OpenThread(THREAD_ALL_ACCESS, FALSE, 211 thread_id.opaque_id); 212 if (thread_handle == NULL) { 213 ret = thread_log_last_error("OpenThread()"); 214 goto cleanup; 215 } 216 217 if (!SetThreadGroupAffinity(thread_handle, &thread_affinity, NULL)) { 218 ret = thread_log_last_error("SetThreadGroupAffinity()"); 219 goto cleanup; 220 } 221 222 cleanup: 223 if (thread_handle != NULL) { 224 CloseHandle(thread_handle); 225 thread_handle = NULL; 226 } 227 228 return ret; 229 } 230 231 int 232 rte_thread_get_affinity_by_id(rte_thread_t thread_id, 233 rte_cpuset_t *cpuset) 234 { 235 HANDLE thread_handle = NULL; 236 PGROUP_AFFINITY cpu_affinity; 237 GROUP_AFFINITY thread_affinity; 238 unsigned int cpu_idx; 239 int ret = 0; 240 241 if (cpuset == NULL) { 242 ret = EINVAL; 243 goto cleanup; 244 } 245 246 thread_handle = OpenThread(THREAD_ALL_ACCESS, FALSE, 247 thread_id.opaque_id); 248 if (thread_handle == NULL) { 249 ret = thread_log_last_error("OpenThread()"); 250 goto cleanup; 251 } 252 253 /* obtain previous thread affinity */ 254 if (!GetThreadGroupAffinity(thread_handle, &thread_affinity)) { 255 ret = thread_log_last_error("GetThreadGroupAffinity()"); 256 goto cleanup; 257 } 258 259 CPU_ZERO(cpuset); 260 261 /* Convert affinity to DPDK cpu set */ 262 for (cpu_idx = 0; cpu_idx < CPU_SETSIZE; cpu_idx++) { 263 264 cpu_affinity = eal_get_cpu_affinity(cpu_idx); 265 266 if ((cpu_affinity->Group == thread_affinity.Group) && 267 ((cpu_affinity->Mask & thread_affinity.Mask) != 0)) { 268 CPU_SET(cpu_idx, cpuset); 269 } 270 } 271 272 cleanup: 273 if (thread_handle != NULL) { 274 CloseHandle(thread_handle); 275 thread_handle = NULL; 276 } 277 return ret; 278 } 279