1 /*- 2 * BSD LICENSE 3 * 4 * Copyright(c) Intel Corporation. All rights reserved. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "spdk/cpuset.h" 35 #include "spdk/log.h" 36 37 struct spdk_cpuset { 38 char str[SPDK_CPUSET_SIZE / 4 + 1]; 39 uint8_t cpus[SPDK_CPUSET_SIZE / 8]; 40 }; 41 42 struct spdk_cpuset * 43 spdk_cpuset_alloc(void) 44 { 45 return (struct spdk_cpuset *)calloc(sizeof(struct spdk_cpuset), 1); 46 } 47 48 void 49 spdk_cpuset_free(struct spdk_cpuset *set) 50 { 51 free(set); 52 } 53 54 bool 55 spdk_cpuset_equal(const struct spdk_cpuset *set1, const struct spdk_cpuset *set2) 56 { 57 assert(set1 != NULL); 58 assert(set2 != NULL); 59 return memcmp(set1->cpus, set2->cpus, sizeof(set2->cpus)) == 0; 60 } 61 62 void 63 spdk_cpuset_copy(struct spdk_cpuset *set1, const struct spdk_cpuset *set2) 64 { 65 assert(set1 != NULL); 66 assert(set2 != NULL); 67 memcpy(&set1->cpus, &set2->cpus, sizeof(set2->cpus)); 68 } 69 70 void 71 spdk_cpuset_negate(struct spdk_cpuset *set) 72 { 73 unsigned int i; 74 assert(set != NULL); 75 for (i = 0; i < sizeof(set->cpus); i++) { 76 set->cpus[i] = ~set->cpus[i]; 77 } 78 } 79 80 void 81 spdk_cpuset_and(struct spdk_cpuset *set1, const struct spdk_cpuset *set2) 82 { 83 unsigned int i; 84 assert(set1 != NULL); 85 assert(set2 != NULL); 86 for (i = 0; i < sizeof(set2->cpus); i++) { 87 set1->cpus[i] &= set2->cpus[i]; 88 } 89 } 90 91 void 92 spdk_cpuset_or(struct spdk_cpuset *set1, const struct spdk_cpuset *set2) 93 { 94 unsigned int i; 95 assert(set1 != NULL); 96 assert(set2 != NULL); 97 for (i = 0; i < sizeof(set2->cpus); i++) { 98 set1->cpus[i] |= set2->cpus[i]; 99 } 100 } 101 102 void 103 spdk_cpuset_xor(struct spdk_cpuset *set1, const struct spdk_cpuset *set2) 104 { 105 unsigned int i; 106 assert(set1 != NULL); 107 assert(set2 != NULL); 108 for (i = 0; i < sizeof(set2->cpus); i++) { 109 set1->cpus[i] ^= set2->cpus[i]; 110 } 111 } 112 113 void 114 spdk_cpuset_zero(struct spdk_cpuset *set) 115 { 116 assert(set != NULL); 117 memset(set->cpus, 0, sizeof(set->cpus)); 118 } 119 120 void 121 spdk_cpuset_set_cpu(struct spdk_cpuset *set, uint32_t cpu, bool state) 122 { 123 assert(set != NULL); 124 assert(cpu < sizeof(set->cpus) * 8); 125 if (state) { 126 set->cpus[cpu / 8] |= (1U << (cpu % 8)); 127 } else { 128 set->cpus[cpu / 8] &= ~(1U << (cpu % 8)); 129 } 130 } 131 132 bool 133 spdk_cpuset_get_cpu(const struct spdk_cpuset *set, uint32_t cpu) 134 { 135 assert(set != NULL); 136 assert(cpu < sizeof(set->cpus) * 8); 137 return (set->cpus[cpu / 8] >> (cpu % 8)) & 1U; 138 } 139 140 uint32_t 141 spdk_cpuset_count(const struct spdk_cpuset *set) 142 { 143 uint32_t count = 0; 144 uint8_t n; 145 unsigned int i; 146 for (i = 0; i < sizeof(set->cpus); i++) { 147 n = set->cpus[i]; 148 while (n) { 149 n &= (n - 1); 150 count++; 151 } 152 } 153 return count; 154 } 155 156 const char * 157 spdk_cpuset_fmt(struct spdk_cpuset *set) 158 { 159 uint32_t lcore, lcore_max = 0; 160 int val, i, n; 161 char *ptr; 162 static const char *hex = "0123456789abcdef"; 163 164 assert(set != NULL); 165 166 for (lcore = 0; lcore < sizeof(set->cpus) * 8; lcore++) { 167 if (spdk_cpuset_get_cpu(set, lcore)) { 168 lcore_max = lcore; 169 } 170 } 171 172 ptr = set->str; 173 n = lcore_max / 8; 174 val = set->cpus[n]; 175 176 /* Store first number only if it is not leading zero */ 177 if ((val & 0xf0) != 0) { 178 *(ptr++) = hex[(val & 0xf0) >> 4]; 179 } 180 *(ptr++) = hex[val & 0x0f]; 181 182 for (i = n - 1; i >= 0; i--) { 183 val = set->cpus[i]; 184 *(ptr++) = hex[(val & 0xf0) >> 4]; 185 *(ptr++) = hex[val & 0x0f]; 186 } 187 *ptr = '\0'; 188 189 return set->str; 190 } 191 192 static int 193 hex_value(uint8_t c) 194 { 195 #define V(x, y) [x] = y + 1 196 static const int8_t val[256] = { 197 V('0', 0), V('1', 1), V('2', 2), V('3', 3), V('4', 4), 198 V('5', 5), V('6', 6), V('7', 7), V('8', 8), V('9', 9), 199 V('A', 0xA), V('B', 0xB), V('C', 0xC), V('D', 0xD), V('E', 0xE), V('F', 0xF), 200 V('a', 0xA), V('b', 0xB), V('c', 0xC), V('d', 0xD), V('e', 0xE), V('f', 0xF), 201 }; 202 #undef V 203 204 return val[c] - 1; 205 } 206 207 static int 208 parse_list(const char *mask, struct spdk_cpuset *set) 209 { 210 char *end; 211 const char *ptr = mask; 212 uint32_t lcore; 213 uint32_t lcore_min, lcore_max; 214 215 spdk_cpuset_zero(set); 216 lcore_min = UINT32_MAX; 217 218 ptr++; 219 end = (char *)ptr; 220 do { 221 while (isblank(*ptr)) { 222 ptr++; 223 } 224 if (*ptr == '\0' || *ptr == ']' || *ptr == '-' || *ptr == ',') { 225 goto invalid_character; 226 } 227 228 errno = 0; 229 lcore = strtoul(ptr, &end, 10); 230 if (errno) { 231 SPDK_ERRLOG("Conversion of core mask in '%s' failed\n", mask); 232 return -1; 233 } 234 235 if (lcore >= sizeof(set->cpus) * 8) { 236 SPDK_ERRLOG("Core number %" PRIu32 " is out of range in '%s'\n", lcore, mask); 237 return -1; 238 } 239 240 while (isblank(*end)) { 241 end++; 242 } 243 244 if (*end == '-') { 245 lcore_min = lcore; 246 } else if (*end == ',' || *end == ']') { 247 lcore_max = lcore; 248 if (lcore_min == UINT32_MAX) { 249 lcore_min = lcore; 250 } 251 if (lcore_min > lcore_max) { 252 SPDK_ERRLOG("Invalid range of CPUs (%" PRIu32 " > %" PRIu32 ")\n", 253 lcore_min, lcore_max); 254 return -1; 255 } 256 for (lcore = lcore_min; lcore <= lcore_max; lcore++) { 257 spdk_cpuset_set_cpu(set, lcore, true); 258 } 259 lcore_min = UINT32_MAX; 260 } else { 261 goto invalid_character; 262 } 263 264 ptr = end + 1; 265 266 } while (*end != ']'); 267 268 return 0; 269 270 invalid_character: 271 if (*end == '\0') { 272 SPDK_ERRLOG("Unexpected end of core list '%s'\n", mask); 273 } else { 274 SPDK_ERRLOG("Parsing of core list '%s' failed on character '%c'\n", mask, *end); 275 } 276 return -1; 277 } 278 279 static int 280 parse_mask(const char *mask, struct spdk_cpuset *set, size_t len) 281 { 282 int i, j; 283 char c; 284 int val; 285 uint32_t lcore = 0; 286 287 if (mask[0] == '0' && (mask[1] == 'x' || mask[1] == 'X')) { 288 mask += 2; 289 len -= 2; 290 } 291 292 spdk_cpuset_zero(set); 293 for (i = len - 1; i >= 0; i--) { 294 c = mask[i]; 295 val = hex_value(c); 296 if (val < 0) { 297 /* Invalid character */ 298 SPDK_ERRLOG("Invalid character in core mask '%s' (%c)\n", mask, c); 299 return -1; 300 } 301 for (j = 0; j < 4 && lcore < sizeof(set->cpus); j++, lcore++) { 302 if ((1 << j) & val) { 303 spdk_cpuset_set_cpu(set, lcore, true); 304 } 305 } 306 } 307 308 return 0; 309 } 310 311 int 312 spdk_cpuset_parse(struct spdk_cpuset *set, const char *mask) 313 { 314 int ret; 315 size_t len; 316 317 if (mask == NULL || set == NULL) { 318 return -1; 319 } 320 321 while (isblank(*mask)) { 322 mask++; 323 } 324 325 len = strlen(mask); 326 while (len > 0 && isblank(mask[len - 1])) { 327 len--; 328 } 329 330 if (len == 0) { 331 return -1; 332 } 333 334 if (mask[0] == '[') { 335 ret = parse_list(mask, set); 336 } else { 337 ret = parse_mask(mask, set, len); 338 } 339 340 return ret; 341 } 342