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