/*- * BSD LICENSE * * Copyright(c) Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "spdk/cpuset.h" #include "spdk/log.h" struct spdk_cpuset { char str[SPDK_CPUSET_SIZE / 4 + 1]; uint8_t cpus[SPDK_CPUSET_SIZE / 8]; }; struct spdk_cpuset * spdk_cpuset_alloc(void) { return (struct spdk_cpuset *)calloc(sizeof(struct spdk_cpuset), 1); } void spdk_cpuset_free(struct spdk_cpuset *set) { free(set); } bool spdk_cpuset_equal(const struct spdk_cpuset *set1, const struct spdk_cpuset *set2) { assert(set1 != NULL); assert(set2 != NULL); return memcmp(set1->cpus, set2->cpus, sizeof(set2->cpus)) == 0; } void spdk_cpuset_copy(struct spdk_cpuset *dst, const struct spdk_cpuset *src) { assert(dst != NULL); assert(src != NULL); memcpy(&dst->cpus, &src->cpus, sizeof(src->cpus)); } void spdk_cpuset_negate(struct spdk_cpuset *set) { unsigned int i; assert(set != NULL); for (i = 0; i < sizeof(set->cpus); i++) { set->cpus[i] = ~set->cpus[i]; } } void spdk_cpuset_and(struct spdk_cpuset *dst, const struct spdk_cpuset *src) { unsigned int i; assert(dst != NULL); assert(src != NULL); for (i = 0; i < sizeof(src->cpus); i++) { dst->cpus[i] &= src->cpus[i]; } } void spdk_cpuset_or(struct spdk_cpuset *dst, const struct spdk_cpuset *src) { unsigned int i; assert(dst != NULL); assert(src != NULL); for (i = 0; i < sizeof(src->cpus); i++) { dst->cpus[i] |= src->cpus[i]; } } void spdk_cpuset_xor(struct spdk_cpuset *dst, const struct spdk_cpuset *src) { unsigned int i; assert(dst != NULL); assert(src != NULL); for (i = 0; i < sizeof(src->cpus); i++) { dst->cpus[i] ^= src->cpus[i]; } } void spdk_cpuset_zero(struct spdk_cpuset *set) { assert(set != NULL); memset(set->cpus, 0, sizeof(set->cpus)); } void spdk_cpuset_set_cpu(struct spdk_cpuset *set, uint32_t cpu, bool state) { assert(set != NULL); assert(cpu < sizeof(set->cpus) * 8); if (state) { set->cpus[cpu / 8] |= (1U << (cpu % 8)); } else { set->cpus[cpu / 8] &= ~(1U << (cpu % 8)); } } bool spdk_cpuset_get_cpu(const struct spdk_cpuset *set, uint32_t cpu) { assert(set != NULL); assert(cpu < sizeof(set->cpus) * 8); return (set->cpus[cpu / 8] >> (cpu % 8)) & 1U; } uint32_t spdk_cpuset_count(const struct spdk_cpuset *set) { uint32_t count = 0; uint8_t n; unsigned int i; for (i = 0; i < sizeof(set->cpus); i++) { n = set->cpus[i]; while (n) { n &= (n - 1); count++; } } return count; } const char * spdk_cpuset_fmt(struct spdk_cpuset *set) { uint32_t lcore, lcore_max = 0; int val, i, n; char *ptr; static const char *hex = "0123456789abcdef"; assert(set != NULL); for (lcore = 0; lcore < sizeof(set->cpus) * 8; lcore++) { if (spdk_cpuset_get_cpu(set, lcore)) { lcore_max = lcore; } } ptr = set->str; n = lcore_max / 8; val = set->cpus[n]; /* Store first number only if it is not leading zero */ if ((val & 0xf0) != 0) { *(ptr++) = hex[(val & 0xf0) >> 4]; } *(ptr++) = hex[val & 0x0f]; for (i = n - 1; i >= 0; i--) { val = set->cpus[i]; *(ptr++) = hex[(val & 0xf0) >> 4]; *(ptr++) = hex[val & 0x0f]; } *ptr = '\0'; return set->str; } static int hex_value(uint8_t c) { #define V(x, y) [x] = y + 1 static const int8_t val[256] = { V('0', 0), V('1', 1), V('2', 2), V('3', 3), V('4', 4), V('5', 5), V('6', 6), V('7', 7), V('8', 8), V('9', 9), V('A', 0xA), V('B', 0xB), V('C', 0xC), V('D', 0xD), V('E', 0xE), V('F', 0xF), V('a', 0xA), V('b', 0xB), V('c', 0xC), V('d', 0xD), V('e', 0xE), V('f', 0xF), }; #undef V return val[c] - 1; } static int parse_list(const char *mask, struct spdk_cpuset *set) { char *end; const char *ptr = mask; uint32_t lcore; uint32_t lcore_min, lcore_max; spdk_cpuset_zero(set); lcore_min = UINT32_MAX; ptr++; end = (char *)ptr; do { while (isblank(*ptr)) { ptr++; } if (*ptr == '\0' || *ptr == ']' || *ptr == '-' || *ptr == ',') { goto invalid_character; } errno = 0; lcore = strtoul(ptr, &end, 10); if (errno) { SPDK_ERRLOG("Conversion of core mask in '%s' failed\n", mask); return -1; } if (lcore >= sizeof(set->cpus) * 8) { SPDK_ERRLOG("Core number %" PRIu32 " is out of range in '%s'\n", lcore, mask); return -1; } while (isblank(*end)) { end++; } if (*end == '-') { lcore_min = lcore; } else if (*end == ',' || *end == ']') { lcore_max = lcore; if (lcore_min == UINT32_MAX) { lcore_min = lcore; } if (lcore_min > lcore_max) { SPDK_ERRLOG("Invalid range of CPUs (%" PRIu32 " > %" PRIu32 ")\n", lcore_min, lcore_max); return -1; } for (lcore = lcore_min; lcore <= lcore_max; lcore++) { spdk_cpuset_set_cpu(set, lcore, true); } lcore_min = UINT32_MAX; } else { goto invalid_character; } ptr = end + 1; } while (*end != ']'); return 0; invalid_character: if (*end == '\0') { SPDK_ERRLOG("Unexpected end of core list '%s'\n", mask); } else { SPDK_ERRLOG("Parsing of core list '%s' failed on character '%c'\n", mask, *end); } return -1; } static int parse_mask(const char *mask, struct spdk_cpuset *set, size_t len) { int i, j; char c; int val; uint32_t lcore = 0; if (mask[0] == '0' && (mask[1] == 'x' || mask[1] == 'X')) { mask += 2; len -= 2; } spdk_cpuset_zero(set); for (i = len - 1; i >= 0; i--) { c = mask[i]; val = hex_value(c); if (val < 0) { /* Invalid character */ SPDK_ERRLOG("Invalid character in core mask '%s' (%c)\n", mask, c); return -1; } for (j = 0; j < 4 && lcore < sizeof(set->cpus); j++, lcore++) { if ((1 << j) & val) { spdk_cpuset_set_cpu(set, lcore, true); } } } return 0; } int spdk_cpuset_parse(struct spdk_cpuset *set, const char *mask) { int ret; size_t len; if (mask == NULL || set == NULL) { return -1; } while (isblank(*mask)) { mask++; } len = strlen(mask); while (len > 0 && isblank(mask[len - 1])) { len--; } if (len == 0) { return -1; } if (mask[0] == '[') { ret = parse_list(mask, set); } else { ret = parse_mask(mask, set, len); } return ret; }