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