1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2017 Intel Corporation. All rights reserved. 3 * All rights reserved. 4 */ 5 6 #include "spdk/cpuset.h" 7 #include "spdk/log.h" 8 9 struct spdk_cpuset * 10 spdk_cpuset_alloc(void) 11 { 12 return (struct spdk_cpuset *)calloc(1, sizeof(struct spdk_cpuset)); 13 } 14 15 void 16 spdk_cpuset_free(struct spdk_cpuset *set) 17 { 18 free(set); 19 } 20 21 bool 22 spdk_cpuset_equal(const struct spdk_cpuset *set1, const struct spdk_cpuset *set2) 23 { 24 assert(set1 != NULL); 25 assert(set2 != NULL); 26 return memcmp(set1->cpus, set2->cpus, sizeof(set2->cpus)) == 0; 27 } 28 29 void 30 spdk_cpuset_copy(struct spdk_cpuset *dst, const struct spdk_cpuset *src) 31 { 32 assert(dst != NULL); 33 assert(src != NULL); 34 memcpy(&dst->cpus, &src->cpus, sizeof(src->cpus)); 35 } 36 37 void 38 spdk_cpuset_negate(struct spdk_cpuset *set) 39 { 40 unsigned int i; 41 assert(set != NULL); 42 for (i = 0; i < sizeof(set->cpus); i++) { 43 set->cpus[i] = ~set->cpus[i]; 44 } 45 } 46 47 void 48 spdk_cpuset_and(struct spdk_cpuset *dst, const struct spdk_cpuset *src) 49 { 50 unsigned int i; 51 assert(dst != NULL); 52 assert(src != NULL); 53 for (i = 0; i < sizeof(src->cpus); i++) { 54 dst->cpus[i] &= src->cpus[i]; 55 } 56 } 57 58 void 59 spdk_cpuset_or(struct spdk_cpuset *dst, const struct spdk_cpuset *src) 60 { 61 unsigned int i; 62 assert(dst != NULL); 63 assert(src != NULL); 64 for (i = 0; i < sizeof(src->cpus); i++) { 65 dst->cpus[i] |= src->cpus[i]; 66 } 67 } 68 69 void 70 spdk_cpuset_xor(struct spdk_cpuset *dst, const struct spdk_cpuset *src) 71 { 72 unsigned int i; 73 assert(dst != NULL); 74 assert(src != NULL); 75 for (i = 0; i < sizeof(src->cpus); i++) { 76 dst->cpus[i] ^= src->cpus[i]; 77 } 78 } 79 80 void 81 spdk_cpuset_zero(struct spdk_cpuset *set) 82 { 83 assert(set != NULL); 84 memset(set->cpus, 0, sizeof(set->cpus)); 85 } 86 87 void 88 spdk_cpuset_set_cpu(struct spdk_cpuset *set, uint32_t cpu, bool state) 89 { 90 assert(set != NULL); 91 assert(cpu < sizeof(set->cpus) * 8); 92 if (state) { 93 set->cpus[cpu / 8] |= (1U << (cpu % 8)); 94 } else { 95 set->cpus[cpu / 8] &= ~(1U << (cpu % 8)); 96 } 97 } 98 99 bool 100 spdk_cpuset_get_cpu(const struct spdk_cpuset *set, uint32_t cpu) 101 { 102 assert(set != NULL); 103 assert(cpu < sizeof(set->cpus) * 8); 104 return (set->cpus[cpu / 8] >> (cpu % 8)) & 1U; 105 } 106 107 void 108 spdk_cpuset_for_each_cpu(const struct spdk_cpuset *set, 109 void (*fn)(void *ctx, uint32_t cpu), void *ctx) 110 { 111 uint8_t n; 112 unsigned int i, j; 113 for (i = 0; i < sizeof(set->cpus); i++) { 114 n = set->cpus[i]; 115 for (j = 0; j < 8; j++) { 116 if (n & (1 << j)) { 117 fn(ctx, i * 8 + j); 118 } 119 } 120 } 121 } 122 123 static void 124 count_fn(void *ctx, uint32_t cpu) 125 { 126 uint32_t *count = ctx; 127 128 (*count)++; 129 } 130 131 uint32_t 132 spdk_cpuset_count(const struct spdk_cpuset *set) 133 { 134 uint32_t count = 0; 135 136 spdk_cpuset_for_each_cpu(set, count_fn, &count); 137 return count; 138 } 139 140 const char * 141 spdk_cpuset_fmt(struct spdk_cpuset *set) 142 { 143 uint32_t lcore, lcore_max = 0; 144 int val, i, n; 145 char *ptr; 146 static const char *hex = "0123456789abcdef"; 147 148 assert(set != NULL); 149 150 for (lcore = 0; lcore < sizeof(set->cpus) * 8; lcore++) { 151 if (spdk_cpuset_get_cpu(set, lcore)) { 152 lcore_max = lcore; 153 } 154 } 155 156 ptr = set->str; 157 n = lcore_max / 8; 158 val = set->cpus[n]; 159 160 /* Store first number only if it is not leading zero */ 161 if ((val & 0xf0) != 0) { 162 *(ptr++) = hex[(val & 0xf0) >> 4]; 163 } 164 *(ptr++) = hex[val & 0x0f]; 165 166 for (i = n - 1; i >= 0; i--) { 167 val = set->cpus[i]; 168 *(ptr++) = hex[(val & 0xf0) >> 4]; 169 *(ptr++) = hex[val & 0x0f]; 170 } 171 *ptr = '\0'; 172 173 return set->str; 174 } 175 176 static int 177 hex_value(uint8_t c) 178 { 179 #define V(x, y) [x] = y + 1 180 static const int8_t val[256] = { 181 V('0', 0), V('1', 1), V('2', 2), V('3', 3), V('4', 4), 182 V('5', 5), V('6', 6), V('7', 7), V('8', 8), V('9', 9), 183 V('A', 0xA), V('B', 0xB), V('C', 0xC), V('D', 0xD), V('E', 0xE), V('F', 0xF), 184 V('a', 0xA), V('b', 0xB), V('c', 0xC), V('d', 0xD), V('e', 0xE), V('f', 0xF), 185 }; 186 #undef V 187 188 return val[c] - 1; 189 } 190 191 static int 192 parse_list(const char *mask, struct spdk_cpuset *set) 193 { 194 char *end; 195 const char *ptr = mask; 196 uint32_t lcore; 197 uint32_t lcore_min, lcore_max; 198 199 spdk_cpuset_zero(set); 200 lcore_min = UINT32_MAX; 201 202 ptr++; 203 end = (char *)ptr; 204 do { 205 while (isblank(*ptr)) { 206 ptr++; 207 } 208 if (*ptr == '\0' || *ptr == ']' || *ptr == '-' || *ptr == ',') { 209 goto invalid_character; 210 } 211 212 errno = 0; 213 lcore = strtoul(ptr, &end, 10); 214 if (errno) { 215 SPDK_ERRLOG("Conversion of core mask in '%s' failed\n", mask); 216 return -1; 217 } 218 219 if (lcore >= sizeof(set->cpus) * 8) { 220 SPDK_ERRLOG("Core number %" PRIu32 " is out of range in '%s'\n", lcore, mask); 221 return -1; 222 } 223 224 while (isblank(*end)) { 225 end++; 226 } 227 228 if (*end == '-') { 229 lcore_min = lcore; 230 } else if (*end == ',' || *end == ']') { 231 lcore_max = lcore; 232 if (lcore_min == UINT32_MAX) { 233 lcore_min = lcore; 234 } 235 if (lcore_min > lcore_max) { 236 SPDK_ERRLOG("Invalid range of CPUs (%" PRIu32 " > %" PRIu32 ")\n", 237 lcore_min, lcore_max); 238 return -1; 239 } 240 for (lcore = lcore_min; lcore <= lcore_max; lcore++) { 241 spdk_cpuset_set_cpu(set, lcore, true); 242 } 243 lcore_min = UINT32_MAX; 244 } else { 245 goto invalid_character; 246 } 247 248 ptr = end + 1; 249 250 } while (*end != ']'); 251 252 return 0; 253 254 invalid_character: 255 if (*end == '\0') { 256 SPDK_ERRLOG("Unexpected end of core list '%s'\n", mask); 257 } else { 258 SPDK_ERRLOG("Parsing of core list '%s' failed on character '%c'\n", mask, *end); 259 } 260 return -1; 261 } 262 263 static int 264 parse_mask(const char *mask, struct spdk_cpuset *set, size_t len) 265 { 266 int i, j; 267 char c; 268 int val; 269 uint32_t lcore = 0; 270 271 if (mask[0] == '0' && (mask[1] == 'x' || mask[1] == 'X')) { 272 mask += 2; 273 len -= 2; 274 } 275 276 spdk_cpuset_zero(set); 277 for (i = len - 1; i >= 0; i--) { 278 c = mask[i]; 279 if (c == ',') { 280 /* Linux puts comma delimiters in its cpumasks, just skip them. */ 281 continue; 282 } 283 val = hex_value(c); 284 if (val < 0) { 285 /* Invalid character */ 286 SPDK_ERRLOG("Invalid character in core mask '%s' (%c)\n", mask, c); 287 return -1; 288 } 289 for (j = 0; j < 4 && lcore < SPDK_CPUSET_SIZE; j++, lcore++) { 290 if ((1 << j) & val) { 291 spdk_cpuset_set_cpu(set, lcore, true); 292 } 293 } 294 } 295 296 return 0; 297 } 298 299 int 300 spdk_cpuset_parse(struct spdk_cpuset *set, const char *mask) 301 { 302 int ret; 303 size_t len; 304 305 if (mask == NULL || set == NULL) { 306 return -1; 307 } 308 309 while (isblank(*mask)) { 310 mask++; 311 } 312 313 len = strlen(mask); 314 while (len > 0 && isblank(mask[len - 1])) { 315 len--; 316 } 317 318 if (len == 0) { 319 return -1; 320 } 321 322 if (mask[0] == '[') { 323 ret = parse_list(mask, set); 324 } else { 325 ret = parse_mask(mask, set, len); 326 } 327 328 return ret; 329 } 330