]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
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 { | |
9f95a23c | 38 | char str[SPDK_CPUSET_SIZE / 4 + 1]; |
11fdf7f2 TL |
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 | |
9f95a23c | 63 | spdk_cpuset_copy(struct spdk_cpuset *dst, const struct spdk_cpuset *src) |
11fdf7f2 | 64 | { |
9f95a23c TL |
65 | assert(dst != NULL); |
66 | assert(src != NULL); | |
67 | memcpy(&dst->cpus, &src->cpus, sizeof(src->cpus)); | |
11fdf7f2 TL |
68 | } |
69 | ||
70 | void | |
9f95a23c | 71 | spdk_cpuset_negate(struct spdk_cpuset *set) |
11fdf7f2 TL |
72 | { |
73 | unsigned int i; | |
9f95a23c TL |
74 | assert(set != NULL); |
75 | for (i = 0; i < sizeof(set->cpus); i++) { | |
76 | set->cpus[i] = ~set->cpus[i]; | |
11fdf7f2 TL |
77 | } |
78 | } | |
79 | ||
80 | void | |
9f95a23c | 81 | spdk_cpuset_and(struct spdk_cpuset *dst, const struct spdk_cpuset *src) |
11fdf7f2 TL |
82 | { |
83 | unsigned int i; | |
9f95a23c TL |
84 | assert(dst != NULL); |
85 | assert(src != NULL); | |
86 | for (i = 0; i < sizeof(src->cpus); i++) { | |
87 | dst->cpus[i] &= src->cpus[i]; | |
88 | } | |
89 | } | |
90 | ||
91 | void | |
92 | spdk_cpuset_or(struct spdk_cpuset *dst, const struct spdk_cpuset *src) | |
93 | { | |
94 | unsigned int i; | |
95 | assert(dst != NULL); | |
96 | assert(src != NULL); | |
97 | for (i = 0; i < sizeof(src->cpus); i++) { | |
98 | dst->cpus[i] |= src->cpus[i]; | |
99 | } | |
100 | } | |
101 | ||
102 | void | |
103 | spdk_cpuset_xor(struct spdk_cpuset *dst, const struct spdk_cpuset *src) | |
104 | { | |
105 | unsigned int i; | |
106 | assert(dst != NULL); | |
107 | assert(src != NULL); | |
108 | for (i = 0; i < sizeof(src->cpus); i++) { | |
109 | dst->cpus[i] ^= src->cpus[i]; | |
11fdf7f2 TL |
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 | } |