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