1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 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(sizeof(struct spdk_cpuset), 1); 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 uint32_t 108 spdk_cpuset_count(const struct spdk_cpuset *set) 109 { 110 uint32_t count = 0; 111 uint8_t n; 112 unsigned int i; 113 for (i = 0; i < sizeof(set->cpus); i++) { 114 n = set->cpus[i]; 115 while (n) { 116 n &= (n - 1); 117 count++; 118 } 119 } 120 return count; 121 } 122 123 const char * 124 spdk_cpuset_fmt(struct spdk_cpuset *set) 125 { 126 uint32_t lcore, lcore_max = 0; 127 int val, i, n; 128 char *ptr; 129 static const char *hex = "0123456789abcdef"; 130 131 assert(set != NULL); 132 133 for (lcore = 0; lcore < sizeof(set->cpus) * 8; lcore++) { 134 if (spdk_cpuset_get_cpu(set, lcore)) { 135 lcore_max = lcore; 136 } 137 } 138 139 ptr = set->str; 140 n = lcore_max / 8; 141 val = set->cpus[n]; 142 143 /* Store first number only if it is not leading zero */ 144 if ((val & 0xf0) != 0) { 145 *(ptr++) = hex[(val & 0xf0) >> 4]; 146 } 147 *(ptr++) = hex[val & 0x0f]; 148 149 for (i = n - 1; i >= 0; i--) { 150 val = set->cpus[i]; 151 *(ptr++) = hex[(val & 0xf0) >> 4]; 152 *(ptr++) = hex[val & 0x0f]; 153 } 154 *ptr = '\0'; 155 156 return set->str; 157 } 158 159 static int 160 hex_value(uint8_t c) 161 { 162 #define V(x, y) [x] = y + 1 163 static const int8_t val[256] = { 164 V('0', 0), V('1', 1), V('2', 2), V('3', 3), V('4', 4), 165 V('5', 5), V('6', 6), V('7', 7), V('8', 8), V('9', 9), 166 V('A', 0xA), V('B', 0xB), V('C', 0xC), V('D', 0xD), V('E', 0xE), V('F', 0xF), 167 V('a', 0xA), V('b', 0xB), V('c', 0xC), V('d', 0xD), V('e', 0xE), V('f', 0xF), 168 }; 169 #undef V 170 171 return val[c] - 1; 172 } 173 174 static int 175 parse_list(const char *mask, struct spdk_cpuset *set) 176 { 177 char *end; 178 const char *ptr = mask; 179 uint32_t lcore; 180 uint32_t lcore_min, lcore_max; 181 182 spdk_cpuset_zero(set); 183 lcore_min = UINT32_MAX; 184 185 ptr++; 186 end = (char *)ptr; 187 do { 188 while (isblank(*ptr)) { 189 ptr++; 190 } 191 if (*ptr == '\0' || *ptr == ']' || *ptr == '-' || *ptr == ',') { 192 goto invalid_character; 193 } 194 195 errno = 0; 196 lcore = strtoul(ptr, &end, 10); 197 if (errno) { 198 SPDK_ERRLOG("Conversion of core mask in '%s' failed\n", mask); 199 return -1; 200 } 201 202 if (lcore >= sizeof(set->cpus) * 8) { 203 SPDK_ERRLOG("Core number %" PRIu32 " is out of range in '%s'\n", lcore, mask); 204 return -1; 205 } 206 207 while (isblank(*end)) { 208 end++; 209 } 210 211 if (*end == '-') { 212 lcore_min = lcore; 213 } else if (*end == ',' || *end == ']') { 214 lcore_max = lcore; 215 if (lcore_min == UINT32_MAX) { 216 lcore_min = lcore; 217 } 218 if (lcore_min > lcore_max) { 219 SPDK_ERRLOG("Invalid range of CPUs (%" PRIu32 " > %" PRIu32 ")\n", 220 lcore_min, lcore_max); 221 return -1; 222 } 223 for (lcore = lcore_min; lcore <= lcore_max; lcore++) { 224 spdk_cpuset_set_cpu(set, lcore, true); 225 } 226 lcore_min = UINT32_MAX; 227 } else { 228 goto invalid_character; 229 } 230 231 ptr = end + 1; 232 233 } while (*end != ']'); 234 235 return 0; 236 237 invalid_character: 238 if (*end == '\0') { 239 SPDK_ERRLOG("Unexpected end of core list '%s'\n", mask); 240 } else { 241 SPDK_ERRLOG("Parsing of core list '%s' failed on character '%c'\n", mask, *end); 242 } 243 return -1; 244 } 245 246 static int 247 parse_mask(const char *mask, struct spdk_cpuset *set, size_t len) 248 { 249 int i, j; 250 char c; 251 int val; 252 uint32_t lcore = 0; 253 254 if (mask[0] == '0' && (mask[1] == 'x' || mask[1] == 'X')) { 255 mask += 2; 256 len -= 2; 257 } 258 259 spdk_cpuset_zero(set); 260 for (i = len - 1; i >= 0; i--) { 261 c = mask[i]; 262 val = hex_value(c); 263 if (val < 0) { 264 /* Invalid character */ 265 SPDK_ERRLOG("Invalid character in core mask '%s' (%c)\n", mask, c); 266 return -1; 267 } 268 for (j = 0; j < 4 && lcore < SPDK_CPUSET_SIZE; j++, lcore++) { 269 if ((1 << j) & val) { 270 spdk_cpuset_set_cpu(set, lcore, true); 271 } 272 } 273 } 274 275 return 0; 276 } 277 278 int 279 spdk_cpuset_parse(struct spdk_cpuset *set, const char *mask) 280 { 281 int ret; 282 size_t len; 283 284 if (mask == NULL || set == NULL) { 285 return -1; 286 } 287 288 while (isblank(*mask)) { 289 mask++; 290 } 291 292 len = strlen(mask); 293 while (len > 0 && isblank(mask[len - 1])) { 294 len--; 295 } 296 297 if (len == 0) { 298 return -1; 299 } 300 301 if (mask[0] == '[') { 302 ret = parse_list(mask, set); 303 } else { 304 ret = parse_mask(mask, set, len); 305 } 306 307 return ret; 308 } 309